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.Management.Automation.Language;7using System.Text;8 9namespace System.Management.Automation10{11 /// <summary>12 /// The command information for cmdlets that are directly executable by PowerShell.13 /// </summary>14 public class CmdletInfo : CommandInfo15 {16 #region ctor17 18 /// <summary>19 /// Constructs a CmdletInfo object from the raw cmdlet data. This should only20 /// be used for Intrinsic commands.21 /// </summary>22 /// <param name="name">23 /// The name of the cmdlet.24 /// </param>25 /// <param name="implementingType">26 /// The type information about the class that implements the cmdlet.27 /// </param>28 /// <param name="helpFile">29 /// The name of the help file associated with the cmdlet30 /// </param>31 /// <param name="PSSnapin">32 /// The PSSnapInInfo of the PSSnapin the cmdlet comes from.33 /// </param>34 /// <param name="context">35 /// The current engine context.36 /// </param>37 internal CmdletInfo(38 string name,39 Type implementingType,40 string helpFile,41 PSSnapInInfo PSSnapin,42 ExecutionContext context)43 : base(name, CommandTypes.Cmdlet, context)44 {45 if (string.IsNullOrEmpty(name))46 {47 throw PSTraceSource.NewArgumentException(nameof(name));48 }49 50 // Get the verb and noun from the name51 if (!SplitCmdletName(name, out _verb, out _noun))52 {53 throw54 PSTraceSource.NewArgumentException(55 nameof(name),56 DiscoveryExceptions.InvalidCmdletNameFormat,57 name);58 }59 60 _implementingType = implementingType;61 _helpFilePath = helpFile;62 _PSSnapin = PSSnapin;63 _options = ScopedItemOptions.ReadOnly;64 65 // CmdletInfo represents cmdlets exposed from assemblies. On a locked down system, only trusted66 // assemblies will be loaded. Therefore, a CmdletInfo instance will always be trusted.67 this.DefiningLanguageMode = PSLanguageMode.FullLanguage;68 }69 70 /// <summary>71 /// This is a copy constructor, used primarily for get-command.72 /// </summary>73 internal CmdletInfo(CmdletInfo other)74 : base(other)75 {76 _verb = other._verb;77 _noun = other._noun;78 _implementingType = other._implementingType;79 _helpFilePath = other._helpFilePath;80 _PSSnapin = other._PSSnapin;81 _options = ScopedItemOptions.ReadOnly;82 }83 84 /// <summary>85 /// Create a copy of commandInfo for GetCommandCommand so that we can generate parameter86 /// sets based on an argument list (so we can get the dynamic parameters.)87 /// </summary>88 internal override CommandInfo CreateGetCommandCopy(object[] arguments)89 {90 CmdletInfo copy = new CmdletInfo(this);91 copy.IsGetCommandCopy = true;92 copy.Arguments = arguments;93 return copy;94 }95 96 /// <summary>97 /// Directly create a cmdlet object from a type. This allows98 /// unregistered commands to be called. It also allows the overhead of99 /// command discovery to be bypassed.100 /// </summary>101 /// <param name="name">The name to use for the cmdlet, must be in the form Noun-Verb.</param>102 /// <param name="implementingType">The .NET class implementing this cmdlet.</param>103 public CmdletInfo(string name, Type implementingType)104 : base(name, CommandTypes.Cmdlet, null)105 {106 if (string.IsNullOrEmpty(name))107 {108 throw PSTraceSource.NewArgumentNullException(nameof(name));109 }110 111 if (implementingType == null)112 {113 throw PSTraceSource.NewArgumentNullException(nameof(name));114 }115 116 if (!typeof(Cmdlet).IsAssignableFrom(implementingType))117 {118 throw PSTraceSource.NewInvalidOperationException(DiscoveryExceptions.CmdletDoesNotDeriveFromCmdletType, "implementingType", implementingType.FullName);119 }120 121 // Get the verb and noun from the name122 if (!SplitCmdletName(name, out _verb, out _noun))123 {124 throw125 PSTraceSource.NewArgumentException(126 nameof(name),127 DiscoveryExceptions.InvalidCmdletNameFormat,128 name);129 }130 131 _implementingType = implementingType;132 _helpFilePath = string.Empty;133 _PSSnapin = null;134 _options = ScopedItemOptions.ReadOnly;135 }136 137 #endregion ctor138 139 #region public members140 141 /// <summary>142 /// Gets the verb of the cmdlet.143 /// </summary>144 public string Verb145 {146 get147 {148 return _verb;149 }150 }151 152 private readonly string _verb = string.Empty;153 154 /// <summary>155 /// Gets the noun of the cmdlet.156 /// </summary>157 public string Noun158 {159 get160 {161 return _noun;162 }163 }164 165 private readonly string _noun = string.Empty;166 167 internal static bool SplitCmdletName(string name, out string verb, out string noun)168 {169 noun = verb = string.Empty;170 if (string.IsNullOrEmpty(name))171 return false;172 173 int index = 0;174 for (int i = 0; i < name.Length; i++)175 {176 if (CharExtensions.IsDash(name[i]))177 {178 index = i;179 break;180 }181 }182 183 if (index > 0)184 {185 verb = name.Substring(0, index);186 noun = name.Substring(index + 1);187 return true;188 }189 190 return false;191 }192 193 /// <summary>194 /// Gets the help file path for the cmdlet.195 /// </summary>196 public string HelpFile197 {198 get199 {200 return _helpFilePath;201 }202 203 internal set204 {205 _helpFilePath = value;206 }207 }208 209 private string _helpFilePath = string.Empty;210 211 internal override HelpCategory HelpCategory212 {213 get { return HelpCategory.Cmdlet; }214 }215 216 /// <summary>217 /// Gets the Snap-in in which the cmdlet is implemented.218 /// </summary>219 public PSSnapInInfo PSSnapIn220 {221 get222 {223 return _PSSnapin;224 }225 }226 227 private readonly PSSnapInInfo _PSSnapin;228 229 /// <summary>230 /// Gets the name of the PSSnapin the cmdlet is implemented in.231 /// </summary>232 internal string PSSnapInName233 {234 get235 {236 string result = null;237 if (_PSSnapin != null)238 {239 result = _PSSnapin.Name;240 }241 242 return result;243 }244 }245 246 /// <summary>247 /// Gets the source version.248 /// </summary>249 public override Version Version250 {251 get252 {253 if (_version == null)254 {255 if (Module != null)256 {257 _version = base.Version;258 }259 else if (_PSSnapin != null)260 {261 _version = _PSSnapin.Version;262 }263 }264 265 return _version;266 }267 }268 269 private Version _version;270 271 /// <summary>272 /// Gets the type that implements the cmdlet.273 /// </summary>274 public Type ImplementingType275 {276 get277 {278 return _implementingType;279 }280 }281 282 private readonly Type _implementingType = null;283 284 /// <summary>285 /// Gets the synopsis of the cmdlet.286 /// </summary>287 public override string Definition288 {289 get290 {291 StringBuilder synopsis = new StringBuilder();292 293 if (this.ImplementingType != null)294 {295 foreach (CommandParameterSetInfo parameterSet in ParameterSets)296 {297 synopsis.AppendLine();298 synopsis.AppendLine(299 string.Format(300 System.Globalization.CultureInfo.CurrentCulture,301 "{0}{1}{2} {3}",302 _verb,303 StringLiterals.CommandVerbNounSeparator,304 _noun,305 parameterSet.ToString()));306 }307 }308 else309 {310 // Skip the synopsis documentation if the cmdlet hasn't been loaded yet.311 synopsis.AppendLine(312 string.Format(313 System.Globalization.CultureInfo.CurrentCulture,314 "{0}{1}{2}",315 _verb,316 StringLiterals.CommandVerbNounSeparator,317 _noun));318 }319 320 return synopsis.ToString();321 }322 }323 324 /// <summary>325 /// Gets the name of the default parameter set.326 /// </summary>327 public string DefaultParameterSet328 {329 get330 {331 return this.CommandMetadata.DefaultParameterSetName;332 }333 }334 335 /// <summary>336 /// Return the output types specified on the cmdlet.337 /// </summary>338 public override ReadOnlyCollection<PSTypeName> OutputType339 {340 get341 {342 if (_outputType == null)343 {344 _outputType = new List<PSTypeName>();345 346 if (ImplementingType != null)347 {348 foreach (object o in ImplementingType.GetCustomAttributes(typeof(OutputTypeAttribute), false))349 {350 OutputTypeAttribute attr = (OutputTypeAttribute)o;351 _outputType.AddRange(attr.Type);352 }353 }354 }355 356 List<PSTypeName> providerTypes = new List<PSTypeName>();357 358 if (Context != null)359 {360 ProviderInfo provider = null;361 if (Arguments != null)362 {363 // See if we have a path argument - we only consider named arguments -Path and -LiteralPath,364 // and only if they are fully specified (no prefixes allowed, so we don't need to deal with365 // ambiguities that the parameter binder would resolve for us.366 367 for (int i = 0; i < Arguments.Length - 1; i++)368 {369 var arg = Arguments[i] as string;370 if (arg != null &&371 (arg.Equals("-Path", StringComparison.OrdinalIgnoreCase) ||372 (arg.Equals("-LiteralPath", StringComparison.OrdinalIgnoreCase))))373 {374 var path = Arguments[i + 1] as string;375 if (path != null)376 {377 Context.SessionState.Path.GetResolvedProviderPathFromPSPath(path, true, out provider);378 }379 }380 }381 }382 383 // If no path argument, just use the current path to choose the provider.384 provider ??= Context.SessionState.Path.CurrentLocation.Provider;385 386 provider.GetOutputTypes(Name, providerTypes);387 if (providerTypes.Count > 0)388 {389 providerTypes.InsertRange(0, _outputType);390 return new ReadOnlyCollection<PSTypeName>(providerTypes);391 }392 }393 394 return new ReadOnlyCollection<PSTypeName>(_outputType);395 }396 }397 398 private List<PSTypeName> _outputType = null;399 400 /// <summary>401 /// Gets or sets the scope options for the alias.402 /// </summary>403 /// <exception cref="System.Management.Automation.SessionStateUnauthorizedAccessException">404 /// If the trying to set an cmdlet that is constant or405 /// if the value trying to be set is ScopedItemOptions.Constant406 /// </exception>407 public ScopedItemOptions Options408 {409 get410 {411 return _options;412 }413 414 set415 {416 SetOptions(value, false);417 }418 }419 420 private ScopedItemOptions _options = ScopedItemOptions.None;421 422 /// <summary>423 /// Sets the options for the cmdlet and allows changes ReadOnly options only if force is specified.424 /// </summary>425 /// <param name="newOptions">426 /// The new options value.427 /// </param>428 /// <param name="force">429 /// If true the change to the options will happen even if the existing options are read-only.430 /// </param>431 internal void SetOptions(ScopedItemOptions newOptions, bool force)432 {433 // Check to see if the cmdlet is readonly, if so434 // throw an exception because the options cannot be changed.435 436 if ((_options & ScopedItemOptions.ReadOnly) != 0)437 {438 SessionStateUnauthorizedAccessException e =439 new SessionStateUnauthorizedAccessException(440 Name,441 SessionStateCategory.Cmdlet,442 "CmdletIsReadOnly",443 SessionStateStrings.CmdletIsReadOnly);444 445 throw e;446 }447 448 _options = newOptions;449 }450 451 #endregion public members452 453 #region internal/private members454 455 /// <summary>456 /// Gets the full name of the cmdlet including the PSSnapin name.457 /// </summary>458 private static string GetFullName(string moduleName, string cmdletName)459 {460 System.Diagnostics.Debug.Assert(cmdletName != null, "cmdletName != null");461 string result = cmdletName;462 if (!string.IsNullOrEmpty(moduleName))463 {464 result = moduleName + '\\' + result;465 }466 467 return result;468 }469 470 /// <summary>471 /// Gets the full name of the cmdlet including the PSSnapin name.472 /// </summary>473 private static string GetFullName(CmdletInfo cmdletInfo)474 {475 return GetFullName(cmdletInfo.ModuleName, cmdletInfo.Name);476 }477 478 /// <summary>479 /// Gets the full name of the cmdlet including the PSSnapin name.480 /// </summary>481 internal static string GetFullName(PSObject psObject)482 {483 // If this is a high-fidelity object then extract full-name normally.484 if (psObject.BaseObject is CmdletInfo)485 {486 CmdletInfo cmdletInfo = (CmdletInfo)psObject.BaseObject;487 return GetFullName(cmdletInfo);488 }489 490 // Otherwise, it is a PSCustomObject shredded in a remote call: extract name as a property.491 else492 {493 // Handle the case in one or both of the properties might not be defined.494 PSPropertyInfo nameProperty = psObject.Properties["Name"];495 PSPropertyInfo psSnapInProperty = psObject.Properties["PSSnapIn"];496 string nameString = nameProperty == null ? string.Empty : (string)nameProperty.Value;497 string psSnapInString = psSnapInProperty == null ? string.Empty : (string)psSnapInProperty.Value;498 return GetFullName(psSnapInString, nameString);499 }500 }501 502 /// <summary>503 /// Gets the full name of the cmdlet including the PSSnapin name.504 /// </summary>505 internal string FullName506 {507 get508 {509 return GetFullName(this);510 }511 }512 513 /// <summary>514 /// Gets the CommandMetadata for this cmdlet.515 /// </summary>516 /// <exception cref="ArgumentException">517 /// The type name is invalid or the length of the type name518 /// exceeds 1024 characters.519 /// </exception>520 /// <exception cref="System.Security.SecurityException">521 /// The caller does not have the required permission to load the assembly522 /// or create the type.523 /// </exception>524 /// <exception cref="ParsingMetadataException">525 /// If more than int.MaxValue parameter-sets are defined for the command.526 /// </exception>527 /// <exception cref="MetadataException">528 /// If a parameter defines the same parameter-set name multiple times.529 /// If the attributes could not be read from a property or field.530 /// </exception>531 internal override CommandMetadata CommandMetadata532 {533 get534 {535 return _cmdletMetadata ??= CommandMetadata.Get(this.Name, this.ImplementingType, Context);536 }537 }538 539 private CommandMetadata _cmdletMetadata;540 541 internal override bool ImplementsDynamicParameters542 {543 get544 {545 if (ImplementingType != null)546 {547 return (ImplementingType.GetInterface(nameof(IDynamicParameters), true) != null);548 }549 else550 {551 return false;552 }553 }554 }555 556 #endregion internal/private members557 }558}559 