MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Collections.ObjectModel;6using System.Globalization;7using System.IO;8using System.Reflection;9using System.Security;10using System.Text;11 12using Microsoft.PowerShell.Commands;13using Microsoft.Win32;14 15using Dbg = System.Management.Automation.Diagnostics;16using Regex = System.Text.RegularExpressions.Regex;17 18namespace System.Management.Automation19{20 internal static class RegistryStrings21 {22 /// <summary>23 /// Root key path under HKLM.24 /// </summary>25 internal const string MonadRootKeyPath = "Software\\Microsoft\\PowerShell";26 27 /// <summary>28 /// Root key name.29 /// </summary>30 internal const string MonadRootKeyName = "PowerShell";31 32 /// <summary>33 /// Key for monad engine.34 /// </summary>35 internal const string MonadEngineKey = "PowerShellEngine";36 37 // Name for various values under PSEngine38 internal const string MonadEngine_ApplicationBase = "ApplicationBase";39 internal const string MonadEngine_ConsoleHostAssemblyName = "ConsoleHostAssemblyName";40 internal const string MonadEngine_ConsoleHostModuleName = "ConsoleHostModuleName";41 internal const string MonadEngine_RuntimeVersion = "RuntimeVersion";42 internal const string MonadEngine_MonadVersion = "PowerShellVersion";43 44 /// <summary>45 /// Key under which all the mshsnapin live.46 /// </summary>47 internal const string MshSnapinKey = "PowerShellSnapIns";48 49 // Name of various values for each mshsnapin50 internal const string MshSnapin_ApplicationBase = "ApplicationBase";51 internal const string MshSnapin_AssemblyName = "AssemblyName";52 internal const string MshSnapin_ModuleName = "ModuleName";53 internal const string MshSnapin_MonadVersion = "PowerShellVersion";54 internal const string MshSnapin_BuiltInTypes = "Types";55 internal const string MshSnapin_BuiltInFormats = "Formats";56 internal const string MshSnapin_Description = "Description";57 internal const string MshSnapin_Version = "Version";58 internal const string MshSnapin_Vendor = "Vendor";59 internal const string MshSnapin_DescriptionResource = "DescriptionIndirect";60 internal const string MshSnapin_VendorResource = "VendorIndirect";61 internal const string MshSnapin_LogPipelineExecutionDetails = "LogPipelineExecutionDetails";62 63 // Name of default mshsnapins64 internal const string CoreMshSnapinName = "Microsoft.PowerShell.Core";65 internal const string HostMshSnapinName = "Microsoft.PowerShell.Host";66 internal const string ManagementMshSnapinName = "Microsoft.PowerShell.Management";67 internal const string SecurityMshSnapinName = "Microsoft.PowerShell.Security";68 internal const string UtilityMshSnapinName = "Microsoft.PowerShell.Utility";69 }70 71 /// <summary>72 /// Contains information about a PSSnapin.73 /// </summary>74 public class PSSnapInInfo75 {76 internal PSSnapInInfo77 (78 string name,79 bool isDefault,80 string applicationBase,81 string assemblyName,82 string moduleName,83 Version psVersion,84 Version version,85 Collection<string> types,86 Collection<string> formats,87 string descriptionFallback,88 string vendorFallback89 )90 {91 if (string.IsNullOrEmpty(name))92 {93 throw PSTraceSource.NewArgumentNullException(nameof(name));94 }95 96 if (string.IsNullOrEmpty(applicationBase))97 {98 throw PSTraceSource.NewArgumentNullException(nameof(applicationBase));99 }100 101 if (string.IsNullOrEmpty(assemblyName))102 {103 throw PSTraceSource.NewArgumentNullException(nameof(assemblyName));104 }105 106 if (string.IsNullOrEmpty(moduleName))107 {108 throw PSTraceSource.NewArgumentNullException(nameof(moduleName));109 }110 111 if (psVersion == null)112 {113 throw PSTraceSource.NewArgumentNullException(nameof(psVersion));114 }115 116 if (version == null)117 {118 version = new Version("0.0");119 }120 121 types ??= new Collection<string>();122 123 formats ??= new Collection<string>();124 125 descriptionFallback ??= string.Empty;126 127 vendorFallback ??= string.Empty;128 129 Name = name;130 IsDefault = isDefault;131 ApplicationBase = applicationBase;132 AssemblyName = assemblyName;133 ModuleName = moduleName;134 PSVersion = psVersion;135 Version = version;136 Types = types;137 Formats = formats;138 _descriptionFallback = descriptionFallback;139 _vendorFallback = vendorFallback;140 }141 142 internal PSSnapInInfo143 (144 string name,145 bool isDefault,146 string applicationBase,147 string assemblyName,148 string moduleName,149 Version psVersion,150 Version version,151 Collection<string> types,152 Collection<string> formats,153 string description,154 string descriptionFallback,155 string vendor,156 string vendorFallback157 )158 : this(name, isDefault, applicationBase, assemblyName, moduleName, psVersion, version, types, formats, descriptionFallback, vendorFallback)159 {160 _description = description;161 _vendor = vendor;162 }163 164 internal PSSnapInInfo165 (166 string name,167 bool isDefault,168 string applicationBase,169 string assemblyName,170 string moduleName,171 Version psVersion,172 Version version,173 Collection<string> types,174 Collection<string> formats,175 string description,176 string descriptionFallback,177 string descriptionIndirect,178 string vendor,179 string vendorFallback,180 string vendorIndirect181 ) : this(name, isDefault, applicationBase, assemblyName, moduleName, psVersion, version, types, formats, description, descriptionFallback, vendor, vendorFallback)182 {183 // add descriptionIndirect and vendorIndirect only if the mshsnapin is a default mshsnapin184 if (isDefault)185 {186 _descriptionIndirect = descriptionIndirect;187 _vendorIndirect = vendorIndirect;188 }189 }190 191 /// <summary>192 /// Unique Name of the PSSnapin.193 /// </summary>194 public string Name { get; }195 196 /// <summary>197 /// Is this PSSnapin default PSSnapin.198 /// </summary>199 public bool IsDefault { get; }200 201 /// <summary>202 /// Returns applicationbase for PSSnapin.203 /// </summary>204 public string ApplicationBase { get; }205 206 /// <summary>207 /// Strong name of PSSnapin assembly.208 /// </summary>209 public string AssemblyName { get; }210 211 /// <summary>212 /// Name of PSSnapIn module.213 /// </summary>214 public string ModuleName { get; }215 216 internal string AbsoluteModulePath217 {218 get219 {220 if (string.IsNullOrEmpty(ModuleName) || Path.IsPathRooted(ModuleName))221 {222 return ModuleName;223 }224 else if (!File.Exists(Path.Combine(ApplicationBase, ModuleName)))225 {226 return Path.GetFileNameWithoutExtension(ModuleName);227 }228 229 return Path.Combine(ApplicationBase, ModuleName);230 }231 }232 233 /// <summary>234 /// PowerShell version used by PSSnapin.235 /// </summary>236 public Version PSVersion { get; }237 238 /// <summary>239 /// Version of PSSnapin.240 /// </summary>241 public Version Version { get; }242 243 /// <summary>244 /// Collection of file names containing types information for PSSnapIn.245 /// </summary>246 public Collection<string> Types { get; }247 248 /// <summary>249 /// Collection of file names containing format information for PSSnapIn.250 /// </summary>251 public Collection<string> Formats { get; }252 253 private readonly string _descriptionIndirect;254 private readonly string _descriptionFallback = string.Empty;255 private string _description;256 /// <summary>257 /// Description of PSSnapin.258 /// </summary>259 public string Description260 {261 get262 {263 if (_description == null)264 {265 LoadIndirectResources();266 }267 268 return _description;269 }270 }271 272 private readonly string _vendorIndirect;273 private readonly string _vendorFallback = string.Empty;274 private string _vendor;275 /// <summary>276 /// Vendor of PSSnapin.277 /// </summary>278 public string Vendor279 {280 get281 {282 if (_vendor == null)283 {284 LoadIndirectResources();285 }286 287 return _vendor;288 }289 }290 291 /// <summary>292 /// Get/set whether to log Pipeline Execution Detail events.293 /// </summary>294 public bool LogPipelineExecutionDetails { get; set; } = false;295 296 /// <summary>297 /// Overrides ToString.298 /// </summary>299 /// <returns>300 /// Name of the PSSnapIn301 /// </returns>302 public override string ToString()303 {304 return Name;305 }306 307 internal RegistryKey MshSnapinKey308 {309 get310 {311 RegistryKey mshsnapinKey = null;312 313 try314 {315 mshsnapinKey = PSSnapInReader.GetMshSnapinKey(Name, PSVersion.Major.ToString(CultureInfo.InvariantCulture));316 }317 catch (ArgumentException)318 {319 }320 catch (SecurityException)321 {322 }323 catch (System.IO.IOException)324 {325 }326 327 return mshsnapinKey;328 }329 }330 331 internal void LoadIndirectResources()332 {333 using (RegistryStringResourceIndirect resourceReader = RegistryStringResourceIndirect.GetResourceIndirectReader())334 {335 LoadIndirectResources(resourceReader);336 }337 }338 339 internal void LoadIndirectResources(RegistryStringResourceIndirect resourceReader)340 {341 if (IsDefault)342 {343 // For default mshsnapins..resource indirects are hardcoded..344 // so dont read from the registry345 _description = resourceReader.GetResourceStringIndirect(346 AssemblyName,347 ModuleName,348 _descriptionIndirect);349 350 _vendor = resourceReader.GetResourceStringIndirect(351 AssemblyName,352 ModuleName,353 _vendorIndirect);354 }355 else356 {357 RegistryKey mshsnapinKey = MshSnapinKey;358 if (mshsnapinKey != null)359 {360 _description =361 resourceReader.GetResourceStringIndirect(362 mshsnapinKey,363 RegistryStrings.MshSnapin_DescriptionResource,364 AssemblyName,365 ModuleName);366 367 _vendor =368 resourceReader.GetResourceStringIndirect(369 mshsnapinKey,370 RegistryStrings.MshSnapin_VendorResource,371 AssemblyName,372 ModuleName);373 }374 }375 376 if (string.IsNullOrEmpty(_description))377 {378 _description = _descriptionFallback;379 }380 381 if (string.IsNullOrEmpty(_vendor))382 {383 _vendor = _vendorFallback;384 }385 }386 387 internal PSSnapInInfo Clone()388 {389 PSSnapInInfo cloned = new PSSnapInInfo(390 Name,391 IsDefault,392 ApplicationBase,393 AssemblyName,394 ModuleName,395 PSVersion,396 Version,397 new Collection<string>(Types),398 new Collection<string>(Formats),399 _description,400 _descriptionFallback,401 _descriptionIndirect,402 _vendor,403 _vendorFallback,404 _vendorIndirect);405 406 return cloned;407 }408 409 /// <summary>410 /// Returns true if the PSSnapIn Id is valid. A PSSnapIn is valid411 /// if-and-only-if it contains only "Alpha Numeric","-","_","."412 /// characters.413 /// </summary>414 /// <param name="psSnapinId">PSSnapIn Id to validate.</param>415 internal static bool IsPSSnapinIdValid(string psSnapinId)416 {417 if (string.IsNullOrEmpty(psSnapinId))418 {419 return false;420 }421 422 return Regex.IsMatch(psSnapinId, "^[A-Za-z0-9-_\x2E]*$");423 }424 425 /// <summary>426 /// Validates the PSSnapIn Id. A PSSnapIn is valid if-and-only-if it427 /// contains only "Alpha Numeric","-","_","." characters.428 /// </summary>429 /// <param name="psSnapinId">PSSnapIn Id to validate.</param>430 /// <exception cref="PSArgumentException">431 /// 1. Specified PSSnapIn is not valid432 /// </exception>433 internal static void VerifyPSSnapInFormatThrowIfError(string psSnapinId)434 {435 // PSSnapIn do not conform to the naming convention..so throw436 // argument exception437 if (!IsPSSnapinIdValid(psSnapinId))438 {439 throw PSTraceSource.NewArgumentException(nameof(psSnapinId),440 MshSnapInCmdletResources.InvalidPSSnapInName,441 psSnapinId);442 }443 444 // Valid SnapId..Just return445 return;446 }447 }448 449 /// <summary>450 /// Internal class to read information about a mshsnapin.451 /// </summary>452 internal static class PSSnapInReader453 {454 /// <summary>455 /// Reads all registered mshsnapin for all monad versions.456 /// </summary>457 /// <returns>458 /// A collection of PSSnapInInfo objects459 /// </returns>460 /// <exception cref="SecurityException">461 /// User doesn't have access to monad/mshsnapin registration information462 /// </exception>463 /// <exception cref="ArgumentException">464 /// Monad key is not installed465 /// </exception>466 internal static Collection<PSSnapInInfo> ReadAll()467 {468 Collection<PSSnapInInfo> allMshSnapins = new Collection<PSSnapInInfo>();469 RegistryKey monadRootKey = GetMonadRootKey();470 471 string[] versions = monadRootKey.GetSubKeyNames();472 if (versions == null)473 {474 return allMshSnapins;475 }476 477 // PS V3 snapin information is stored under 1 registry key..478 // so no need to iterate over twice.479 Collection<string> filteredVersions = new Collection<string>();480 foreach (string version in versions)481 {482 string temp = PSVersionInfo.GetRegistryVersionKeyForSnapinDiscovery(version);483 if (string.IsNullOrEmpty(temp))484 {485 temp = version;486 }487 488 if (!filteredVersions.Contains(temp))489 {490 filteredVersions.Add(temp);491 }492 }493 494 foreach (string version in filteredVersions)495 {496 if (string.IsNullOrEmpty(version))497 {498 continue;499 }500 // found a key which is not version501 if (!MeetsVersionFormat(version))502 {503 continue;504 }505 506 Collection<PSSnapInInfo> oneVersionMshSnapins = null;507 try508 {509 oneVersionMshSnapins = ReadAll(monadRootKey, version);510 }511 // If we cannot get information for one version, continue with other512 // versions513 catch (SecurityException)514 {515 }516 catch (ArgumentException)517 {518 }519 520 if (oneVersionMshSnapins != null)521 {522 foreach (PSSnapInInfo info in oneVersionMshSnapins)523 {524 allMshSnapins.Add(info);525 }526 }527 }528 529 return allMshSnapins;530 }531 532 /// <summary>533 /// Version should be integer (1, 2, 3 etc)534 /// </summary>535 /// <param name="version"></param>536 /// <returns></returns>537 private538 static539 bool MeetsVersionFormat(string version)540 {541 bool r = true;542 try543 {544 LanguagePrimitives.ConvertTo(version, typeof(int), CultureInfo.InvariantCulture);545 }546 catch (PSInvalidCastException)547 {548 r = false;549 }550 551 return r;552 }553 554 /// <summary>555 /// Reads all registered mshsnapin for specified psVersion.556 /// </summary>557 /// <returns>558 /// A collection of PSSnapInInfo objects559 /// </returns>560 /// <exception cref="SecurityException">561 /// User doesn't have permission to read MonadRoot or Version562 /// </exception>563 /// <exception cref="ArgumentException">564 /// MonadRoot or Version key doesn't exist.565 /// </exception>566 internal static Collection<PSSnapInInfo> ReadAll(string psVersion)567 {568 if (string.IsNullOrEmpty(psVersion))569 {570 throw PSTraceSource.NewArgumentNullException(nameof(psVersion));571 }572 573 RegistryKey monadRootKey = GetMonadRootKey();574 return ReadAll(monadRootKey, psVersion);575 }576 577 /// <summary>578 /// Reads all the mshsnapins for a given psVersion.579 /// </summary>580 /// <exception cref="SecurityException">581 /// The User doesn't have required permission to read the registry key for this version.582 /// </exception>583 /// <exception cref="ArgumentException">584 /// Specified version doesn't exist.585 /// </exception>586 /// <exception cref="SecurityException">587 /// User doesn't have permission to read specified version588 /// </exception>589 private static Collection<PSSnapInInfo> ReadAll(RegistryKey monadRootKey, string psVersion)590 {591 Dbg.Assert(monadRootKey != null, "caller should validate the information");592 Dbg.Assert(!string.IsNullOrEmpty(psVersion), "caller should validate the information");593 594 Collection<PSSnapInInfo> mshsnapins = new Collection<PSSnapInInfo>();595 RegistryKey versionRoot = GetVersionRootKey(monadRootKey, psVersion);596 RegistryKey mshsnapinRoot = GetMshSnapinRootKey(versionRoot, psVersion);597 598 // get name of all mshsnapin for this version599 string[] mshsnapinIds = mshsnapinRoot.GetSubKeyNames();600 601 foreach (string id in mshsnapinIds)602 {603 if (string.IsNullOrEmpty(id))604 {605 continue;606 }607 608 try609 {610 mshsnapins.Add(ReadOne(mshsnapinRoot, id));611 }612 // If we cannot read some mshsnapins, we should continue613 catch (SecurityException)614 {615 }616 catch (ArgumentException)617 {618 }619 }620 621 return mshsnapins;622 }623 624 /// <summary>625 /// Read mshsnapin for specified mshsnapinId and psVersion.626 /// </summary>627 /// <returns>628 /// MshSnapin info object629 /// </returns>630 /// <exception cref="SecurityException">631 /// The user does not have the permissions required to read the632 /// registry key for one of the following:633 /// 1) Monad634 /// 2) PSVersion635 /// 3) MshSnapinId636 /// </exception>637 /// <exception cref="ArgumentException">638 /// 1) Monad key is not present639 /// 2) VersionKey is not present640 /// 3) MshSnapin key is not present641 /// 4) MshSnapin key is not valid642 /// </exception>643 internal static PSSnapInInfo Read(string psVersion, string mshsnapinId)644 {645 if (string.IsNullOrEmpty(psVersion))646 {647 throw PSTraceSource.NewArgumentNullException(nameof(psVersion));648 }649 650 if (string.IsNullOrEmpty(mshsnapinId))651 {652 throw PSTraceSource.NewArgumentNullException(nameof(mshsnapinId));653 }654 // PSSnapIn Reader wont service invalid mshsnapins655 // Monad has specific restrictions on the mshsnapinid like656 // mshsnapinid should be A-Za-z0-9.-_ etc.657 PSSnapInInfo.VerifyPSSnapInFormatThrowIfError(mshsnapinId);658 659 RegistryKey rootKey = GetMonadRootKey();660 RegistryKey versionRoot = GetVersionRootKey(rootKey, psVersion);661 RegistryKey mshsnapinRoot = GetMshSnapinRootKey(versionRoot, psVersion);662 663 return ReadOne(mshsnapinRoot, mshsnapinId);664 }665 666 /// <summary>667 /// Reads the mshsnapin info for a specific key under specific monad version.668 /// </summary>669 /// <remarks>670 /// ReadOne will never create a default PSSnapInInfo object.671 /// </remarks>672 /// <exception cref="SecurityException">673 /// The user does not have the permissions required to read the674 /// registry key for specified mshsnapin.675 /// </exception>676 /// <exception cref="ArgumentException">677 /// 1) Specified mshsnapin is not installed.678 /// 2) Specified mshsnapin is not correctly installed.679 /// </exception>680 private static PSSnapInInfo ReadOne(RegistryKey mshSnapInRoot, string mshsnapinId)681 {682 Dbg.Assert(!string.IsNullOrEmpty(mshsnapinId), "caller should validate the parameter");683 Dbg.Assert(mshSnapInRoot != null, "caller should validate the parameter");684 685 RegistryKey mshsnapinKey;686 mshsnapinKey = mshSnapInRoot.OpenSubKey(mshsnapinId);687 if (mshsnapinKey == null)688 {689 s_mshsnapinTracer.TraceError("Error opening registry key {0}\\{1}.", mshSnapInRoot.Name, mshsnapinId);690 throw PSTraceSource.NewArgumentException(nameof(mshsnapinId), MshSnapinInfo.MshSnapinDoesNotExist, mshsnapinId);691 }692 693 string applicationBase = ReadStringValue(mshsnapinKey, RegistryStrings.MshSnapin_ApplicationBase, true);694 string assemblyName = ReadStringValue(mshsnapinKey, RegistryStrings.MshSnapin_AssemblyName, true);695 string moduleName = ReadStringValue(mshsnapinKey, RegistryStrings.MshSnapin_ModuleName, true);696 Version monadVersion = ReadVersionValue(mshsnapinKey, RegistryStrings.MshSnapin_MonadVersion, true);697 Version version = ReadVersionValue(mshsnapinKey, RegistryStrings.MshSnapin_Version, false);698 699 string description = ReadStringValue(mshsnapinKey, RegistryStrings.MshSnapin_Description, false);700 if (description == null)701 {702 s_mshsnapinTracer.WriteLine("No description is specified for mshsnapin {0}. Using empty string for description.", mshsnapinId);703 description = string.Empty;704 }705 706 string vendor = ReadStringValue(mshsnapinKey, RegistryStrings.MshSnapin_Vendor, false);707 if (vendor == null)708 {709 s_mshsnapinTracer.WriteLine("No vendor is specified for mshsnapin {0}. Using empty string for description.", mshsnapinId);710 vendor = string.Empty;711 }712 713 bool logPipelineExecutionDetails = false;714 string logPipelineExecutionDetailsStr = ReadStringValue(mshsnapinKey, RegistryStrings.MshSnapin_LogPipelineExecutionDetails, false);715 if (!string.IsNullOrEmpty(logPipelineExecutionDetailsStr))716 {717 if (string.Equals("1", logPipelineExecutionDetailsStr, StringComparison.OrdinalIgnoreCase))718 logPipelineExecutionDetails = true;719 }720 721 Collection<string> types = ReadMultiStringValue(mshsnapinKey, RegistryStrings.MshSnapin_BuiltInTypes, false);722 Collection<string> formats = ReadMultiStringValue(mshsnapinKey, RegistryStrings.MshSnapin_BuiltInFormats, false);723 724 s_mshsnapinTracer.WriteLine("Successfully read registry values for mshsnapin {0}. Constructing PSSnapInInfo object.", mshsnapinId);725 PSSnapInInfo mshSnapinInfo = new PSSnapInInfo(mshsnapinId, false, applicationBase, assemblyName, moduleName, monadVersion, version, types, formats, description, vendor);726 mshSnapinInfo.LogPipelineExecutionDetails = logPipelineExecutionDetails;727 728 return mshSnapinInfo;729 }730 731 /// <summary>732 /// Gets multistring value for name.733 /// </summary>734 /// <param name="mshsnapinKey"></param>735 /// <param name="name"></param>736 /// <param name="mandatory"></param>737 /// <returns></returns>738 /// <exception cref="ArgumentException">739 /// if value is not present and mandatory is true740 /// </exception>741 private static Collection<string> ReadMultiStringValue(RegistryKey mshsnapinKey, string name, bool mandatory)742 {743 object value = mshsnapinKey.GetValue(name);744 if (value == null)745 {746 // If this key should be present..throw error747 if (mandatory)748 {749 s_mshsnapinTracer.TraceError("Mandatory property {0} not specified for registry key {1}",750 name, mshsnapinKey.Name);751 throw PSTraceSource.NewArgumentException(nameof(name), MshSnapinInfo.MandatoryValueNotPresent, name, mshsnapinKey.Name);752 }753 else754 {755 return null;756 }757 }758 759 // value cannot be null here...760 string[] msv = value as string[];761 762 if (msv == null)763 {764 // Check if the value is in string format765 if (value is string singleValue)766 {767 msv = new string[1];768 msv[0] = singleValue;769 }770 }771 772 if (msv == null)773 {774 if (mandatory)775 {776 s_mshsnapinTracer.TraceError("Cannot get string/multi-string value for mandatory property {0} in registry key {1}",777 name, mshsnapinKey.Name);778 throw PSTraceSource.NewArgumentException(nameof(name), MshSnapinInfo.MandatoryValueNotInCorrectFormatMultiString, name, mshsnapinKey.Name);779 }780 else781 {782 return null;783 }784 }785 786 s_mshsnapinTracer.WriteLine("Successfully read property {0} from {1}",787 name, mshsnapinKey.Name);788 return new Collection<string>(msv);789 }790 791 /// <summary>792 /// Get the value for name.793 /// </summary>794 /// <param name="mshsnapinKey"></param>795 /// <param name="name"></param>796 /// <param name="mandatory"></param>797 /// <returns></returns>798 /// <exception cref="ArgumentException">799 /// if no value is available and mandatory is true.800 /// </exception>801 internal static string ReadStringValue(RegistryKey mshsnapinKey, string name, bool mandatory)802 {803 Dbg.Assert(!string.IsNullOrEmpty(name), "caller should validate the parameter");804 Dbg.Assert(mshsnapinKey != null, "Caller should validate the parameter");805 806 object value = mshsnapinKey.GetValue(name);807 if (value == null && mandatory)808 {809 s_mshsnapinTracer.TraceError("Mandatory property {0} not specified for registry key {1}",810 name, mshsnapinKey.Name);811 throw PSTraceSource.NewArgumentException(nameof(name), MshSnapinInfo.MandatoryValueNotPresent, name, mshsnapinKey.Name);812 }813 814 string s = value as string;815 if (string.IsNullOrEmpty(s) && mandatory)816 {817 s_mshsnapinTracer.TraceError("Value is null or empty for mandatory property {0} in {1}",818 name, mshsnapinKey.Name);819 throw PSTraceSource.NewArgumentException(nameof(name), MshSnapinInfo.MandatoryValueNotInCorrectFormat, name, mshsnapinKey.Name);820 }821 822 s_mshsnapinTracer.WriteLine("Successfully read value {0} for property {1} from {2}",823 s, name, mshsnapinKey.Name);824 return s;825 }826 827 internal static Version ReadVersionValue(RegistryKey mshsnapinKey, string name, bool mandatory)828 {829 string temp = ReadStringValue(mshsnapinKey, name, mandatory);830 if (temp == null)831 {832 s_mshsnapinTracer.TraceError("Cannot read value for property {0} in registry key {1}",833 name, mshsnapinKey.ToString());834 Dbg.Assert(!mandatory, "mandatory is true, ReadStringValue should have thrown exception");835 return null;836 }837 838 Version v;839 try840 {841 v = new Version(temp);842 }843 catch (ArgumentOutOfRangeException)844 {845 s_mshsnapinTracer.TraceError("Cannot convert value {0} to version format", temp);846 throw PSTraceSource.NewArgumentException(nameof(name), MshSnapinInfo.VersionValueInCorrect, name, mshsnapinKey.Name);847 }848 catch (ArgumentException)849 {850 s_mshsnapinTracer.TraceError("Cannot convert value {0} to version format", temp);851 throw PSTraceSource.NewArgumentException(nameof(name), MshSnapinInfo.VersionValueInCorrect, name, mshsnapinKey.Name);852 }853 catch (OverflowException)854 {855 s_mshsnapinTracer.TraceError("Cannot convert value {0} to version format", temp);856 throw PSTraceSource.NewArgumentException(nameof(name), MshSnapinInfo.VersionValueInCorrect, name, mshsnapinKey.Name);857 }858 catch (FormatException)859 {860 s_mshsnapinTracer.TraceError("Cannot convert value {0} to version format", temp);861 throw PSTraceSource.NewArgumentException(nameof(name), MshSnapinInfo.VersionValueInCorrect, name, mshsnapinKey.Name);862 }863 864 s_mshsnapinTracer.WriteLine("Successfully converted string {0} to version format.", v);865 return v;866 }867 868 internal static void ReadRegistryInfo(out Version assemblyVersion, out string publicKeyToken, out string culture, out string applicationBase, out Version psVersion)869 {870 applicationBase = Utils.DefaultPowerShellAppBase;871 Dbg.Assert(872 !string.IsNullOrEmpty(applicationBase),873 string.Create(CultureInfo.CurrentCulture, $"{RegistryStrings.MonadEngine_ApplicationBase} is empty or null"));874 875 // Get the PSVersion from Utils..this is hardcoded876 psVersion = PSVersionInfo.PSVersion;877 Dbg.Assert(878 psVersion != null,879 string.Create(CultureInfo.CurrentCulture, $"{RegistryStrings.MonadEngine_MonadVersion} is null"));880 881 // Get version number in x.x.x.x format882 // This information is available from the executing assembly883 //884 // PROBLEM: The following code assumes all assemblies have the same version,885 // culture, publickeytoken...This will break the scenarios where only one of886 // the assemblies is patched. ie., all monad assemblies should have the887 // same version number.888 AssemblyName assemblyName = typeof(PSSnapInReader).Assembly.GetName();889 assemblyVersion = assemblyName.Version;890 byte[] publicTokens = assemblyName.GetPublicKeyToken();891 if (publicTokens.Length == 0)892 {893 throw PSTraceSource.NewArgumentException("PublicKeyToken", MshSnapinInfo.PublicKeyTokenAccessFailed);894 }895 896 publicKeyToken = ConvertByteArrayToString(publicTokens);897 898 // save some cpu cycles by hardcoding the culture to neutral899 // assembly should never be targeted to a particular culture900 culture = "neutral";901 }902 903 /// <summary>904 /// PublicKeyToken is in the form of byte[]. Use this function to convert to a string.905 /// </summary>906 /// <param name="tokens">Array of byte's.</param>907 /// <returns></returns>908 internal static string ConvertByteArrayToString(byte[] tokens)909 {910 Dbg.Assert(tokens != null, "Input tokens should never be null");911 StringBuilder tokenBuilder = new StringBuilder(tokens.Length * 2);912 foreach (byte b in tokens)913 {914 tokenBuilder.Append(b.ToString("x2", CultureInfo.InvariantCulture));915 }916 917 return tokenBuilder.ToString();918 }919 920 /// <summary>921 /// Reads core snapin for monad engine.922 /// </summary>923 /// <returns>924 /// A PSSnapInInfo object925 /// </returns>926 internal static PSSnapInInfo ReadCoreEngineSnapIn()927 {928 ReadRegistryInfo(929 out Version assemblyVersion,930 out string publicKeyToken,931 out string culture,932 out string applicationBase,933 out Version psVersion);934 935 // System.Management.Automation formats & types files936 Collection<string> types = new Collection<string>(new string[] { "types.ps1xml", "typesv3.ps1xml" });937 Collection<string> formats = new Collection<string>(new string[]938 {"Certificate.format.ps1xml", "DotNetTypes.format.ps1xml", "FileSystem.format.ps1xml",939 "Help.format.ps1xml", "HelpV3.format.ps1xml", "PowerShellCore.format.ps1xml", "PowerShellTrace.format.ps1xml",940 "Registry.format.ps1xml"});941 942 string strongName = string.Format(943 CultureInfo.InvariantCulture,944 "{0}, Version={1}, Culture={2}, PublicKeyToken={3}",945 s_coreSnapin.AssemblyName,946 assemblyVersion,947 culture,948 publicKeyToken);949 950 string moduleName = Path.Combine(applicationBase, s_coreSnapin.AssemblyName + ".dll");951 952 PSSnapInInfo coreMshSnapin = new PSSnapInInfo(953 s_coreSnapin.PSSnapInName,954 isDefault: true,955 applicationBase,956 strongName,957 moduleName,958 psVersion,959 assemblyVersion,960 types,961 formats,962 description: null,963 s_coreSnapin.Description,964 s_coreSnapin.DescriptionIndirect,965 vendor: null,966 vendorFallback: null,967 s_coreSnapin.VendorIndirect);968#if !UNIX969 // NOTE: On Unix, logging has to be deferred until after command-line parsing970 // complete. On Windows, deferring the call is not needed971 // and this is in the startup code path.972 SetSnapInLoggingInformation(coreMshSnapin);973#endif974 975 return coreMshSnapin;976 }977 978 /// <summary>979 /// Reads all registered mshsnapins for currently executing monad engine.980 /// </summary>981 /// <returns>982 /// A collection of PSSnapInInfo objects983 /// </returns>984 internal static Collection<PSSnapInInfo> ReadEnginePSSnapIns()985 {986 ReadRegistryInfo(987 out Version assemblyVersion,988 out string publicKeyToken,989 out string culture,990 out string applicationBase,991 out Version psVersion);992 993 // System.Management.Automation formats & types files994 Collection<string> smaFormats = new Collection<string>(new string[]995 {"Certificate.format.ps1xml", "DotNetTypes.format.ps1xml", "FileSystem.format.ps1xml",996 "Help.format.ps1xml", "HelpV3.format.ps1xml", "PowerShellCore.format.ps1xml", "PowerShellTrace.format.ps1xml",997 "Registry.format.ps1xml"});998 Collection<string> smaTypes = new Collection<string>(new string[] { "types.ps1xml", "typesv3.ps1xml" });999 1000 // create default mshsnapininfo objects..1001 Collection<PSSnapInInfo> engineMshSnapins = new Collection<PSSnapInInfo>();1002 string assemblyVersionString = assemblyVersion.ToString();1003 1004 for (int item = 0; item < DefaultMshSnapins.Count; item++)1005 {1006 DefaultPSSnapInInformation defaultMshSnapinInfo = DefaultMshSnapins[item];1007 1008 string strongName = string.Format(1009 CultureInfo.InvariantCulture,1010 "{0}, Version={1}, Culture={2}, PublicKeyToken={3}",1011 defaultMshSnapinInfo.AssemblyName,1012 assemblyVersionString,1013 culture,1014 publicKeyToken);1015 1016 Collection<string> formats = null;1017 Collection<string> types = null;1018 1019 if (defaultMshSnapinInfo.AssemblyName.Equals("System.Management.Automation", StringComparison.OrdinalIgnoreCase))1020 {1021 formats = smaFormats;1022 types = smaTypes;1023 }1024 else if (defaultMshSnapinInfo.AssemblyName.Equals("Microsoft.PowerShell.Commands.Diagnostics", StringComparison.OrdinalIgnoreCase))1025 {1026 types = new Collection<string>(new string[] { "GetEvent.types.ps1xml" });1027 formats = new Collection<string>(new string[] { "Event.format.ps1xml", "Diagnostics.format.ps1xml" });1028 }1029 else if (defaultMshSnapinInfo.AssemblyName.Equals("Microsoft.WSMan.Management", StringComparison.OrdinalIgnoreCase))1030 {1031 formats = new Collection<string>(new string[] { "WSMan.format.ps1xml" });1032 }1033 1034 string moduleName = Path.Combine(applicationBase, defaultMshSnapinInfo.AssemblyName + ".dll");1035 1036 PSSnapInInfo defaultMshSnapin = new PSSnapInInfo(1037 defaultMshSnapinInfo.PSSnapInName,1038 isDefault: true,1039 applicationBase,1040 strongName,1041 moduleName,1042 psVersion,1043 assemblyVersion,1044 types,1045 formats,1046 description: null,1047 defaultMshSnapinInfo.Description,1048 defaultMshSnapinInfo.DescriptionIndirect,1049 vendor: null,1050 vendorFallback: null,1051 defaultMshSnapinInfo.VendorIndirect);1052 1053 SetSnapInLoggingInformation(defaultMshSnapin);1054 engineMshSnapins.Add(defaultMshSnapin);1055 }1056 1057 return engineMshSnapins;1058 }1059 1060 /// <summary>1061 /// Enable Snapin logging based on group policy.1062 /// </summary>1063 private static void SetSnapInLoggingInformation(PSSnapInInfo psSnapInInfo)1064 {1065 IEnumerable<string> names;1066 ModuleCmdletBase.ModuleLoggingGroupPolicyStatus status = ModuleCmdletBase.GetModuleLoggingInformation(out names);1067 if (status != ModuleCmdletBase.ModuleLoggingGroupPolicyStatus.Undefined)1068 {1069 SetSnapInLoggingInformation(psSnapInInfo, status, names);1070 }1071 }1072 1073 /// <summary>1074 /// Enable Snapin logging based on group policy.1075 /// </summary>1076 private static void SetSnapInLoggingInformation(PSSnapInInfo psSnapInInfo, ModuleCmdletBase.ModuleLoggingGroupPolicyStatus status, IEnumerable<string> moduleOrSnapinNames)1077 {1078 if (((status & ModuleCmdletBase.ModuleLoggingGroupPolicyStatus.Enabled) != 0) && moduleOrSnapinNames != null)1079 {1080 foreach (string currentGPModuleOrSnapinName in moduleOrSnapinNames)1081 {1082 if (string.Equals(psSnapInInfo.Name, currentGPModuleOrSnapinName, StringComparison.OrdinalIgnoreCase))1083 {1084 psSnapInInfo.LogPipelineExecutionDetails = true;1085 }1086 else if (WildcardPattern.ContainsWildcardCharacters(currentGPModuleOrSnapinName))1087 {1088 WildcardPattern wildcard = WildcardPattern.Get(currentGPModuleOrSnapinName, WildcardOptions.IgnoreCase);1089 if (wildcard.IsMatch(psSnapInInfo.Name))1090 {1091 psSnapInInfo.LogPipelineExecutionDetails = true;1092 }1093 }1094 }1095 }1096 }1097 1098 /// <summary>1099 /// Get the key to monad root.1100 /// </summary>1101 /// <returns></returns>1102 /// <exception cref="SecurityException">1103 /// Caller doesn't have access to monad registration information.1104 /// </exception>1105 /// <exception cref="ArgumentException">1106 /// Monad registration information is not available.1107 /// </exception>1108 internal static RegistryKey GetMonadRootKey()1109 {1110 RegistryKey rootKey = Registry.LocalMachine.OpenSubKey(RegistryStrings.MonadRootKeyPath);1111 if (rootKey == null)1112 {1113 // This should never occur because this code is running1114 // because monad is installed. { well this can occur if someone1115 // deletes the registry key after starting monad1116 Dbg.Assert(false, "Root Key of Monad installation is not present");1117 throw PSTraceSource.NewArgumentException("monad", MshSnapinInfo.MonadRootRegistryAccessFailed);1118 }1119 1120 return rootKey;1121 }1122 1123 /// <summary>1124 /// Get the registry key to PSEngine.1125 /// </summary>1126 /// <returns>RegistryKey.</returns>1127 /// <param name="psVersion">Major version in string format.</param>1128 /// <exception cref="ArgumentException">1129 /// Monad registration information is not available.1130 /// </exception>1131 internal static RegistryKey GetPSEngineKey(string psVersion)1132 {1133 RegistryKey rootKey = GetMonadRootKey();1134 // root key wont be null1135 Dbg.Assert(rootKey != null, "Root Key of Monad installation is not present");1136 1137 RegistryKey versionRootKey = GetVersionRootKey(rootKey, psVersion);1138 // version root key wont be null1139 Dbg.Assert(versionRootKey != null, "Version Rootkey of Monad installation is not present");1140 1141 RegistryKey psEngineParentKey = rootKey.OpenSubKey(psVersion);1142 if (psEngineParentKey == null)1143 {1144 throw PSTraceSource.NewArgumentException("monad", MshSnapinInfo.MonadEngineRegistryAccessFailed);1145 }1146 1147 RegistryKey psEngineKey = psEngineParentKey.OpenSubKey(RegistryStrings.MonadEngineKey);1148 if (psEngineKey == null)1149 {1150 throw PSTraceSource.NewArgumentException("monad", MshSnapinInfo.MonadEngineRegistryAccessFailed);1151 }1152 1153 return psEngineKey;1154 }1155 1156 /// <summary>1157 /// Gets the version root key for specified monad version.1158 /// </summary>1159 /// <param name="rootKey"></param>1160 /// <param name="psVersion"></param>1161 /// <returns></returns>1162 /// <exception cref="SecurityException">1163 /// Caller doesn't have permission to read the version key1164 /// </exception>1165 /// <exception cref="ArgumentException">1166 /// specified psVersion key is not present1167 /// </exception>1168 internal static1169 RegistryKey1170 GetVersionRootKey(RegistryKey rootKey, string psVersion)1171 {1172 Dbg.Assert(!string.IsNullOrEmpty(psVersion), "caller should validate the parameter");1173 Dbg.Assert(rootKey != null, "caller should validate the parameter");1174 1175 string versionKey = PSVersionInfo.GetRegistryVersionKeyForSnapinDiscovery(psVersion);1176 RegistryKey versionRoot = rootKey.OpenSubKey(versionKey);1177 if (versionRoot == null)1178 {1179 throw PSTraceSource.NewArgumentException(nameof(psVersion), MshSnapinInfo.SpecifiedVersionNotFound, versionKey);1180 }1181 1182 return versionRoot;1183 }1184 1185 /// <summary>1186 /// Gets the mshsnapin root key for specified monad version.1187 /// </summary>1188 /// <param name="versionRootKey"></param>1189 /// <param name="psVersion"></param>1190 /// <returns></returns>1191 /// <exception cref="SecurityException">1192 /// Caller doesn't have permission to read the mshsnapin key1193 /// </exception>1194 /// <exception cref="ArgumentException">1195 /// mshsnapin key is not present1196 /// </exception>1197 private static1198 RegistryKey1199 GetMshSnapinRootKey(RegistryKey versionRootKey, string psVersion)1200 {