MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.Diagnostics.CodeAnalysis;8using System.Linq;9using System.Management.Automation.Internal;10using System.Management.Automation.Language;11using System.Management.Automation.Runspaces;12using System.Reflection;13 14using Microsoft.PowerShell.Commands;15 16using Dbg = System.Management.Automation.Diagnostics;17 18namespace System.Management.Automation19{20 /// <summary>21 /// Class describing a PowerShell module...22 /// </summary>23 public sealed class PSModuleInfo24 {25 internal const string DynamicModulePrefixString = "__DynamicModule_";26 27 private static readonly ReadOnlyDictionary<string, TypeDefinitionAst> s_emptyTypeDefinitionDictionary =28 new ReadOnlyDictionary<string, TypeDefinitionAst>(new Dictionary<string, TypeDefinitionAst>(StringComparer.OrdinalIgnoreCase));29 30 // This dictionary doesn't include ExportedTypes from nested modules.31 private ReadOnlyDictionary<string, TypeDefinitionAst> _exportedTypeDefinitionsNoNested { get; set; }32 33 private static readonly HashSet<string> s_scriptModuleExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)34 {35 StringLiterals.PowerShellModuleFileExtension,36 };37 38 internal static void SetDefaultDynamicNameAndPath(PSModuleInfo module)39 {40 string gs = Guid.NewGuid().ToString();41 module.Path = gs;42 module.Name = "__DynamicModule_" + gs;43 }44 45 /// <summary>46 /// This object describes a PowerShell module...47 /// </summary>48 /// <param name="path">The absolute path to the module.</param>49 /// <param name="context">The execution context for this engine instance.</param>50 /// <param name="sessionState">The module's sessionstate object - this may be null if the module is a dll.</param>51 internal PSModuleInfo(string path, ExecutionContext context, SessionState sessionState)52 : this(null, path, context, sessionState)53 {54 }55 56 /// <summary>57 /// This object describes a PowerShell module...58 /// </summary>59 /// <param name="name">The name to use for the module. If null, get it from the path name.</param>60 /// <param name="path">The absolute path to the module.</param>61 /// <param name="context">The execution context for this engine instance.</param>62 /// <param name="sessionState">The module's sessionstate object - this may be null if the module is a dll.</param>63 /// <param name="languageMode">Language mode for script based modules.</param>64 internal PSModuleInfo(string name, string path, ExecutionContext context, SessionState sessionState, PSLanguageMode? languageMode)65 : this(name, path, context, sessionState)66 {67 LanguageMode = languageMode;68 }69 70 /// <summary>71 /// This object describes a PowerShell module...72 /// </summary>73 /// <param name="name">The name to use for the module. If null, get it from the path name.</param>74 /// <param name="path">The absolute path to the module.</param>75 /// <param name="context">The execution context for this engine instance.</param>76 /// <param name="sessionState">The module's sessionstate object - this may be null if the module is a dll.</param>77 internal PSModuleInfo(string name, string path, ExecutionContext context, SessionState sessionState)78 {79 if (path != null)80 {81 string resolvedPath = ModuleCmdletBase.GetResolvedPath(path, context);82 // The resolved path might be null if we're building a dynamic module and the path83 // is just a GUID, not an actual path that can be resolved.84 Path = resolvedPath ?? path;85 }86 87 SessionState = sessionState;88 if (sessionState != null)89 {90 sessionState.Internal.Module = this;91 }92 93 // Use the name of basename of the path as the module name if no module name is supplied.94 Name = name ?? ModuleIntrinsics.GetModuleName(Path);95 }96 97 /// <summary>98 /// Default constructor to create an empty module info.99 /// </summary>100 public PSModuleInfo(bool linkToGlobal)101 : this(LocalPipeline.GetExecutionContextFromTLS(), linkToGlobal)102 {103 }104 105 /// <summary>106 /// Default constructor to create an empty module info.107 /// </summary>108 internal PSModuleInfo(ExecutionContext context, bool linkToGlobal)109 {110 if (context == null)111 throw new InvalidOperationException("PSModuleInfo");112 113 SetDefaultDynamicNameAndPath(this);114 115 // By default the top-level scope in a session state object is the global scope for the instance.116 // For modules, we need to set its global scope to be another scope object and, chain the top117 // level scope for this sessionstate instance to be the parent. The top level scope for this ss is the118 // script scope for the ss.119 120 // Allocate the session state instance for this module.121 SessionState = new SessionState(context, true, linkToGlobal);122 SessionState.Internal.Module = this;123 }124 125 /// <summary>126 /// Construct a PSModuleInfo instance initializing it from a scriptblock instead of a script file.127 /// </summary>128 /// <param name="scriptBlock">The scriptblock to use to initialize the module.</param>129 public PSModuleInfo(ScriptBlock scriptBlock)130 {131 if (scriptBlock == null)132 {133 throw PSTraceSource.NewArgumentException(nameof(scriptBlock));134 }135 136 // Get the ExecutionContext from the thread.137 var context = LocalPipeline.GetExecutionContextFromTLS();138 139 if (context == null)140 throw new InvalidOperationException("PSModuleInfo");141 142 SetDefaultDynamicNameAndPath(this);143 144 // By default the top-level scope in a session state object is the global scope for the instance.145 // For modules, we need to set its global scope to be another scope object and, chain the top146 // level scope for this sessionstate instance to be the parent. The top level scope for this ss is the147 // script scope for the ss.148 149 // Allocate the session state instance for this module.150 SessionState = new SessionState(context, true, true);151 SessionState.Internal.Module = this;152 153 LanguageMode = scriptBlock.LanguageMode;154 155 // Now set up the module's session state to be the current session state156 SessionStateInternal oldSessionState = context.EngineSessionState;157 try158 {159 context.EngineSessionState = SessionState.Internal;160 161 // Set the PSScriptRoot variable...162 context.SetVariable(SpecialVariables.PSScriptRootVarPath, Path);163 164 scriptBlock = scriptBlock.Clone();165 scriptBlock.SessionState = SessionState;166 167 Pipe outputPipe = new Pipe { NullPipe = true };168 // And run the scriptblock...169 scriptBlock.InvokeWithPipe(170 useLocalScope: false,171 errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToCurrentErrorPipe,172 dollarUnder: AutomationNull.Value,173 input: AutomationNull.Value,174 scriptThis: AutomationNull.Value,175 outputPipe: outputPipe,176 invocationInfo: null177 );178 }179 finally180 {181 context.EngineSessionState = oldSessionState;182 }183 }184 185 /// <summary>186 /// Specifies the language mode for script based modules.187 /// </summary>188 internal PSLanguageMode? LanguageMode189 {190 get;191 set;192 } = PSLanguageMode.FullLanguage;193 194 /// <summary>195 /// Set to true when script module automatically exports all functions by default.196 /// </summary>197 internal bool ModuleAutoExportsAllFunctions { get; set; }198 199 internal bool ModuleHasPrivateMembers { get; set; }200 201 /// <summary>202 /// True if the module had errors during loading.203 /// </summary>204 internal bool HadErrorsLoading { get; set; }205 206 /// <summary>207 /// ToString() implementation which returns the name of the module.208 /// </summary>209 /// <returns>The name of the module.</returns>210 public override string ToString()211 {212 return this.Name;213 }214 215 /// <summary>216 /// Get/set whether to log Pipeline Execution Detail events.217 /// </summary>218 public bool LogPipelineExecutionDetails { get; set; } = false;219 220 /// <summary>221 /// The name of this module.222 /// </summary>223 public string Name { get; private set; } = string.Empty;224 225 /// <summary>226 /// Sets the name property of the PSModuleInfo object.227 /// </summary>228 /// <param name="name">The name to set it to.</param>229 internal void SetName(string name)230 {231 Name = name;232 }233 234 /// <summary>235 /// The path to the file that defined this module...236 /// </summary>237 public string Path { get; internal set; } = string.Empty;238 239 /// <summary>240 /// If the module is a binary module or a script module that defines241 /// classes, this property if a reference to the assembly, otherwise242 /// it is null.243 /// </summary>244 public Assembly ImplementingAssembly { get; internal set; }245 246 /// <summary>247 /// If this is a script module, then this property will contain248 /// the PowerShell source text that was used to define this module.249 /// </summary>250 public string Definition251 {252 get { return _definitionExtent == null ? string.Empty : _definitionExtent.Text; }253 }254 255 internal IScriptExtent _definitionExtent;256 257 /// <summary>258 /// A description of this module...259 /// </summary>260 public string Description261 {262 get { return _description; }263 264 set { _description = value ?? string.Empty; }265 }266 267 private string _description = string.Empty;268 269 /// <summary>270 /// The guid for this module if one was defined in the module manifest.271 /// </summary>272 public Guid Guid { get; private set; }273 274 internal void SetGuid(Guid guid)275 {276 Guid = guid;277 }278 279 /// <summary>280 /// The HelpInfo for this module if one was defined in the module manifest.281 /// </summary>282 [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")]283 public string HelpInfoUri { get; private set; }284 285 internal bool IsWindowsPowerShellCompatModule { get; set; }286 287 internal void SetHelpInfoUri(string uri)288 {289 HelpInfoUri = uri;290 }291 292 /// <summary>293 /// Get the module base directory for this module. For modules loaded via a module294 /// manifest, this will be the directory containing the manifest file rather than295 /// the directory containing the actual module file. This is particularly useful296 /// when loading a GAC'ed assembly.297 /// </summary>298 public string ModuleBase299 {300 get301 {302 return _moduleBase ??= !string.IsNullOrEmpty(Path) ? IO.Path.GetDirectoryName(Path) : string.Empty;303 }304 }305 306 internal void SetModuleBase(string moduleBase)307 {308 _moduleBase = moduleBase;309 }310 311 private string _moduleBase;312 313 /// <summary>314 /// This value is set from the PrivateData member in the module manifest.315 /// It allows implementor specific data to be passed to the module316 /// via the manifest file.317 /// </summary>318 public object PrivateData319 {320 get321 {322 return _privateData;323 }324 325 set326 {327 _privateData = value;328 SetPSDataPropertiesFromPrivateData();329 }330 }331 332 private object _privateData = null;333 334 private void SetPSDataPropertiesFromPrivateData()335 {336 // Reset the old values of PSData properties.337 _tags.Clear();338 ReleaseNotes = null;339 LicenseUri = null;340 ProjectUri = null;341 IconUri = null;342 343 if (_privateData is Hashtable hashData && hashData["PSData"] is Hashtable psData)344 {345 var tagsValue = psData["Tags"];346 if (tagsValue is object[] tags && tags.Length > 0)347 {348 foreach (var tagString in tags.OfType<string>())349 {350 AddToTags(tagString);351 }352 }353 else if (tagsValue is string tag)354 {355 AddToTags(tag);356 }357 358 if (psData["LicenseUri"] is string licenseUri)359 {360 LicenseUri = GetUriFromString(licenseUri);361 }362 363 if (psData["ProjectUri"] is string projectUri)364 {365 ProjectUri = GetUriFromString(projectUri);366 }367 368 if (psData["IconUri"] is string iconUri)369 {370 IconUri = GetUriFromString(iconUri);371 }372 373 ReleaseNotes = psData["ReleaseNotes"] as string;374 }375 }376 377 private static Uri GetUriFromString(string uriString)378 {379 Uri uri = null;380 if (uriString != null)381 {382 // try creating the Uri object383 // Ignoring the return value from Uri.TryCreate(), as uri value will be null on false or valid uri object on true.384 Uri.TryCreate(uriString, UriKind.Absolute, out uri);385 }386 387 return uri;388 }389 390 /// <summary>391 /// Get the experimental features declared in this module.392 /// </summary>393 public IEnumerable<ExperimentalFeature> ExperimentalFeatures { get; internal set; } = Utils.EmptyReadOnlyCollection<ExperimentalFeature>();394 395 /// <summary>396 /// Tags of this module.397 /// </summary>398 public IEnumerable<string> Tags399 {400 get { return _tags; }401 }402 403 private readonly List<string> _tags = new List<string>();404 405 internal void AddToTags(string tag)406 {407 _tags.Add(tag);408 }409 410 /// <summary>411 /// ProjectUri of this module.412 /// </summary>413 public Uri ProjectUri { get; internal set; }414 415 /// <summary>416 /// IconUri of this module.417 /// </summary>418 public Uri IconUri { get; internal set; }419 420 /// <summary>421 /// LicenseUri of this module.422 /// </summary>423 public Uri LicenseUri { get; internal set; }424 425 /// <summary>426 /// ReleaseNotes of this module.427 /// </summary>428 public string ReleaseNotes { get; internal set; }429 430 /// <summary>431 /// Repository SourceLocation of this module.432 /// </summary>433 public Uri RepositorySourceLocation { get; internal set; }434 435 /// <summary>436 /// The version of this module.437 /// </summary>438 public Version Version { get; private set; } = new Version(0, 0);439 440 /// <summary>441 /// Sets the module version.442 /// </summary>443 /// <param name="version">The version to set...</param>444 internal void SetVersion(Version version)445 {446 Version = version;447 }448 449 /// <summary>450 /// True if the module was compiled (i.e. a .DLL) instead of451 /// being in PowerShell script...452 /// </summary>453 public ModuleType ModuleType { get; private set; } = ModuleType.Script;454 455 /// <summary>456 /// This module as being a compiled module...457 /// </summary>458 internal void SetModuleType(ModuleType moduleType) { ModuleType = moduleType; }459 460 /// <summary>461 /// Module Author.462 /// </summary>463 public string Author464 {465 get; internal set;466 }467 468 /// <summary>469 /// Controls the module access mode...470 /// </summary>471 public ModuleAccessMode AccessMode472 {473 get474 {475 return _accessMode;476 }477 478 set479 {480 if (_accessMode == ModuleAccessMode.Constant)481 {482 throw PSTraceSource.NewInvalidOperationException();483 }484 485 _accessMode = value;486 }487 }488 489 private ModuleAccessMode _accessMode = ModuleAccessMode.ReadWrite;490 491 /// <summary>492 /// CLR Version.493 /// </summary>494 public Version ClrVersion495 {496 get;497 internal set;498 }499 500 /// <summary>501 /// Company Name.502 /// </summary>503 public string CompanyName504 {505 get;506 internal set;507 }508 509 /// <summary>510 /// Copyright.511 /// </summary>512 public string Copyright513 {514 get;515 internal set;516 }517 518 /// <summary>519 /// .NET Framework Version.520 /// </summary>521 public Version DotNetFrameworkVersion522 {523 get;524 internal set;525 }526 527 internal Collection<string> DeclaredFunctionExports = null;528 internal Collection<string> DeclaredCmdletExports = null;529 internal Collection<string> DeclaredAliasExports = null;530 internal Collection<string> DeclaredVariableExports = null;531 532 internal List<string> DetectedFunctionExports = new List<string>();533 internal List<string> DetectedCmdletExports = new List<string>();534 internal Dictionary<string, string> DetectedAliasExports = new Dictionary<string, string>();535 536 /// <summary>537 /// Lists the functions exported by this module...538 /// </summary>539 public Dictionary<string, FunctionInfo> ExportedFunctions540 {541 get542 {543 Dictionary<string, FunctionInfo> exports = new Dictionary<string, FunctionInfo>(StringComparer.OrdinalIgnoreCase);544 545 // If the module is not binary, it may also have functions...546 if (DeclaredFunctionExports != null)547 {548 if (DeclaredFunctionExports.Count == 0)549 {550 return exports;551 }552 553 foreach (string fn in DeclaredFunctionExports)554 {555 FunctionInfo tempFunction = new FunctionInfo(fn, ScriptBlock.EmptyScriptBlock, null) { Module = this };556 exports[fn] = tempFunction;557 }558 }559 else if (SessionState != null)560 {561 // If there is no session state object associated with this list,562 // just return a null list of exports...563 if (SessionState.Internal.ExportedFunctions != null)564 {565 foreach (FunctionInfo fi in SessionState.Internal.ExportedFunctions)566 {567 if (!exports.ContainsKey(fi.Name))568 {569 exports[ModuleCmdletBase.AddPrefixToCommandName(fi.Name, fi.Prefix)] = fi;570 }571 }572 }573 }574 else575 {576 foreach (var detectedExport in DetectedFunctionExports)577 {578 if (!exports.ContainsKey(detectedExport))579 {580 FunctionInfo tempFunction = new FunctionInfo(detectedExport, ScriptBlock.EmptyScriptBlock, null) { Module = this };581 exports[detectedExport] = tempFunction;582 }583 }584 }585 586 return exports;587 }588 }589 590 private static bool IsScriptModuleFile(string path)591 {592 var ext = System.IO.Path.GetExtension(path);593 return ext != null && s_scriptModuleExtensions.Contains(ext);594 }595 596 /// <summary>597 /// Lists the types (PowerShell classes, enums, interfaces) exported by this module.598 /// This returns ASTs for types, created in parse time.599 /// </summary>600 public ReadOnlyDictionary<string, TypeDefinitionAst> GetExportedTypeDefinitions()601 {602 // We cache exported types from this modules, but not from nestedModules,603 // because we may not have NestedModules list populated on the first call.604 // TODO(sevoroby): it may harm perf a little bit. Can we sort it out?605 606 if (_exportedTypeDefinitionsNoNested == null)607 {608 string rootedPath = null;609 if (RootModule == null)610 {611 if (this.Path != null)612 {613 rootedPath = this.Path;614 }615 }616 else617 {618 rootedPath = IO.Path.Combine(this.ModuleBase, this.RootModule);619 }620 621 // ExternalScriptInfo.GetScriptBlockAst() uses a cache layer to avoid re-parsing.622 CreateExportedTypeDefinitions(rootedPath != null && IsScriptModuleFile(rootedPath) && IO.File.Exists(rootedPath) ?623 (new ExternalScriptInfo(rootedPath, rootedPath)).GetScriptBlockAst() : null);624 }625 626 var res = new Dictionary<string, TypeDefinitionAst>(StringComparer.OrdinalIgnoreCase);627 foreach (var nestedModule in this.NestedModules)628 {629 if (nestedModule == this)630 {631 // Circular nested modules could happen with ill-organized module structure.632 // For example, module folder 'test' has two files: 'test.psd1' and 'test.psm1', and 'test.psd1' has the following content:633 // "@{ ModuleVersion = '0.0.1'; RootModule = 'test'; NestedModules = @('test') }"634 // Then, 'Import-Module test.psd1 -PassThru' will return a ModuleInfo object with circular nested modules.635 continue;636 }637 638 foreach (var typePairs in nestedModule.GetExportedTypeDefinitions())639 {640 // The last one name wins! It's the same for command names in nested modules.641 // For rootModule C with Two nested modules (A, B) the order is: A, B, C642 res[typePairs.Key] = typePairs.Value;643 }644 }645 646 foreach (var typePairs in _exportedTypeDefinitionsNoNested)647 {648 res[typePairs.Key] = typePairs.Value;649 }650 651 return new ReadOnlyDictionary<string, TypeDefinitionAst>(res);652 }653 654 /// <summary>655 /// Create ExportedTypeDefinitions from ast.656 /// </summary>657 /// <param name="moduleContentScriptBlockAsts"></param>658 internal void CreateExportedTypeDefinitions(ScriptBlockAst moduleContentScriptBlockAsts)659 {660 if (moduleContentScriptBlockAsts == null)661 {662 this._exportedTypeDefinitionsNoNested = s_emptyTypeDefinitionDictionary;663 }664 else665 {666 this._exportedTypeDefinitionsNoNested = new ReadOnlyDictionary<string, TypeDefinitionAst>(667 moduleContentScriptBlockAsts.FindAll(static a => (a is TypeDefinitionAst), false)668 .OfType<TypeDefinitionAst>()669 .ToDictionary(static a => a.Name, StringComparer.OrdinalIgnoreCase));670 }671 }672 673 internal void AddDetectedTypeExports(List<TypeDefinitionAst> typeDefinitions)674 {675 this._exportedTypeDefinitionsNoNested = new ReadOnlyDictionary<string, TypeDefinitionAst>(676 typeDefinitions.ToDictionary(static a => a.Name, StringComparer.OrdinalIgnoreCase));677 }678 679 /// <summary>680 /// Prefix.681 /// </summary>682 public string Prefix683 {684 get;685 internal set;686 }687 688 /// <summary>689 /// Add function to the fixed exports list.690 /// </summary>691 /// <param name="name">The function to add.</param>692 internal void AddDetectedFunctionExport(string name)693 {694 Dbg.Assert(name != null, "AddDetectedFunctionExport should not be called with a null value");695 696 if (!DetectedFunctionExports.Contains(name))697 {698 DetectedFunctionExports.Add(name);699 }700 }701 702 /// <summary>703 /// Lists the functions exported by this module...704 /// </summary>705 public Dictionary<string, CmdletInfo> ExportedCmdlets706 {707 get708 {709 Dictionary<string, CmdletInfo> exports = new Dictionary<string, CmdletInfo>(StringComparer.OrdinalIgnoreCase);710 711 if (DeclaredCmdletExports != null)712 {713 if (DeclaredCmdletExports.Count == 0)714 {715 return exports;716 }717 718 foreach (string fn in DeclaredCmdletExports)719 {720 CmdletInfo tempCmdlet = new CmdletInfo(fn, null, null, null, null) { Module = this };721 exports[fn] = tempCmdlet;722 }723 }724 else if ((CompiledExports != null) && (CompiledExports.Count > 0))725 {726 foreach (CmdletInfo cmdlet in CompiledExports)727 {728 exports[cmdlet.Name] = cmdlet;729 }730 }731 else732 {733 foreach (string detectedExport in DetectedCmdletExports)734 {735 if (!exports.ContainsKey(detectedExport))736 {737 CmdletInfo tempCmdlet = new CmdletInfo(detectedExport, null, null, null, null) { Module = this };738 exports[detectedExport] = tempCmdlet;739 }740 }741 }742 743 return exports;744 }745 }746 747 /// <summary>748 /// Add CmdletInfo to the fixed exports list...749 /// </summary>750 /// <param name="cmdlet">The cmdlet to add...</param>751 internal void AddDetectedCmdletExport(string cmdlet)752 {753 Dbg.Assert(cmdlet != null, "AddDetectedCmdletExport should not be called with a null value");754 755 if (!DetectedCmdletExports.Contains(cmdlet))756 {757 DetectedCmdletExports.Add(cmdlet);758 }759 }760 761 /// <summary>762 /// Gets the aggregated list of visible commands exported from the module. If there are two763 /// commands of different types exported with the same name (e.g. alias 'foo' and cmdlet 'foo') the764 /// combined dictionary will only contain the highest precedence cmdlet (e.g. the alias 'foo' since765 /// aliases shadow cmdlets.766 /// </summary>767 public Dictionary<string, CommandInfo> ExportedCommands768 {769 get770 {771 Dictionary<string, CommandInfo> exports = new Dictionary<string, CommandInfo>(StringComparer.OrdinalIgnoreCase);772 Dictionary<string, CmdletInfo> cmdlets = this.ExportedCmdlets;773 if (cmdlets != null)774 {775 foreach (var cmdlet in cmdlets)776 {777 exports[cmdlet.Key] = cmdlet.Value;778 }779 }780 781 Dictionary<string, FunctionInfo> functions = this.ExportedFunctions;782 if (functions != null)783 {784 foreach (var function in functions)785 {786 exports[function.Key] = function.Value;787 }788 }789 790 Dictionary<string, AliasInfo> aliases = this.ExportedAliases;791 if (aliases != null)792 {793 foreach (var alias in aliases)794 {795 exports[alias.Key] = alias.Value;796 }797 }798 799 return exports;800 }801 }802 803 /// <summary>804 /// Add CmdletInfo to the fixed exports list...805 /// </summary>806 /// <param name="cmdlet">The cmdlet to add...</param>807 internal void AddExportedCmdlet(CmdletInfo cmdlet)808 {809 Dbg.Assert(cmdlet != null, "AddExportedCmdlet should not be called with a null value");810 _compiledExports.Add(cmdlet);811 }812 813 /// <summary>814 /// Return the merged list of exported cmdlets. This is necessary815 /// because you may have a binary module with nested modules where816 /// some cmdlets come from the module and others come from the nested817 /// module. We need to consolidate the list so it can properly be constrained.818 /// </summary>819 internal List<CmdletInfo> CompiledExports820 {821 get822 {823 // If this module has a session state instance and there are any824 // exported cmdlets in the session state, migrate them to the825 // module info _compiledCmdlets entry.826 if (SessionState != null && SessionState.Internal.ExportedCmdlets != null &&827 SessionState.Internal.ExportedCmdlets.Count > 0)828 {829 foreach (CmdletInfo ci in SessionState.Internal.ExportedCmdlets)830 {831 _compiledExports.Add(ci);832 }833 834 SessionState.Internal.ExportedCmdlets.Clear();835 }836 837 return _compiledExports;838 }839 }840 841 private readonly List<CmdletInfo> _compiledExports = new List<CmdletInfo>();842 843 /// <summary>844 /// Add AliasInfo to the fixed exports list...845 /// </summary>846 /// <param name="aliasInfo">The cmdlet to add...</param>847 internal void AddExportedAlias(AliasInfo aliasInfo)848 {849 Dbg.Assert(aliasInfo != null, "AddExportedAlias should not be called with a null value");850 CompiledAliasExports.Add(aliasInfo);851 }852 853 /// <summary>854 /// Return the merged list of exported aliases. This is necessary855 /// because you may have a binary module with nested modules where856 /// some aliases come from the module and others come from the nested857 /// module. We need to consolidate the list so it can properly be constrained.858 /// </summary>859 internal List<AliasInfo> CompiledAliasExports { get; } = new List<AliasInfo>();860 861 /// <summary>862 /// FileList.863 /// </summary>864 public IEnumerable<string> FileList865 {866 get { return _fileList; }867 }868 869 private List<string> _fileList = new List<string>();870 871 internal void AddToFileList(string file)872 {873 _fileList.Add(file);874 }875 876 /// <summary>877 /// Lists the PowerShell editions this module is compatible with. This should878 /// reflect the module manifest the module was loaded with, or if no manifest was given879 /// or the key was not in the manifest, this should be an empty collection. This880 /// property is never null.881 /// </summary>882 public IEnumerable<string> CompatiblePSEditions883 {884 get { return _compatiblePSEditions; }885 }886 887 private readonly List<string> _compatiblePSEditions = new List<string>();888 889 internal void AddToCompatiblePSEditions(string psEdition)890 {891 _compatiblePSEditions.Add(psEdition);892 }893 894 internal void AddToCompatiblePSEditions(IEnumerable<string> psEditions)895 {896 _compatiblePSEditions.AddRange(psEditions);897 }898 899 /// <summary>900 /// Describes whether the module was considered compatible at load time.901 /// Any module not on the System32 module path should have this as true.902 /// Modules loaded from the System32 module path will have this as true if they903 /// have declared edition compatibility with PowerShell 6+. Currently, this field904 /// is true for all non-psd1 module files, when it should not be. Being able to905 /// load psm1/dll modules from the System32 module path without needing to skip906 /// the edition check is considered a bug and should be fixed.907 /// </summary>908 internal bool IsConsideredEditionCompatible { get; set; } = true;909 910 /// <summary>911 /// ModuleList.912 /// </summary>913 public IEnumerable<object> ModuleList914 {915 get { return _moduleList; }916 }917 918 private Collection<object> _moduleList = new Collection<object>();919 920 internal void AddToModuleList(object m)921 {922 _moduleList.Add(m);923 }924 925 /// <summary>926 /// Returns the list of child modules of this module. This will only927 /// be non-empty for module manifests.928 /// </summary>929 public ReadOnlyCollection<PSModuleInfo> NestedModules930 {931 get932 {933 return _readonlyNestedModules ??= new ReadOnlyCollection<PSModuleInfo>(_nestedModules);934 }935 }936 937 private ReadOnlyCollection<PSModuleInfo> _readonlyNestedModules;938 939 /// <summary>940 /// Add a module to the list of child modules.941 /// </summary>942 /// <param name="nestedModule">The module to add.</param>943 internal void AddNestedModule(PSModuleInfo nestedModule)944 {945 AddModuleToList(nestedModule, _nestedModules);946 }947 948 private readonly List<PSModuleInfo> _nestedModules = new List<PSModuleInfo>();949 950 /// <summary>951 /// PowerShell Host Name.952 /// </summary>953 public string PowerShellHostName954 {955 get;956 internal set;957 }958 959 /// <summary>960 /// PowerShell Host Version.961 /// </summary>962 public Version PowerShellHostVersion963 {964 get;965 internal set;966 }967 968 /// <summary>969 /// PowerShell Version.970 /// </summary>971 public Version PowerShellVersion972 {973 get;974 internal set;975 }976 977 /// <summary>978 /// Processor Architecture.979 /// </summary>980 public ProcessorArchitecture ProcessorArchitecture981 {982 get;983 internal set;984 }985 986 /// <summary>987 /// Scripts to Process.988 /// </summary>989 public IEnumerable<string> Scripts990 {991 get { return _scripts; }992 }993 994 private List<string> _scripts = new List<string>();995 996 internal void AddScript(string s)997 {998 _scripts.Add(s);999 }1000 1001 /// <summary>1002 /// Required Assemblies.1003 /// </summary>1004 public IEnumerable<string> RequiredAssemblies1005 {1006 get { return _requiredAssemblies; }1007 }1008 1009 private Collection<string> _requiredAssemblies = new Collection<string>();1010 1011 internal void AddRequiredAssembly(string assembly)1012 {1013 _requiredAssemblies.Add(assembly);1014 }1015 1016 /// <summary>1017 /// Returns the list of required modules of this module. This will only1018 /// be non-empty for module manifests.1019 /// </summary>1020 public ReadOnlyCollection<PSModuleInfo> RequiredModules1021 {1022 get1023 {1024 return _readonlyRequiredModules ??= new ReadOnlyCollection<PSModuleInfo>(_requiredModules);1025 }1026 }1027 1028 private ReadOnlyCollection<PSModuleInfo> _readonlyRequiredModules;1029 1030 /// <summary>1031 /// Add a module to the list of required modules.1032 /// </summary>1033 /// <param name="requiredModule">The module to add.</param>1034 internal void AddRequiredModule(PSModuleInfo requiredModule)1035 {1036 AddModuleToList(requiredModule, _requiredModules);1037 }1038 1039 private List<PSModuleInfo> _requiredModules = new List<PSModuleInfo>();1040 1041 /// <summary>1042 /// Returns the list of required modules specified in the module manifest of this module. This will only1043 /// be non-empty for module manifests.1044 /// </summary>1045 internal ReadOnlyCollection<ModuleSpecification> RequiredModulesSpecification1046 {1047 get1048 {1049 return _readonlyRequiredModulesSpecification ??= new ReadOnlyCollection<ModuleSpecification>(_requiredModulesSpecification);1050 }1051 }1052 1053 private ReadOnlyCollection<ModuleSpecification> _readonlyRequiredModulesSpecification;1054 1055 /// <summary>1056 /// Add a module to the list of required modules specification.1057 /// </summary>1058 /// <param name="requiredModuleSpecification">The module to add.</param>1059 internal void AddRequiredModuleSpecification(ModuleSpecification requiredModuleSpecification)1060 {1061 _requiredModulesSpecification.Add(requiredModuleSpecification);1062 }1063 1064 private List<ModuleSpecification> _requiredModulesSpecification = new List<ModuleSpecification>();1065 1066 /// <summary>1067 /// Root Module.1068 /// </summary>1069 public string RootModule1070 {1071 get;1072 internal set;1073 }1074 1075 /// <summary>1076 /// This member is used to copy over the RootModule in case the module is a manifest module1077 /// This is so that only ModuleInfo for modules with type=Manifest have RootModule populated.1078 /// </summary>1079 internal string RootModuleForManifest1080 {1081 get;1082 set;1083 }1084 1085 /// <summary>1086 /// Add a module to the list of modules, avoiding adding duplicates.1087 /// </summary>1088 private static void AddModuleToList(PSModuleInfo module, List<PSModuleInfo> moduleList)1089 {1090 Dbg.Assert(module != null, "AddModuleToList should not be called with a null value");1091 // Add the module if it isn't already there...1092 foreach (PSModuleInfo m in moduleList)1093 {1094 if (m.Path.Equals(module.Path, StringComparison.OrdinalIgnoreCase))1095 return;1096 }1097 1098 moduleList.Add(module);1099 }1100 1101 internal static readonly string[] _builtinVariables = new string[] { "_", "this", "input", "args", "true", "false", "null",1102 "PSDefaultParameterValues", "Error", "PSScriptRoot", "PSCommandPath", "MyInvocation", "ExecutionContext", "StackTrace" };1103 1104 /// <summary>1105 /// Lists the variables exported by this module.1106 /// </summary>1107 public Dictionary<string, PSVariable> ExportedVariables1108 {1109 get1110 {1111 Dictionary<string, PSVariable> exportedVariables = new Dictionary<string, PSVariable>(StringComparer.OrdinalIgnoreCase);1112 1113 if ((DeclaredVariableExports != null) && (DeclaredVariableExports.Count > 0))1114 {1115 foreach (string fn in DeclaredVariableExports)1116 {1117 exportedVariables[fn] = null;1118 }1119 }1120 else1121 {1122 // If there is no session state object associated with this list,1123 // just return a null list of exports. This will be true if the1124 // module is a compiled module.1125 if (SessionState == null || SessionState.Internal.ExportedVariables == null)1126 {1127 return exportedVariables;1128 }1129 1130 foreach (PSVariable v in SessionState.Internal.ExportedVariables)1131 {1132 exportedVariables[v.Name] = v;1133 }1134 }1135 1136 return exportedVariables;1137 }1138 }1139 1140 /// <summary>1141 /// Lists the aliases exported by this module.1142 /// </summary>1143 public Dictionary<string, AliasInfo> ExportedAliases1144 {1145 get1146 {1147 Dictionary<string, AliasInfo> exportedAliases = new Dictionary<string, AliasInfo>(StringComparer.OrdinalIgnoreCase);1148 1149 if ((DeclaredAliasExports != null) && (DeclaredAliasExports.Count > 0))1150 {1151 foreach (string fn in DeclaredAliasExports)1152 {1153 AliasInfo tempAlias = new AliasInfo(fn, null, null) { Module = this };1154 exportedAliases[fn] = tempAlias;1155 }1156 }1157 else if ((CompiledAliasExports != null) && (CompiledAliasExports.Count > 0))1158 {1159 foreach (AliasInfo ai in CompiledAliasExports)1160 {1161 exportedAliases[ai.Name] = ai;1162 }1163 }1164 else1165 {1166 // There is no session state object associated with this list.1167 if (SessionState == null)1168 {1169 // Check if we detected any1170 if (DetectedAliasExports.Count > 0)1171 {1172 foreach (var pair in DetectedAliasExports)1173 {1174 string detectedExport = pair.Key;1175 if (!exportedAliases.ContainsKey(detectedExport))1176 {1177 AliasInfo tempAlias = new AliasInfo(detectedExport, pair.Value, null) { Module = this };1178 exportedAliases[detectedExport] = tempAlias;1179 }1180 }1181 }1182 else1183 {1184 // just return a null list of exports. This will be true if the1185 // module is a compiled module.1186 return exportedAliases;1187 }1188 }1189 else1190 {1191 // We have a session state1192 foreach (AliasInfo ai in SessionState.Internal.ExportedAliases)1193 {1194 exportedAliases[ai.Name] = ai;1195 }1196 }1197 }1198 1199 return exportedAliases;1200 }