MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Concurrent;6using System.Collections.Generic;7using System.Collections.ObjectModel;8using System.Diagnostics.CodeAnalysis;9using System.Diagnostics.Tracing;10using System.IO;11using System.Linq;12using System.Management.Automation.Host;13using System.Management.Automation.Internal;14using System.Management.Automation.Language;15using System.Management.Automation.Provider;16using System.Management.Automation.Security;17using System.Reflection;18using System.Runtime.CompilerServices;19using System.Text;20using System.Threading;21using System.Threading.Tasks;22 23using Microsoft.PowerShell.Commands;24 25using Debug = System.Management.Automation.Diagnostics;26 27namespace System.Management.Automation.Runspaces28{29 internal static class EarlyStartup30 {31 internal static void Init()32 {33 // Code added here should:34 // * run every time we start PowerSHell35 // * have high CPU cost36 // * be ordered from most expensive to least expensive, or at least needed earliest37 // * this method should return quickly, so all work should be run in one or more tasks.38 // * code called from here should correctly handle being called twice, in case initialization39 // is needed in the main code path before the task completes.40 //41 // Code added here should not:42 // * count on running - not all hosts will call this method43 // * have high disk cost44 45 // We shouldn't create too many tasks.46#if !UNIX47 // Amsi initialize can be a little slow.48 Task.Run(() => AmsiUtils.WinScanContent(content: string.Empty, sourceMetadata: string.Empty, warmUp: true));49#endif50 // Initialize the types 'Compiler', 'CachedReflectionInfo', and 'ExpressionCache'.51 // Their type initializers do a lot of reflection operations.52 // We will access 'Compiler' members when creating the first session state.53 Task.Run(() => _ = Compiler.DottedLocalsTupleType);54 55 // One other task for other stuff that's faster, but still a little slow.56 Task.Run(() =>57 {58 // Loading the resources for System.Management.Automation can be expensive,59 // so force that to happen early on a background thread.60 _ = RunspaceInit.OutputEncodingDescription;61 62 // This will init some tables and could load some assemblies.63 // We will access 'LanguagePrimitives' when binding built-in variables for the Runspace.64 LanguagePrimitives.GetEnumerator(null);65 66 // This will init some tables and could load some assemblies.67 // We will access 'TypeAccelerators' when auto-loading the PSReadLine module, which happens last.68 _ = TypeAccelerators.builtinTypeAccelerators;69 });70 }71 }72 73 /// <summary>74 /// Baseclass for defining elements that can be added75 /// to an InitialSessionState object.76 /// </summary>77 public abstract class InitialSessionStateEntry78 {79 /// <summary>80 /// The ctor so that each derived class has a name.81 /// </summary>82 /// <param name="name"></param>83 protected InitialSessionStateEntry(string name)84 {85 Name = name;86 }87 88 /// <summary>89 /// The name of this entry.90 /// </summary>91 public string Name { get; internal set; }92 93 /// <summary>94 /// The SnapIn to load from initially.95 /// </summary>96 public PSSnapInInfo PSSnapIn { get; private set; }97 98 internal void SetPSSnapIn(PSSnapInInfo psSnapIn)99 {100 PSSnapIn = psSnapIn;101 }102 103 /// <summary>104 /// The SnapIn to load from initially.105 /// </summary>106 public PSModuleInfo Module { get; private set; }107 108 internal void SetModule(PSModuleInfo module)109 {110 Module = module;111 }112 113 /// <summary>114 /// Shallow-clone this object.115 /// </summary>116 /// <returns>The cloned object...</returns>117 public abstract InitialSessionStateEntry Clone();118 }119 120 /// <summary>121 /// Class to constrain session state entries.122 /// </summary>123 public abstract class ConstrainedSessionStateEntry : InitialSessionStateEntry124 {125 /// <summary>126 /// </summary>127 /// <param name="name"></param>128 /// <param name="visibility"></param>129 protected ConstrainedSessionStateEntry(string name, SessionStateEntryVisibility visibility)130 : base(name)131 {132 Visibility = visibility;133 }134 135 /// <summary>136 /// </summary>137 public SessionStateEntryVisibility Visibility { get; set; }138 }139 140 /// <summary>141 /// Command class so that all the commands can derive off this one.142 /// Adds the flexibility of adding additional derived class,143 /// such as ProxyCommand for Exchange.144 /// Derived classes - Alias, Application, Cmdlet, Function, Script.145 /// </summary>146 public abstract class SessionStateCommandEntry : ConstrainedSessionStateEntry147 {148 /// <summary>149 /// Base constructor for all SessionState commands.150 /// </summary>151 /// <param name="name"></param>152 protected SessionStateCommandEntry(string name)153 : base(name, SessionStateEntryVisibility.Public)154 {155 }156 157 /// <summary>158 /// </summary>159 /// <param name="name"></param>160 /// <param name="visibility"></param>161 protected internal SessionStateCommandEntry(string name, SessionStateEntryVisibility visibility)162 : base(name, visibility)163 {164 }165 166 /// <summary>167 /// Returns the type of the command using an enum168 /// instead of requiring a full reflection type check.169 /// </summary>170 public CommandTypes CommandType { get; internal set; }171 172 /// <summary>173 /// Is internal so it can be set by the engine code...174 /// This is used to specify whether this command was imported or not175 /// If noClobber is specified during Import-Module, it is set to false.176 /// </summary>177 internal bool _isImported = true;178 }179 180 /// <summary>181 /// Type file configuration entry...182 /// </summary>183 public sealed class SessionStateTypeEntry : InitialSessionStateEntry184 {185 /// <summary>186 /// Loads all entries from the types file.187 /// </summary>188 /// <param name="fileName"></param>189 public SessionStateTypeEntry(string fileName)190 : base(fileName)191 {192 if (string.IsNullOrWhiteSpace(fileName))193 {194 throw PSTraceSource.NewArgumentException(nameof(fileName));195 }196 197 FileName = fileName.Trim();198 }199 200 /// <summary>201 /// Loads all the types specified in the typeTable.202 /// </summary>203 /// <param name="typeTable"></param>204 public SessionStateTypeEntry(TypeTable typeTable)205 : base("*")206 {207 if (typeTable == null)208 {209 throw PSTraceSource.NewArgumentNullException(nameof(typeTable));210 }211 212 TypeTable = typeTable;213 }214 215 /// <summary>216 /// Loads all entries from the typeData.217 /// </summary>218 /// <param name="typeData"></param>219 /// <param name="isRemove"></param>220 public SessionStateTypeEntry(TypeData typeData, bool isRemove)221 : base("*")222 {223 if (typeData == null)224 {225 throw PSTraceSource.NewArgumentNullException(nameof(typeData));226 }227 228 TypeData = typeData;229 IsRemove = isRemove;230 }231 232 /// <summary>233 /// Shallow-clone this object.234 /// </summary>235 /// <returns>The cloned object.</returns>236 public override InitialSessionStateEntry Clone()237 {238 SessionStateTypeEntry entry;239 if (FileName != null)240 {241 entry = new SessionStateTypeEntry(FileName);242 }243 else if (TypeTable != null)244 {245 entry = new SessionStateTypeEntry(TypeTable);246 }247 else248 {249 entry = new SessionStateTypeEntry(TypeData, IsRemove);250 }251 252 entry.SetPSSnapIn(this.PSSnapIn);253 entry.SetModule(this.Module);254 return entry;255 }256 257 /// <summary>258 /// The pathname of the types.ps1xml file. This can be null if259 /// TypeTable constructor or TypeData constructor is used.260 /// </summary>261 public string FileName { get; }262 263 /// <summary>264 /// The TypeTable specified with constructor. This can be null if265 /// FileName constructor or TypeData constructor is used.266 /// </summary>267 public TypeTable TypeTable { get; }268 269 /// <summary>270 /// The TypeData we want to update with. This can be null if271 /// FileName constructor or TypeTable constructor is used.272 /// </summary>273 public TypeData TypeData { get; }274 275 /// <summary>276 /// The operation will be done on the typedata. This is only277 /// meaningful when the TypeData constructor is used.278 /// </summary>279 public bool IsRemove { get; }280 281 // So that we can specify the type information on the fly,282 // without using Types.ps1xml file283 // public SessionStateTypeEntry(string name, xmlreader definition);284 // public string Definition { get; }285 }286 287 /// <summary>288 /// Format file configuration entry...289 /// </summary>290 public sealed class SessionStateFormatEntry : InitialSessionStateEntry291 {292 /// <summary>293 /// Loads the entire formats file.294 /// </summary>295 /// <param name="fileName"></param>296 public SessionStateFormatEntry(string fileName)297 : base("*")298 {299 if (string.IsNullOrWhiteSpace(fileName))300 {301 throw PSTraceSource.NewArgumentException(nameof(fileName));302 }303 304 FileName = fileName.Trim();305 }306 307 /// <summary>308 /// Loads all the format data specified in the formatTable.309 /// </summary>310 /// <param name="formattable"></param>311 public SessionStateFormatEntry(FormatTable formattable)312 : base("*")313 {314 if (formattable == null)315 {316 throw PSTraceSource.NewArgumentNullException(nameof(formattable));317 }318 319 Formattable = formattable;320 }321 322 /// <summary>323 /// Loads all the format data specified in the typeDefinition.324 /// </summary>325 /// <param name="typeDefinition"></param>326 public SessionStateFormatEntry(ExtendedTypeDefinition typeDefinition)327 : base("*")328 {329 if (typeDefinition == null)330 {331 throw PSTraceSource.NewArgumentNullException(nameof(typeDefinition));332 }333 334 FormatData = typeDefinition;335 }336 337 /// <summary>338 /// Shallow-clone this object...339 /// </summary>340 /// <returns>The cloned object.</returns>341 public override InitialSessionStateEntry Clone()342 {343 SessionStateFormatEntry entry;344 345 if (FileName != null)346 {347 entry = new SessionStateFormatEntry(FileName);348 }349 else if (Formattable != null)350 {351 entry = new SessionStateFormatEntry(Formattable);352 }353 else354 {355 entry = new SessionStateFormatEntry(FormatData);356 }357 358 entry.SetPSSnapIn(this.PSSnapIn);359 entry.SetModule(this.Module);360 return entry;361 }362 363 /// <summary>364 /// The name of the format file referenced by this entry...365 /// </summary>366 public string FileName { get; }367 368 /// <summary>369 /// The FormatTable specified with constructor. This can be null if370 /// FileName constructor is used.371 /// </summary>372 public FormatTable Formattable { get; }373 374 /// <summary>375 /// The FormatData specified with constructor.376 /// This can be null if the FileName or FormatTable constructors are used.377 /// </summary>378 public ExtendedTypeDefinition FormatData { get; }379 380 // So that we can specify the format information on the fly,381 // without using Format.ps1xml file382 // public SessionStateFormatEntry(string name, xmlreader definition);383 // public string Definition { get; }384 }385 386 /// <summary>387 /// An assembly to load for this sessionstate...388 /// </summary>389 public sealed class SessionStateAssemblyEntry : InitialSessionStateEntry390 {391 /// <summary>392 /// Create a named entry for the assembly to load with both the393 /// name and the path to the assembly as a backup.394 /// </summary>395 /// <param name="name">The name of the assembly to load.</param>396 /// <param name="fileName">The path to the assembly to use as an alternative.</param>397 public SessionStateAssemblyEntry(string name, string fileName)398 : base(name)399 {400 FileName = fileName;401 }402 403 /// <summary>404 /// Create a named entry for the assembly to load, specifying405 /// just the name.406 /// </summary>407 /// <param name="name">The name of the assembly to load.</param>408 public SessionStateAssemblyEntry(string name)409 : base(name)410 {411 }412 413 /// <summary>414 /// Shallow-clone this object.415 /// </summary>416 /// <returns>The cloned object.</returns>417 public override InitialSessionStateEntry Clone()418 {419 var entry = new SessionStateAssemblyEntry(Name, FileName);420 entry.SetPSSnapIn(this.PSSnapIn);421 entry.SetModule(this.Module);422 return entry;423 }424 425 /// <summary>426 /// Return the assembly file name...427 /// </summary>428 public string FileName { get; }429 }430 431 /// <summary>432 /// List a cmdlet to add to this session state entry.433 /// </summary>434 public sealed class SessionStateCmdletEntry : SessionStateCommandEntry435 {436 /// <summary>437 /// </summary>438 /// <param name="name"></param>439 /// <param name="implementingType"></param>440 /// <param name="helpFileName"></param>441 public SessionStateCmdletEntry(string name, Type implementingType, string helpFileName)442 : base(name, SessionStateEntryVisibility.Public)443 {444 ImplementingType = implementingType;445 HelpFileName = helpFileName;446 CommandType = CommandTypes.Cmdlet;447 }448 449 /// <summary>450 /// </summary>451 /// <param name="name"></param>452 /// <param name="implementingType"></param>453 /// <param name="helpFileName"></param>454 /// <param name="visibility"></param>455 internal SessionStateCmdletEntry(string name, Type implementingType, string helpFileName, SessionStateEntryVisibility visibility)456 : base(name, visibility)457 {458 ImplementingType = implementingType;459 HelpFileName = helpFileName;460 CommandType = CommandTypes.Cmdlet;461 }462 463 /// <summary>464 /// Shallow-clone this object...465 /// </summary>466 /// <returns></returns>467 public override InitialSessionStateEntry Clone()468 {469 SessionStateCmdletEntry entry = new SessionStateCmdletEntry(Name, ImplementingType, HelpFileName, Visibility);470 entry.SetPSSnapIn(this.PSSnapIn);471 entry.SetModule(this.Module);472 return entry;473 }474 475 /// <summary>476 /// </summary>477 public Type ImplementingType { get; }478 479 /// <summary>480 /// </summary>481 public string HelpFileName { get; }482 }483 484 /// <summary>485 /// </summary>486 public sealed class SessionStateProviderEntry : ConstrainedSessionStateEntry487 {488 /// <summary>489 /// </summary>490 /// <param name="name"></param>491 /// <param name="implementingType"></param>492 /// <param name="helpFileName"></param>493 public SessionStateProviderEntry(string name, Type implementingType, string helpFileName)494 : base(name, SessionStateEntryVisibility.Public)495 {496 ImplementingType = implementingType;497 HelpFileName = helpFileName;498 }499 500 internal SessionStateProviderEntry(string name, Type implementingType, string helpFileName, SessionStateEntryVisibility visibility)501 : base(name, visibility)502 {503 ImplementingType = implementingType;504 HelpFileName = helpFileName;505 }506 507 /// <summary>508 /// Shallow-clone this object...509 /// </summary>510 /// <returns>The cloned object.</returns>511 public override InitialSessionStateEntry Clone()512 {513 SessionStateProviderEntry entry = new SessionStateProviderEntry(Name, ImplementingType, HelpFileName, this.Visibility);514 entry.SetPSSnapIn(this.PSSnapIn);515 entry.SetModule(this.Module);516 return entry;517 }518 519 /// <summary>520 /// </summary>521 public Type ImplementingType { get; }522 523 /// <summary>524 /// </summary>525 public string HelpFileName { get; }526 }527 528 /// <summary>529 /// </summary>530 public sealed class SessionStateScriptEntry : SessionStateCommandEntry531 {532 /// <summary>533 /// Create a session state command entry instance.534 /// </summary>535 /// <param name="path">The path to the script.</param>536 public SessionStateScriptEntry(string path)537 : base(path, SessionStateEntryVisibility.Public)538 {539 Path = path;540 CommandType = CommandTypes.ExternalScript;541 }542 543 /// <summary>544 /// Create a session state command entry instance with the specified visibility.545 /// </summary>546 /// <param name="path">The path to the script.</param>547 /// <param name="visibility">Visibility of the script.</param>548 internal SessionStateScriptEntry(string path, SessionStateEntryVisibility visibility)549 : base(path, visibility)550 {551 Path = path;552 CommandType = CommandTypes.ExternalScript;553 }554 555 /// <summary>556 /// Shallow-clone this object...557 /// </summary>558 /// <returns>The cloned object.</returns>559 public override InitialSessionStateEntry Clone()560 {561 SessionStateScriptEntry entry = new SessionStateScriptEntry(Path, Visibility);562 entry.SetModule(this.Module);563 return entry;564 }565 566 /// <summary>567 /// </summary>568 public string Path { get; }569 }570 571 /// <summary>572 /// </summary>573 public sealed class SessionStateAliasEntry : SessionStateCommandEntry574 {575 /// <summary>576 /// Define an alias entry to add to the initial session state.577 /// </summary>578 /// <param name="name">The name of the alias entry to add.</param>579 /// <param name="definition">The name of the command it resolves to.</param>580 public SessionStateAliasEntry(string name, string definition)581 : base(name, SessionStateEntryVisibility.Public)582 {583 Definition = definition;584 CommandType = CommandTypes.Alias;585 }586 587 /// <summary>588 /// Define an alias entry to add to the initial session state.589 /// </summary>590 /// <param name="name">The name of the alias entry to add.</param>591 /// <param name="definition">The name of the command it resolves to.</param>592 /// <param name="description">A description of the purpose of the alias.</param>593 public SessionStateAliasEntry(string name, string definition, string description)594 : base(name, SessionStateEntryVisibility.Public)595 {596 Definition = definition;597 CommandType = CommandTypes.Alias;598 Description = description;599 }600 601 /// <summary>602 /// Define an alias entry to add to the initial session state.603 /// </summary>604 /// <param name="name">The name of the alias entry to add.</param>605 /// <param name="definition">The name of the command it resolves to.</param>606 /// <param name="description">A description of the purpose of the alias.</param>607 /// <param name="options">Options defining the scope visibility, readonly and constant.</param>608 public SessionStateAliasEntry(string name, string definition, string description, ScopedItemOptions options)609 : base(name, SessionStateEntryVisibility.Public)610 {611 Definition = definition;612 CommandType = CommandTypes.Alias;613 Description = description;614 Options = options;615 }616 617 /// <summary>618 /// Define an alias entry to add to the initial session state.619 /// </summary>620 /// <param name="name">The name of the alias entry to add.</param>621 /// <param name="definition">The name of the command it resolves to.</param>622 /// <param name="description">A description of the purpose of the alias.</param>623 /// <param name="options">Options defining the scope visibility, readonly and constant.</param>624 /// <param name="visibility"></param>625 internal SessionStateAliasEntry(string name, string definition, string description, ScopedItemOptions options, SessionStateEntryVisibility visibility)626 : base(name, visibility)627 {628 Definition = definition;629 CommandType = CommandTypes.Alias;630 Description = description;631 Options = options;632 }633 /// <summary>634 /// Shallow-clone this object...635 /// </summary>636 /// <returns>The cloned object.</returns>637 public override InitialSessionStateEntry Clone()638 {639 SessionStateAliasEntry entry = new SessionStateAliasEntry(Name, Definition, Description, Options, Visibility);640 entry.SetModule(this.Module);641 return entry;642 }643 644 /// <summary>645 /// The string defining the body of this alias...646 /// </summary>647 public string Definition { get; }648 649 /// <summary>650 /// A string describing this alias...651 /// </summary>652 public string Description { get; } = string.Empty;653 654 /// <summary>655 /// Options controlling scope visibility and setability for this entry.656 /// </summary>657 public ScopedItemOptions Options { get; } = ScopedItemOptions.None;658 }659 660 /// <summary>661 /// </summary>662 public sealed class SessionStateApplicationEntry : SessionStateCommandEntry663 {664 /// <summary>665 /// Used to define a permitted script in this session state. If the path is666 /// "*", then any path is permitted.667 /// </summary>668 /// <param name="path">The full path to the application.</param>669 public SessionStateApplicationEntry(string path)670 : base(path, SessionStateEntryVisibility.Public)671 {672 Path = path;673 CommandType = CommandTypes.Application;674 }675 676 /// <summary>677 /// Used to define a permitted script in this session state. If the path is678 /// "*", then any path is permitted.679 /// </summary>680 /// <param name="path">The full path to the application.</param>681 /// <param name="visibility">Sets the external visibility of the path.</param>682 internal SessionStateApplicationEntry(string path, SessionStateEntryVisibility visibility)683 : base(path, visibility)684 {685 Path = path;686 CommandType = CommandTypes.Application;687 }688 689 /// <summary>690 /// Shallow-clone this object...691 /// </summary>692 /// <returns>The cloned object.</returns>693 public override InitialSessionStateEntry Clone()694 {695 SessionStateApplicationEntry entry = new SessionStateApplicationEntry(Path, Visibility);696 entry.SetModule(this.Module);697 return entry;698 }699 700 /// <summary>701 /// The path to this application...702 /// </summary>703 public string Path { get; }704 }705 706 /// <summary>707 /// </summary>708 public sealed class SessionStateFunctionEntry : SessionStateCommandEntry709 {710 /// <summary>711 /// Represents a function definition in an Initial session state object.712 /// </summary>713 /// <param name="name">The name of the function.</param>714 /// <param name="definition">The definition of the function.</param>715 /// <param name="options">Options controlling scope-related elements of this object.</param>716 /// <param name="helpFile">The name of the help file associated with the function.</param>717 public SessionStateFunctionEntry(string name, string definition, ScopedItemOptions options, string helpFile)718 : base(name, SessionStateEntryVisibility.Public)719 {720 Definition = definition;721 CommandType = CommandTypes.Function;722 Options = options;723 ScriptBlock = ScriptBlock.Create(Definition);724 ScriptBlock.LanguageMode = PSLanguageMode.FullLanguage;725 726 HelpFile = helpFile;727 }728 729 /// <summary>730 /// Represents a function definition in an Initial session state object.731 /// </summary>732 /// <param name="name">The name of the function.</param>733 /// <param name="definition">The definition of the function.</param>734 /// <param name="helpFile">The name of the help file associated with the function.</param>735 public SessionStateFunctionEntry(string name, string definition, string helpFile)736 : this(name, definition, ScopedItemOptions.None, helpFile)737 {738 }739 740 /// <summary>741 /// Represents a function definition in an Initial session state object.742 /// </summary>743 /// <param name="name">The name of the function.</param>744 /// <param name="definition">The definition of the function.</param>745 public SessionStateFunctionEntry(string name, string definition)746 : this(name, definition, ScopedItemOptions.None, null)747 {748 }749 750 /// <summary>751 /// This is an internal copy constructor.752 /// </summary>753 internal SessionStateFunctionEntry(string name, string definition, ScopedItemOptions options,754 SessionStateEntryVisibility visibility, ScriptBlock scriptBlock, string helpFile)755 : base(name, visibility)756 {757 Definition = definition;758 CommandType = CommandTypes.Function;759 Options = options;760 ScriptBlock = scriptBlock;761 HelpFile = helpFile;762 }763 764 internal static SessionStateFunctionEntry GetDelayParsedFunctionEntry(string name, string definition, bool isProductCode, PSLanguageMode languageMode)765 {766 var fnEntry = GetDelayParsedFunctionEntry(name, definition, isProductCode);767 fnEntry.ScriptBlock.LanguageMode = languageMode;768 return fnEntry;769 }770 771 internal static SessionStateFunctionEntry GetDelayParsedFunctionEntry(string name, string definition, bool isProductCode)772 {773 var sb = ScriptBlock.CreateDelayParsedScriptBlock(definition, isProductCode);774 return new SessionStateFunctionEntry(name, definition, ScopedItemOptions.None, SessionStateEntryVisibility.Public, sb, null);775 }776 777 internal static SessionStateFunctionEntry GetDelayParsedFunctionEntry(string name, string definition, ScriptBlock sb)778 {779 return new SessionStateFunctionEntry(name, definition, ScopedItemOptions.None, SessionStateEntryVisibility.Public, sb, null);780 }781 782 /// <summary>783 /// Shallow-clone this object...784 /// </summary>785 /// <returns>The cloned object.</returns>786 public override InitialSessionStateEntry Clone()787 {788 SessionStateFunctionEntry entry = new SessionStateFunctionEntry(Name, Definition, Options, Visibility, ScriptBlock, HelpFile);789 entry.SetModule(this.Module);790 return entry;791 }792 793 /// <summary>794 /// Sets the name of the help file associated with the function.795 /// </summary>796 internal void SetHelpFile(string help)797 {798 HelpFile = help;799 }800 801 /// <summary>802 /// The string to use to define this function...803 /// </summary>804 public string Definition { get; }805 806 /// <summary>807 /// The script block for this function.808 /// </summary>809 internal ScriptBlock ScriptBlock { get; set; }810 811 /// <summary>812 /// Options controlling scope visibility and setability for this entry.813 /// </summary>814 public ScopedItemOptions Options { get; } = ScopedItemOptions.None;815 816 /// <summary>817 /// The name of the help file associated with the function.818 /// </summary>819 public string HelpFile { get; private set; }820 }821 822 /// <summary>823 /// </summary>824 public sealed class SessionStateVariableEntry : ConstrainedSessionStateEntry825 {826 /// <summary>827 /// Is used to define a variable that should be created when828 /// the runspace is opened. Note - if this object is cloned,829 /// then the clone will contain a reference to the original object830 /// not a clone of it.831 /// </summary>832 /// <param name="name">The name of the variable.</param>833 /// <param name="value">The value to set the variable to.</param>834 /// <param name="description">A descriptive string to attach to the variable.</param>835 public SessionStateVariableEntry(string name, object value, string description)836 : base(name, SessionStateEntryVisibility.Public)837 {838 Value = value;839 Description = description;840 }841 842 /// <summary>843 /// Is used to define a variable that should be created when844 /// the runspace is opened. Note - if this object is cloned,845 /// then the clone will contain a reference to the original object846 /// not a clone of it.847 /// </summary>848 /// <param name="name">The name of the variable.</param>849 /// <param name="value">The value to set the variable to.</param>850 /// <param name="description">A descriptive string to attach to the variable.</param>851 /// <param name="options">Options like readonly, constant, allscope, etc.</param>852 public SessionStateVariableEntry(string name, object value, string description, ScopedItemOptions options)853 : base(name, SessionStateEntryVisibility.Public)854 {855 Value = value;856 Description = description;857 Options = options;858 }859 860 /// <summary>861 /// Is used to define a variable that should be created when862 /// the runspace is opened. Note - if this object is cloned,863 /// then the clone will contain a reference to the original object864 /// not a clone of it.865 /// </summary>866 /// <param name="name">The name of the variable.</param>867 /// <param name="value">The value to set the variable to.</param>868 /// <param name="description">A descriptive string to attach to the variable.</param>869 /// <param name="options">Options like readonly, constant, allscope, etc.</param>870 /// <param name="attributes">A list of attributes to attach to the variable.</param>871 public SessionStateVariableEntry(string name, object value, string description, ScopedItemOptions options, Collection<Attribute> attributes)872 : base(name, SessionStateEntryVisibility.Public)873 {874 Value = value;875 Description = description;876 Options = options;877 _attributes = attributes;878 }879 880 /// <summary>881 /// Is used to define a variable that should be created when882 /// the runspace is opened. Note - if this object is cloned,883 /// then the clone will contain a reference to the original object884 /// not a clone of it.885 /// </summary>886 /// <param name="name">The name of the variable.</param>887 /// <param name="value">The value to set the variable to.</param>888 /// <param name="description">A descriptive string to attach to the variable.</param>889 /// <param name="options">Options like readonly, constant, allscope, etc.</param>890 /// <param name="attribute">A single attribute to attach to the variable.</param>891 public SessionStateVariableEntry(string name, object value, string description, ScopedItemOptions options, Attribute attribute)892 : base(name, SessionStateEntryVisibility.Public)893 {894 Value = value;895 Description = description;896 Options = options;897 _attributes = new Collection<Attribute>();898 _attributes.Add(attribute);899 }900 901 /// <summary>902 /// Is used to define a variable that should be created when903 /// the runspace is opened. Note - if this object is cloned,904 /// then the clone will contain a reference to the original object905 /// not a clone of it.906 /// </summary>907 /// <param name="name">The name of the variable.</param>908 /// <param name="value">The value to set the variable to.</param>909 /// <param name="description">A descriptive string to attach to the variable.</param>910 /// <param name="options">Options like readonly, constant, allscope, etc.</param>911 /// <param name="attributes">A single attribute to attach to the variable.</param>912 /// <param name="visibility"></param>913 internal SessionStateVariableEntry(string name, object value, string description, ScopedItemOptions options, Collection<Attribute> attributes, SessionStateEntryVisibility visibility)914 : base(name, visibility)915 {916 Value = value;917 Description = description;918 Options = options;919 _attributes = attributes;920 }921 922 /// <summary>923 /// Shallow-clone this object...924 /// </summary>925 /// <returns>The cloned object.</returns>926 public override InitialSessionStateEntry Clone()927 {928 // Copy the attribute collection if necessary...929 Collection<Attribute> attrs = null;930 if (_attributes != null && _attributes.Count > 0)931 {932 attrs = new Collection<Attribute>(_attributes);933 }934 935 return new SessionStateVariableEntry(Name, Value, Description, Options, attrs, Visibility);936 }937 938 /// <summary>939 /// The value to bind to this variable.940 /// </summary>941 public object Value { get; }942 943 /// <summary>944 /// The description associated with this variable.945 /// </summary>946 public string Description { get; } = string.Empty;947 948 /// <summary>949 /// The options associated with this variable (e.g. readonly, allscope, etc.)950 /// </summary>951 public ScopedItemOptions Options { get; } = ScopedItemOptions.None;952 953 /// <summary>954 /// The attributes that will be attached to this object.955 /// </summary>956 public Collection<Attribute> Attributes957 {958 get { return _attributes ??= new Collection<Attribute>(); }959 }960 961 private Collection<Attribute> _attributes;962 }963 964 /// <summary>965 /// </summary>966 /// <typeparam name="T"></typeparam>967 public sealed class InitialSessionStateEntryCollection<T> : IEnumerable<T> where T : InitialSessionStateEntry968 {969 /// <summary>970 /// Create an empty collection...971 /// </summary>972 public InitialSessionStateEntryCollection()973 {974 _internalCollection = new Collection<T>();975 }976 977 /// <summary>978 /// Create an new collection, copying in the passed items...979 /// </summary>980 /// <param name="items"></param>981 public InitialSessionStateEntryCollection(IEnumerable<T> items)982 {983 ArgumentNullException.ThrowIfNull(items);984 985 _internalCollection = new Collection<T>();986 987 foreach (T item in items)988 {989 _internalCollection.Add(item);990 }991 }992 993 /// <summary>994 /// Clone this collection.995 /// </summary>996 /// <returns>The cloned collection.</returns>997 public InitialSessionStateEntryCollection<T> Clone()998 {999 InitialSessionStateEntryCollection<T> result;1000 lock (_syncObject)1001 {1002 result = new InitialSessionStateEntryCollection<T>();1003 1004 foreach (T item in _internalCollection)1005 {1006 result.Add((T)item.Clone());1007 }1008 }1009 1010 return result;1011 }1012 1013 /// <summary>1014 /// Reset the collection.1015 /// </summary>1016 public void Reset()1017 {1018 lock (_syncObject)1019 {1020 _internalCollection.Clear();1021 }1022 }1023 1024 /// <summary>1025 /// Returns a count of the number of items in the collection...1026 /// </summary>1027 public int Count1028 {1029 get { return _internalCollection.Count; }1030 }1031 1032 /// <summary>1033 /// </summary>1034 /// <param name="index"></param>1035 /// <returns></returns>1036 public T this[int index]1037 {1038 get1039 {1040 T result;1041 lock (_syncObject)1042 {1043 result = _internalCollection[index];1044 }1045 1046 return result;1047 }1048 }1049 1050 /// <summary>1051 /// To find the entries based on name.1052 /// Why collection - Different SnapIn/modules and same entity names.1053 /// If used on command collection entry, then for the same name, one can have multiple output.1054 /// </summary>1055 /// <param name="name"></param>1056 /// <returns></returns>1057 public Collection<T> this[string name]1058 {1059 get1060 {1061 Collection<T> result = new Collection<T>();1062 lock (_syncObject)1063 {1064 foreach (T element in _internalCollection)1065 {1066 if (element.Name.Equals(name, StringComparison.OrdinalIgnoreCase))1067 {1068 result.Add(element);1069 }1070 }1071 }1072 1073 return result;1074 }1075 }1076 1077 /// <summary>1078 /// Find entries based on string name which can include wildcards.1079 /// </summary>1080 /// <param name="name"></param>1081 /// <returns></returns>1082 internal Collection<T> LookUpByName(string name)1083 {1084 if (name == null)1085 {1086 throw new PSArgumentNullException(nameof(name));1087 }1088 1089 Collection<T> result = new Collection<T>();1090 WildcardPattern namePattern = WildcardPattern.Get(name, WildcardOptions.IgnoreCase);1091 lock (_syncObject)1092 {1093 foreach (T element in _internalCollection)1094 {1095 if (namePattern.IsMatch(element.Name))1096 {1097 result.Add(element);1098 }1099 }1100 }1101 1102 return result;1103 }1104 1105 /// <summary>1106 /// </summary>1107 /// <param name="index"></param>1108 public void RemoveItem(int index)1109 {1110 lock (_syncObject)1111 {1112 _internalCollection.RemoveAt(index);1113 }1114 }1115 1116 /// <summary>1117 /// Remove a number of items starting at the specified index.1118 /// </summary>1119 /// <param name="index"></param>1120 /// <param name="count"></param>1121 public void RemoveItem(int index, int count)1122 {1123 lock (_syncObject)1124 {1125 while (count-- > 0)1126 {1127 _internalCollection.RemoveAt(index);1128 }1129 }1130 }1131 1132 /// <summary>1133 /// Clears the collection...1134 /// </summary>1135 public void Clear()1136 {1137 lock (_syncObject)1138 {1139 _internalCollection.Clear();1140 }1141 }1142 1143 /// <summary>1144 /// This overload exists so that we can remove items based on the item name, rather than1145 /// its position in the collection. The type argument can be null but we'll throw an error if1146 /// we can't distinguish between multiple entries of the same name but different types1147 /// and the type hasn't been specified.1148 /// BUGBUG - brucepay - the throw thing is not implemented yet...1149 /// </summary>1150 /// <param name="name">The name of the element to remove.</param>1151 /// <param name="type">The type of object to remove, can be null to remove any type.</param>1152 public void Remove(string name, object type)1153 {1154 ArgumentNullException.ThrowIfNull(name);1155 1156 lock (_syncObject)1157 {1158 Type objType = null;1159 1160 if (type != null)1161 {1162 objType = type as Type ?? type.GetType();1163 }1164 1165 // Work backwards through the collection...1166 for (int i = _internalCollection.Count - 1; i >= 0; i--)1167 {1168 T element = _internalCollection[i];1169 if (element == null)1170 {1171 continue;1172 }1173 1174 if ((objType == null || element.GetType() == objType) &&1175 string.Equals(element.Name, name, StringComparison.OrdinalIgnoreCase))1176 {1177 _internalCollection.RemoveAt(i);1178 }1179 }1180 }1181 }1182 1183 /// <summary>1184 /// Add an item to this collection.1185 /// </summary>1186 /// <param name="item">The item to add...</param>1187 public void Add(T item)1188 {1189 ArgumentNullException.ThrowIfNull(item);1190 1191 lock (_syncObject)1192 {1193 _internalCollection.Add(item);1194 }1195 }1196 1197 /// <summary>1198 /// Add items to this collection.1199 /// </summary>1200 /// <param name="items"></param>