MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4#if !UNIX5 6using System;7using System.Collections.ObjectModel;8using System.Globalization;9using System.Text;10using Microsoft.Win32;11using System.Management.Automation;12using System.Management.Automation.Internal;13using System.Management.Automation.Provider;14using Dbg = System.Management.Automation;15using Microsoft.PowerShell.Commands.Internal;16 17namespace Microsoft.PowerShell.Commands18{19 /// <summary>20 /// Provider that provides access to Registry through cmdlets. This provider21 /// implements <see cref="System.Management.Automation.Provider.NavigationCmdletProvider"/>,22 /// <see cref="System.Management.Automation.Provider.IPropertyCmdletProvider"/>,23 /// <see cref="System.Management.Automation.Provider.IDynamicPropertyCmdletProvider"/>,24 /// <see cref="System.Management.Automation.Provider.ISecurityDescriptorCmdletProvider"/>25 /// interfaces.26 /// </summary>27 /// <!--28 ///29 /// INSTALLATION:30 ///31 /// Type the following at a PowerShell prompt:32 ///33 /// new-PSProvider -Path "REG.cmdletprovider" -description "My registry navigation provider"34 ///35 /// TO EXERCISE THE PROVIDER:36 ///37 /// Get-PSDrive38 /// set-location HKLM:\software39 /// get-childitem40 /// New-PSDrive -PSProvider REG -name HKCR -root HKEY_CLASSES_ROOT\CLSID41 /// set-location HKCR:42 /// get-childitem "{0000*"43 ///44 /// The CmdletProvider attribute defines the name and capabilities of the provider.45 /// The first parameter is the default friendly name for the provider. The second parameter46 /// is the provider name which, along with some assembly information like version, company, etc.47 /// is used as a fully-qualified provider name which can be used for disambiguation.48 /// The third parameter states the capabilities of the provider.49 ///50 /// -->51#if CORECLR // System.Transaction namespace is not in CoreClr.52 [CmdletProvider(RegistryProvider.ProviderName, ProviderCapabilities.ShouldProcess)]53#else54 [CmdletProvider(RegistryProvider.ProviderName, ProviderCapabilities.ShouldProcess | ProviderCapabilities.Transactions)]55#endif56 [OutputType(typeof(string), ProviderCmdlet = ProviderCmdlet.MoveItemProperty)]57 [OutputType(typeof(RegistryKey), typeof(string), ProviderCmdlet = ProviderCmdlet.GetChildItem)]58 [OutputType(typeof(RegistryKey), ProviderCmdlet = ProviderCmdlet.GetItem)]59 [OutputType(typeof(System.Security.AccessControl.RegistrySecurity), ProviderCmdlet = ProviderCmdlet.GetAcl)]60 [OutputType(typeof(Microsoft.Win32.RegistryKey), ProviderCmdlet = ProviderCmdlet.GetChildItem)]61 [OutputType(typeof(RegistryKey), ProviderCmdlet = ProviderCmdlet.GetItem)]62 [OutputType(typeof(RegistryKey), typeof(string), typeof(Int32), typeof(Int64), ProviderCmdlet = ProviderCmdlet.GetItemProperty)]63 [OutputType(typeof(RegistryKey), ProviderCmdlet = ProviderCmdlet.NewItem)]64 [OutputType(typeof(string), typeof(PathInfo), ProviderCmdlet = ProviderCmdlet.ResolvePath)]65 [OutputType(typeof(PathInfo), ProviderCmdlet = ProviderCmdlet.PushLocation)]66 [OutputType(typeof(PathInfo), ProviderCmdlet = ProviderCmdlet.PopLocation)]67 public sealed partial class RegistryProvider :68 NavigationCmdletProvider,69 IPropertyCmdletProvider,70 IDynamicPropertyCmdletProvider,71 ISecurityDescriptorCmdletProvider72 {73 #region tracer74 75 /// <summary>76 /// An instance of the PSTraceSource class used for trace output77 /// using "ProviderProvider" as the category.78 /// </summary>79 [Dbg.TraceSourceAttribute(80 "RegistryProvider",81 "The namespace navigation provider for the Windows Registry")]82 private static readonly Dbg.PSTraceSource s_tracer =83 Dbg.PSTraceSource.GetTracer("RegistryProvider",84 "The namespace navigation provider for the Windows Registry");85 86 #endregion tracer87 88 /// <summary>89 /// Gets the name of the provider.90 /// </summary>91 public const string ProviderName = "Registry";92 93 #region CmdletProvider overrides94 95 /// <summary>96 /// Gets the alternate item separator character for this provider.97 /// </summary>98 public override char AltItemSeparator => ItemSeparator;99 100 #endregion101 102 #region DriveCmdletProvider overrides103 104 /// <summary>105 /// Verifies that the new drive has a valid root.106 /// </summary>107 /// <returns>A PSDriveInfo object.</returns>108 /// <!--109 /// It also givesthe provider an opportunity to return a110 /// derived class of PSDriveInfo which can contain provider specific111 /// information about the drive.This may be done for performance112 /// or reliability reasons or toprovide extra data to all calls113 /// using the drive114 /// -->115 protected override PSDriveInfo NewDrive(PSDriveInfo drive)116 {117 if (drive == null)118 {119 throw PSTraceSource.NewArgumentNullException(nameof(drive));120 }121 122 if (!ItemExists(drive.Root))123 {124 Exception e = new ArgumentException(RegistryProviderStrings.NewDriveRootDoesNotExist);125 WriteError(new ErrorRecord(126 e,127 e.GetType().FullName,128 ErrorCategory.InvalidArgument,129 drive.Root));130 }131 132 return drive;133 }134 135 /// <summary>136 /// Creates HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER registry drives during provider initialization.137 /// </summary>138 /// <remarks>139 /// After the Start method is called on a provider, the InitializeDefaultDrives140 /// method is called. This is an opportunity for the provider to141 /// mount drives that are important to it. For instance, the Active Directory142 /// provider might mount a drive for the defaultNamingContext if the143 /// machine is joined to a domain. The FileSystem mounts all drives then available.144 /// </remarks>145 protected override Collection<PSDriveInfo> InitializeDefaultDrives()146 {147 Collection<PSDriveInfo> drives = new Collection<PSDriveInfo>();148 149 drives.Add(150 new PSDriveInfo(151 "HKLM",152 ProviderInfo,153 "HKEY_LOCAL_MACHINE",154 RegistryProviderStrings.HKLMDriveDescription,155 null));156 157 drives.Add(158 new PSDriveInfo(159 "HKCU",160 ProviderInfo,161 "HKEY_CURRENT_USER",162 RegistryProviderStrings.HKCUDriveDescription,163 null));164 165 return drives;166 }167 168 #endregion DriveCmdletProvider overrides169 170 #region ItemCmdletProvider overrides171 172 /// <summary>173 /// Determines if the specified <paramref name="path"/> is syntactically and semantically valid.174 /// </summary>175 /// <param name="path">176 /// The path to validate.177 /// </param>178 /// <returns>179 /// True if the path is valid, or False otherwise.180 /// </returns>181 protected override bool IsValidPath(string path)182 {183 bool result = true;184 185 do // false loop186 {187 // There really aren't any illegal characters or syntactical patterns188 // to validate, so just ensure that the path starts with one of the hive roots.189 190 string root = NormalizePath(path);191 root = root.TrimStart(StringLiterals.DefaultPathSeparator);192 root = root.TrimEnd(StringLiterals.DefaultPathSeparator);193 194 int pathSeparator = root.IndexOf(StringLiterals.DefaultPathSeparator);195 196 if (pathSeparator != -1)197 {198 root = root.Substring(0, pathSeparator);199 }200 201 if (string.IsNullOrEmpty(root))202 {203 // An empty path means that we are at the root and should204 // enumerate the hives. So that is a valid path.205 result = true;206 break;207 }208 209 if (GetHiveRoot(root) == null)210 {211 result = false;212 }213 } while (false);214 215 return result;216 }217 218 /// <summary>219 /// Gets the RegistryKey item at the specified <paramref name="path"/>220 /// and writes it to the pipeline using the WriteObject method.221 /// Any non-terminating exceptions are written to the WriteError method.222 /// </summary>223 /// <param name="path">224 /// The path to the key to retrieve.225 /// </param>226 protected override void GetItem(string path)227 {228 // Get the registry item229 230 IRegistryWrapper result = GetRegkeyForPathWriteIfError(path, false);231 232 if (result == null)233 {234 return;235 }236 237 // Write out the result238 239 WriteRegistryItemObject(result, path);240 }241 242 /// <summary>243 /// Sets registry values at <paramref name="path "/> to the <paramref name="value"/> specified.244 /// </summary>245 /// <param name="path">246 /// The path to the item that is to be set. Only registry values can be set using247 /// this method.248 /// </param>249 /// <param name="value">250 /// The new value for the registry value.251 /// </param>252 protected override void SetItem(string path, object value)253 {254 if (string.IsNullOrEmpty(path))255 {256 throw PSTraceSource.NewArgumentException(nameof(path));257 }258 259 // Confirm the set item with the user260 261 string action = RegistryProviderStrings.SetItemAction;262 263 string resourceTemplate = RegistryProviderStrings.SetItemResourceTemplate;264 265 string resource =266 string.Format(267 Host.CurrentCulture,268 resourceTemplate,269 path,270 value);271 272 if (ShouldProcess(resource, action))273 {274 // Get the registry item275 276 IRegistryWrapper key = GetRegkeyForPathWriteIfError(path, true);277 278 if (key == null)279 {280 return;281 }282 283 // Check to see if the type was specified by the user284 285 bool valueSet = false;286 if (DynamicParameters != null)287 {288 RegistryProviderSetItemDynamicParameter dynParams =289 DynamicParameters as RegistryProviderSetItemDynamicParameter;290 291 if (dynParams != null)292 {293 try294 {295 // Convert the parameter to a RegistryValueKind296 297 RegistryValueKind kind = dynParams.Type;298 299 key.SetValue(null, value, kind);300 valueSet = true;301 }302 catch (ArgumentException argException)303 {304 WriteError(new ErrorRecord(argException, argException.GetType().FullName, ErrorCategory.InvalidArgument, null));305 key.Close();306 return;307 }308 catch (System.IO.IOException ioException)309 {310 // An exception occurred while trying to get the key. Write311 // out the error.312 313 WriteError(new ErrorRecord(ioException, ioException.GetType().FullName, ErrorCategory.WriteError, path));314 key.Close();315 return;316 }317 catch (System.Security.SecurityException securityException)318 {319 // An exception occurred while trying to get the key. Write320 // out the error.321 322 WriteError(new ErrorRecord(securityException, securityException.GetType().FullName, ErrorCategory.PermissionDenied, path));323 key.Close();324 return;325 }326 catch (System.UnauthorizedAccessException unauthorizedAccessException)327 {328 // An exception occurred while trying to get the key. Write329 // out the error.330 WriteError(new ErrorRecord(unauthorizedAccessException, unauthorizedAccessException.GetType().FullName, ErrorCategory.PermissionDenied, path));331 key.Close();332 return;333 }334 }335 }336 337 if (!valueSet)338 {339 try340 {341 // Set the value342 key.SetValue(null, value);343 }344 catch (System.IO.IOException ioException)345 {346 // An exception occurred while trying to get the key. Write347 // out the error.348 349 WriteError(new ErrorRecord(ioException, ioException.GetType().FullName, ErrorCategory.WriteError, path));350 key.Close();351 return;352 }353 catch (System.Security.SecurityException securityException)354 {355 // An exception occurred while trying to get the key. Write356 // out the error.357 358 WriteError(new ErrorRecord(securityException, securityException.GetType().FullName, ErrorCategory.PermissionDenied, path));359 key.Close();360 return;361 }362 catch (System.UnauthorizedAccessException unauthorizedAccessException)363 {364 // An exception occurred while trying to get the key. Write365 // out the error.366 367 WriteError(new ErrorRecord(unauthorizedAccessException, unauthorizedAccessException.GetType().FullName, ErrorCategory.PermissionDenied, path));368 key.Close();369 return;370 }371 }372 373 // Write out the result374 object result = value;375 376 // Since SetValue can munge the data to a specified377 // type (RegistryValueKind), retrieve the value again378 // to output it in the correct form to the user.379 result = ReadExistingKeyValue(key, null);380 key.Close();381 382 WriteItemObject(result, path, false);383 }384 }385 386 /// <summary>387 /// Gets the dynamic parameters for the SetItem method.388 /// </summary>389 /// <param name="path">390 /// Ignored.391 /// </param>392 /// <param name="value">393 /// Ignored.394 /// </param>395 /// <returns>396 /// An instance of the <see cref="Microsoft.PowerShell.Commands.RegistryProviderSetItemDynamicParameter"/> class which397 /// contains a parameter for the Type.398 /// </returns>399 protected override object SetItemDynamicParameters(string path, object value)400 {401 return new RegistryProviderSetItemDynamicParameter();402 }403 404 /// <summary>405 /// Clears the item at the specified <paramref name="path"/>.406 /// </summary>407 /// <param name="path">408 /// The path to the item that is to be cleared. Only registry values can be cleared using409 /// this method.410 /// </param>411 /// <remarks>412 /// The registry provider implements this by removing all the values for the specified key.413 /// The item that is cleared is written to the WriteObject method.414 /// If the path is to a value, then an ArgumentException is written.415 /// </remarks>416 protected override void ClearItem(string path)417 {418 if (string.IsNullOrEmpty(path))419 {420 throw PSTraceSource.NewArgumentException(nameof(path));421 }422 423 // Confirm the clear item with the user424 425 string action = RegistryProviderStrings.ClearItemAction;426 427 string resourceTemplate = RegistryProviderStrings.ClearItemResourceTemplate;428 429 string resource =430 string.Format(431 Host.CurrentCulture,432 resourceTemplate,433 path);434 435 if (ShouldProcess(resource, action))436 {437 // Get the registry item438 439 IRegistryWrapper key = GetRegkeyForPathWriteIfError(path, true);440 441 if (key == null)442 {443 return;444 }445 446 string[] valueNames;447 448 try449 {450 // Remove each value451 valueNames = key.GetValueNames();452 }453 catch (System.IO.IOException ioException)454 {455 // An exception occurred while trying to get the key. Write456 // out the error.457 458 WriteError(new ErrorRecord(ioException, ioException.GetType().FullName, ErrorCategory.ReadError, path));459 return;460 }461 catch (System.Security.SecurityException securityException)462 {463 // An exception occurred while trying to get the key. Write464 // out the error.465 466 WriteError(new ErrorRecord(securityException, securityException.GetType().FullName, ErrorCategory.PermissionDenied, path));467 return;468 }469 catch (System.UnauthorizedAccessException unauthorizedAccessException)470 {471 // An exception occurred while trying to get the key. Write472 // out the error.473 474 WriteError(new ErrorRecord(unauthorizedAccessException, unauthorizedAccessException.GetType().FullName, ErrorCategory.PermissionDenied, path));475 return;476 }477 478 for (int index = 0; index < valueNames.Length; ++index)479 {480 try481 {482 key.DeleteValue(valueNames[index]);483 }484 catch (System.IO.IOException ioException)485 {486 // An exception occurred while trying to delete the value. Write487 // out the error.488 489 WriteError(new ErrorRecord(ioException, ioException.GetType().FullName, ErrorCategory.WriteError, path));490 }491 catch (System.Security.SecurityException securityException)492 {493 // An exception occurred while trying to delete the value. Write494 // out the error.495 496 WriteError(new ErrorRecord(securityException, securityException.GetType().FullName, ErrorCategory.PermissionDenied, path));497 }498 catch (System.UnauthorizedAccessException unauthorizedAccessException)499 {500 // An exception occurred while trying to get the key. Write501 // out the error.502 503 WriteError(new ErrorRecord(unauthorizedAccessException, unauthorizedAccessException.GetType().FullName, ErrorCategory.PermissionDenied, path));504 }505 }506 507 // Write out the key508 509 WriteRegistryItemObject(key, path);510 }511 }512 513 #endregion ItemCmdletProvider overrides514 515 #region ContainerCmdletProvider overrides516 517 /// <summary>518 /// Gets all the child keys and values of the key at the specified <paramref name="path"/>.519 /// </summary>520 /// <param name="path">521 /// The path to the key to get the child keys of.522 /// </param>/523 /// <param name="recurse">524 /// Determines if the call should be recursive. If true, all subkeys of525 /// the key at the specified path will be written. If false, only the526 /// immediate children of the key at the specified path will be written.527 /// </param>528 /// <param name="depth">529 /// Current depth of recursion; special case uint.MaxValue performs full recursion.530 /// </param>531 protected override void GetChildItems(532 string path,533 bool recurse,534 uint depth)535 {536 s_tracer.WriteLine("recurse = {0}, depth = {1}", recurse, depth);537 538 if (path == null)539 {540 throw PSTraceSource.NewArgumentNullException(nameof(path));541 }542 543 if (IsHiveContainer(path))544 {545 // If the path is empty or it is / or \, return all the hives546 547 foreach (string hiveName in s_hiveNames)548 {549 // Making sure to obey the StopProcessing.550 if (Stopping)551 {552 return;553 }554 555 GetItem(hiveName);556 }557 }558 else559 {560 // Get the key at the specified path561 562 IRegistryWrapper key = GetRegkeyForPathWriteIfError(path, false);563 564 if (key == null)565 {566 return;567 }568 569 try570 {571 // Get all the subkeys of the specified path572 573 string[] keyNames = key.GetSubKeyNames();574 key.Close();575 576 if (keyNames != null)577 {578 foreach (string subkeyName in keyNames)579 {580 // Making sure to obey the StopProcessing.581 if (Stopping)582 {583 return;584 }585 586 if (!string.IsNullOrEmpty(subkeyName))587 {588 string keypath = path;589 590 try591 {592 // Generate the path for each key name593 594 keypath = MakePath(path, subkeyName, childIsLeaf: true);595 596 if (!string.IsNullOrEmpty(keypath))597 {598 // Call GetItem to retrieve the RegistryKey object599 // and write it to the WriteObject method.600 601 IRegistryWrapper resultKey = GetRegkeyForPath(keypath, false);602 603 if (resultKey != null)604 {605 WriteRegistryItemObject(resultKey, keypath);606 }607 608 // Now recurse if necessary609 610 if (recurse)611 {612 // Limiter for recursion613 if (depth > 0) // this includes special case 'depth == uint.MaxValue' for unlimited recursion614 {615 GetChildItems(keypath, recurse, depth - 1);616 }617 }618 }619 }620 catch (System.IO.IOException ioException)621 {622 // An exception occurred while trying to get the key. Write623 // out the error.624 625 WriteError(new ErrorRecord(ioException, ioException.GetType().FullName, ErrorCategory.ReadError, keypath));626 }627 catch (System.Security.SecurityException securityException)628 {629 // An exception occurred while trying to get the key. Write630 // out the error.631 632 WriteError(new ErrorRecord(securityException, securityException.GetType().FullName, ErrorCategory.PermissionDenied, keypath));633 }634 catch (System.UnauthorizedAccessException unauthorizedAccessException)635 {636 // An exception occurred while trying to get the key. Write637 // out the error.638 639 WriteError(new ErrorRecord(unauthorizedAccessException, unauthorizedAccessException.GetType().FullName, ErrorCategory.PermissionDenied, keypath));640 }641 }642 }643 }644 }645 catch (System.IO.IOException ioException)646 {647 // An exception occurred while trying to get the key. Write648 // out the error.649 650 WriteError(new ErrorRecord(ioException, ioException.GetType().FullName, ErrorCategory.ReadError, path));651 }652 catch (System.Security.SecurityException securityException)653 {654 // An exception occurred while trying to get the key. Write655 // out the error.656 657 WriteError(new ErrorRecord(securityException, securityException.GetType().FullName, ErrorCategory.PermissionDenied, path));658 }659 catch (System.UnauthorizedAccessException unauthorizedAccessException)660 {661 // An exception occurred while trying to get the key. Write662 // out the error.663 664 WriteError(new ErrorRecord(unauthorizedAccessException, unauthorizedAccessException.GetType().FullName, ErrorCategory.PermissionDenied, path));665 }666 }667 }668 669 /// <summary>670 /// Gets all the child key and value names of the key at the specified <paramref name="path"/>.671 /// </summary>672 /// <param name="path">673 /// The path to the key to get the child names from.674 /// </param>675 /// <param name="returnContainers">676 /// Ignored since the registry provider does not implement filtering.677 /// Normally, if this parameter is ReturnAllContainers then all subkeys should be678 /// returned. If it is false, then only those subkeys that match the679 /// filter should be returned.680 /// </param>681 protected override void GetChildNames(682 string path,683 ReturnContainers returnContainers)684 {685 if (path == null)686 {687 throw PSTraceSource.NewArgumentNullException(nameof(path));688 }689 690 if (path.Length == 0)691 {692 // If the path is empty get the names of the hives693 694 foreach (string hiveName in s_hiveNames)695 {696 // Making sure to obey the StopProcessing.697 if (Stopping)698 {699 return;700 }701 702 WriteItemObject(hiveName, hiveName, true);703 }704 }705 else706 {707 // Get the key at the specified path708 709 IRegistryWrapper key = GetRegkeyForPathWriteIfError(path, false);710 711 if (key == null)712 {713 return;714 }715 716 try717 {718 // Get the child key names719 720 string[] results = key.GetSubKeyNames();721 key.Close();722 723 // Write the child key names to the WriteItemObject method724 725 for (int index = 0; index < results.Length; ++index)726 {727 // Making sure to obey the StopProcessing.728 if (Stopping)729 {730 return;731 }732 733 string childName = EscapeChildName(results[index]);734 string childPath = MakePath(path, childName, childIsLeaf: true);735 736 WriteItemObject(childName, childPath, true);737 }738 }739 catch (System.IO.IOException ioException)740 {741 // An exception occurred while trying to get the key. Write742 // out the error.743 744 WriteError(new ErrorRecord(ioException, ioException.GetType().FullName, ErrorCategory.ReadError, path));745 }746 catch (System.Security.SecurityException securityException)747 {748 // An exception occurred while trying to get the key. Write749 // out the error.750 751 WriteError(new ErrorRecord(securityException, securityException.GetType().FullName, ErrorCategory.PermissionDenied, path));752 }753 catch (System.UnauthorizedAccessException unauthorizedAccessException)754 {755 // An exception occurred while trying to get the key. Write756 // out the error.757 758 WriteError(new ErrorRecord(unauthorizedAccessException, unauthorizedAccessException.GetType().FullName, ErrorCategory.PermissionDenied, path));759 }760 }761 }762 763 private const string charactersThatNeedEscaping = ".*?[]:";764 765 /// <summary>766 /// Escapes the characters in the registry key path that are used by globbing and767 /// path.768 /// </summary>769 /// <param name="path">770 /// The path to escape.771 /// </param>772 /// <returns>773 /// The escaped path.774 /// </returns>775 /// <remarks>776 /// This method handles surrogate pairs. Please see msdn documentation777 /// </remarks>778 private static string EscapeSpecialChars(string path)779 {780 StringBuilder result = new StringBuilder();781 782 // Get the text enumerator..this will iterate through each character783 // the character can be a surrogate pair784 System.Globalization.TextElementEnumerator textEnumerator =785 System.Globalization.StringInfo.GetTextElementEnumerator(path);786 787 Dbg.Diagnostics.Assert(788 textEnumerator != null,789 string.Create(CultureInfo.CurrentCulture, $"Cannot get a text enumerator for name {path}"));790 791 while (textEnumerator.MoveNext())792 {793 // Iterate through each element and findout whether794 // any text needs escaping795 string textElement = textEnumerator.GetTextElement();796 797 // NTRAID#Windows Out of Band Releases-939036-2006/07/12-LeeHolm798 // A single character can never contain a string of799 // charactersThatNeedEscaping, so this method does nothing. The fix800 // is to remove all calls to this escaping code, though, as this escaping801 // should not be done.802 if (textElement.Contains(charactersThatNeedEscaping))803 {804 // This text element needs escaping805 result.Append('`');806 }807 808 result.Append(textElement);809 }810 811 return result.ToString();812 }813 814 /// <summary>815 /// Escapes the characters in the registry key name that are used by globbing and816 /// path.817 /// </summary>818 /// <param name="name">819 /// The name to escape.820 /// </param>821 /// <returns>822 /// The escaped name.823 /// </returns>824 /// <remarks>825 /// This method handles surrogate pairs. Please see msdn documentation826 /// </remarks>827 private static string EscapeChildName(string name)828 {829 StringBuilder result = new StringBuilder();830 831 // Get the text enumerator..this will iterate through each character832 // the character can be a surrogate pair833 System.Globalization.TextElementEnumerator textEnumerator =834 System.Globalization.StringInfo.GetTextElementEnumerator(name);835 836 Dbg.Diagnostics.Assert(837 textEnumerator != null,838 string.Create(CultureInfo.CurrentCulture, $"Cannot get a text enumerator for name {name}"));839 840 while (textEnumerator.MoveNext())841 {842 // Iterate through each element and findout whether843 // any text needs escaping844 string textElement = textEnumerator.GetTextElement();845 846 // NTRAID#Windows Out of Band Releases-939036-2006/07/12-LeeHolm847 // A single character can never contain a string of848 // charactersThatNeedEscaping, so this method does nothing. The fix849 // is to remove all calls to this escaping code, though, as this escaping850 // should not be done.851 if (textElement.Contains(charactersThatNeedEscaping))852 {853 // This text element needs escaping854 result.Append('`');855 }856 857 result.Append(textElement);858 }859 860 return result.ToString();861 }862 863 /// <summary>864 /// Renames the key at the specified <paramref name="path"/> to <paramref name="newName"/>.865 /// </summary>866 /// <param name="path">867 /// The path to the key to rename.868 /// </param>869 /// <param name="newName">870 /// The new name of the key.871 /// </param>872 protected override void RenameItem(873 string path,874 string newName)875 {876 if (string.IsNullOrEmpty(path))877 {878 throw PSTraceSource.NewArgumentException(nameof(path));879 }880 881 if (string.IsNullOrEmpty(newName))882 {883 throw PSTraceSource.NewArgumentException(nameof(newName));884 }885 886 s_tracer.WriteLine("newName = {0}", newName);887 888 string parentPath = GetParentPath(path, null);889 string newPath = MakePath(parentPath, newName);890 891 // Make sure we aren't going to overwrite an existing item892 893 bool exists = ItemExists(newPath);894 895 if (exists)896 {897 Exception e = new ArgumentException(RegistryProviderStrings.RenameItemAlreadyExists);898 WriteError(new ErrorRecord(899 e,900 e.GetType().FullName,901 ErrorCategory.InvalidArgument,902 newPath));903 904 return;905 }906 // Confirm the rename item with the user907 908 string action = RegistryProviderStrings.RenameItemAction;909 910 string resourceTemplate = RegistryProviderStrings.RenameItemResourceTemplate;911 912 string resource =913 string.Format(914 Host.CurrentCulture,915 resourceTemplate,916 path,917 newPath);918 919 if (ShouldProcess(resource, action))920 {921 // Implement rename as a move operation922 923 MoveRegistryItem(path, newPath);924 }925 }926 927 /// <summary>928 /// Creates a new registry key or value at the specified <paramref name="path"/>.929 /// </summary>930 /// <param name="path">931 /// The path to the new key to create.932 /// </param>933 /// <param name="type">934 /// The type is ignored because this provider only creates935 /// registry keys.936 /// </param>937 /// <param name="newItem">938 /// The newItem is ignored because the provider creates the939 /// key based on the path.940 /// </param>941 protected override void NewItem(942 string path,943 string type,944 object newItem)945 {946 if (string.IsNullOrEmpty(path))947 {948 throw PSTraceSource.NewArgumentException(nameof(path));949 }950 951 // Confirm the new item with the user952 953 string action = RegistryProviderStrings.NewItemAction;954 955 string resourceTemplate = RegistryProviderStrings.NewItemResourceTemplate;956 957 string resource =958 string.Format(959 Host.CurrentCulture,960 resourceTemplate,961 path);962 if (ShouldProcess(resource, action))963 {964 // Check to see if the key already exists965 IRegistryWrapper resultKey = GetRegkeyForPath(path, false);966 967 if (resultKey != null)968 {969 if (!Force)970 {971 Exception e = new System.IO.IOException(RegistryProviderStrings.KeyAlreadyExists);972 WriteError(new ErrorRecord(973 e,974 e.GetType().FullName,975 ErrorCategory.ResourceExists,976 resultKey));977 978 resultKey.Close();979 return;980 }981 else982 {983 // Remove the existing key before creating the new one984 resultKey.Close();985 RemoveItem(path, false);986 }987 }988 989 if (Force)990 {991 if (!CreateIntermediateKeys(path))992 {993 // We are unable to create Intermediate keys. Just return.994 return;995 }996 }997 998 // Get the parent and child portions of the path999 1000 string parentPath = GetParentPath(path, null);1001 string childName = GetChildName(path);1002 1003 // Get the key at the specified path1004 IRegistryWrapper key = GetRegkeyForPathWriteIfError(parentPath, true);1005 1006 if (key == null)1007 {1008 return;1009 }1010 1011 try1012 {1013 // Create the new subkey1014 IRegistryWrapper newKey = key.CreateSubKey(childName);1015 key.Close();1016 1017 try1018 {1019 // Set the default key value if the value and type were specified1020 1021 if (newItem != null)1022 {1023 RegistryValueKind kind;1024 if (!ParseKind(type, out kind))1025 {1026 return;1027 }1028 1029 SetRegistryValue(newKey, string.Empty, newItem, kind, path, false);1030 }1031 }1032 catch (Exception exception)1033 {1034 // The key has been created, but the default value failed to be set.1035 // If possible, just write an error instead of failing the entire operation.1036 1037 if ((exception is ArgumentException) ||1038 (exception is InvalidCastException) ||1039 (exception is System.IO.IOException) ||1040 (exception is System.Security.SecurityException) ||1041 (exception is System.UnauthorizedAccessException) ||1042 (exception is NotSupportedException))1043 {1044 ErrorRecord rec = new ErrorRecord(1045 exception,1046 exception.GetType().FullName,1047 ErrorCategory.WriteError,1048 newKey);1049 rec.ErrorDetails = new ErrorDetails(StringUtil.Format(RegistryProviderStrings.KeyCreatedValueFailed, childName));1050 WriteError(rec);1051 }1052 else1053 throw;1054 }1055 1056 // Write the new key out.1057 WriteRegistryItemObject(newKey, path);1058 }1059 catch (System.IO.IOException ioException)1060 {1061 // An exception occurred while trying to get the key. Write1062 // out the error.1063 1064 WriteError(new ErrorRecord(ioException, ioException.GetType().FullName, ErrorCategory.WriteError, path));1065 }1066 catch (System.Security.SecurityException securityException)1067 {1068 // An exception occurred while trying to get the key. Write1069 // out the error.1070 1071 WriteError(new ErrorRecord(securityException, securityException.GetType().FullName, ErrorCategory.PermissionDenied, path));1072 }1073 catch (System.UnauthorizedAccessException unauthorizedAccessException)1074 {1075 // An exception occurred while trying to get the key. Write1076 // out the error.1077 1078 WriteError(new ErrorRecord(unauthorizedAccessException, unauthorizedAccessException.GetType().FullName, ErrorCategory.PermissionDenied, path));1079 }1080 catch (ArgumentException argException)1081 {1082 WriteError(new ErrorRecord(argException, argException.GetType().FullName, ErrorCategory.InvalidArgument, path));1083 }1084 catch (NotSupportedException notSupportedException)1085 {1086 WriteError(new ErrorRecord(notSupportedException, notSupportedException.GetType().FullName, ErrorCategory.InvalidOperation, path));1087 }1088 }1089 }1090 1091 /// <summary>1092 /// Removes the specified registry key and all sub-keys.1093 /// </summary>1094 /// <param name="path">1095 /// The path to the key to remove.1096 /// </param>1097 /// <param name="recurse">1098 /// Ignored. All removes are recursive because the1099 /// registry provider does not support filters.1100 /// </param>1101 protected override void RemoveItem(1102 string path,1103 bool recurse)1104 {1105 if (string.IsNullOrEmpty(path))1106 {1107 throw PSTraceSource.NewArgumentException(nameof(path));1108 }1109 1110 s_tracer.WriteLine("recurse = {0}", recurse);1111 1112 // Get the parent and child portions of the path1113 1114 string parentPath = GetParentPath(path, null);1115 string childName = GetChildName(path);1116 1117 // Get the parent key1118 1119 IRegistryWrapper key = GetRegkeyForPathWriteIfError(parentPath, true);1120 1121 if (key == null)1122 {1123 return;1124 }1125 1126 // Confirm the remove item with the user1127 1128 string action = RegistryProviderStrings.RemoveKeyAction;1129 1130 string resourceTemplate = RegistryProviderStrings.RemoveKeyResourceTemplate;1131 1132 string resource =1133 string.Format(1134 Host.CurrentCulture,1135 resourceTemplate,1136 path);1137 1138 if (ShouldProcess(resource, action))1139 {1140 try1141 {1142 key.DeleteSubKeyTree(childName);1143 }1144 catch (ArgumentException argumentException)1145 {1146 WriteError(new ErrorRecord(argumentException, argumentException.GetType().FullName, ErrorCategory.WriteError, path));1147 }1148 catch (System.IO.IOException ioException)1149 {1150 // An exception occurred while trying to get the key. Write1151 // out the error.1152 1153 WriteError(new ErrorRecord(ioException, ioException.GetType().FullName, ErrorCategory.WriteError, path));1154 }1155 catch (System.Security.SecurityException securityException)1156 {1157 // An exception occurred while trying to get the key. Write1158 // out the error.1159 1160 WriteError(new ErrorRecord(securityException, securityException.GetType().FullName, ErrorCategory.PermissionDenied, path));1161 }1162 catch (System.UnauthorizedAccessException unauthorizedAccessException)1163 {1164 // An exception occurred while trying to get the key. Write1165 // out the error.1166 1167 WriteError(new ErrorRecord(unauthorizedAccessException, unauthorizedAccessException.GetType().FullName, ErrorCategory.PermissionDenied, path));1168 }1169 catch (NotSupportedException notSupportedException)1170 {1171 WriteError(new ErrorRecord(notSupportedException, notSupportedException.GetType().FullName, ErrorCategory.InvalidOperation, path));1172 }1173 }1174 1175 key.Close();1176 }1177 1178 /// <summary>1179 /// Determines if the key at the specified path exists.1180 /// </summary>1181 /// <param name="path">1182 /// The path to the key to determine if it exists.1183 /// </param>1184 /// <returns>1185 /// True if the key at the specified path exists, false otherwise.1186 /// </returns>1187 protected override bool ItemExists(string path)1188 {1189 bool result = false;1190 1191 if (path == null)1192 {1193 throw PSTraceSource.NewArgumentNullException(nameof(path));1194 }1195 1196 try1197 {1198 if (IsHiveContainer(path))1199 {1200 // an empty path, \ or / are valid because