"Fossies" - the Fresh Open Source Software Archive

Member "PowerShell-7.2.6/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddMember.cs" (11 Aug 2022, 21611 Bytes) of package /linux/misc/PowerShell-7.2.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C# source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "AddMember.cs" see the Fossies "Dox" file reference documentation.

    1 // Copyright (c) Microsoft Corporation.
    2 // Licensed under the MIT License.
    3 
    4 using System;
    5 using System.Collections;
    6 using System.Collections.Generic;
    7 using System.Collections.ObjectModel;
    8 using System.Globalization;
    9 using System.Management.Automation;
   10 using System.Management.Automation.Host;
   11 using System.Management.Automation.Internal;
   12 using System.Reflection;
   13 
   14 namespace Microsoft.PowerShell.Commands
   15 {
   16     /// <summary>
   17     /// This class implements get-member command.
   18     /// </summary>
   19     [Cmdlet(VerbsCommon.Add, "Member", DefaultParameterSetName = "TypeNameSet",
   20         HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2097109", RemotingCapability = RemotingCapability.None)]
   21     public class AddMemberCommand : PSCmdlet
   22     {
   23         private static readonly object s_notSpecified = new();
   24 
   25         private static bool HasBeenSpecified(object obj)
   26         {
   27             return !System.Object.ReferenceEquals(obj, s_notSpecified);
   28         }
   29 
   30         private PSObject _inputObject;
   31         /// <summary>
   32         /// The object to add a member to.
   33         /// </summary>
   34         [Parameter(Mandatory = true, ValueFromPipeline = true, ParameterSetName = "MemberSet")]
   35         [Parameter(Mandatory = true, ValueFromPipeline = true, ParameterSetName = "TypeNameSet")]
   36         [Parameter(Mandatory = true, ValueFromPipeline = true, ParameterSetName = NotePropertySingleMemberSet)]
   37         [Parameter(Mandatory = true, ValueFromPipeline = true, ParameterSetName = NotePropertyMultiMemberSet)]
   38         public PSObject InputObject
   39         {
   40             get { return _inputObject; }
   41 
   42             set { _inputObject = value; }
   43         }
   44 
   45         private PSMemberTypes _memberType;
   46         /// <summary>
   47         /// The member type of to be added.
   48         /// </summary>
   49         [Parameter(Mandatory = true, Position = 0, ParameterSetName = "MemberSet")]
   50         [Alias("Type")]
   51         public PSMemberTypes MemberType
   52         {
   53             get { return _memberType; }
   54 
   55             set { _memberType = value; }
   56         }
   57 
   58         private string _memberName;
   59         /// <summary>
   60         /// The name of the new member.
   61         /// </summary>
   62         [Parameter(Mandatory = true, Position = 1, ParameterSetName = "MemberSet")]
   63         public string Name
   64         {
   65             get { return _memberName; }
   66 
   67             set { _memberName = value; }
   68         }
   69 
   70         private object _value1 = s_notSpecified;
   71         /// <summary>
   72         /// First value of the new member. The meaning of this value changes according to the member type.
   73         /// </summary>
   74         [Parameter(Position = 2, ParameterSetName = "MemberSet")]
   75         public object Value
   76         {
   77             get { return _value1; }
   78 
   79             set { _value1 = value; }
   80         }
   81 
   82         private object _value2 = s_notSpecified;
   83         /// <summary>
   84         /// Second value of the new member. The meaning of this value changes according to the member type.
   85         /// </summary>
   86         [Parameter(Position = 3, ParameterSetName = "MemberSet")]
   87         public object SecondValue
   88         {
   89             get { return _value2; }
   90 
   91             set { _value2 = value; }
   92         }
   93 
   94         private string _typeName;
   95         /// <summary>
   96         /// Add new type name to the specified object for TypeNameSet.
   97         /// </summary>
   98         [Parameter(Mandatory = true, ParameterSetName = "TypeNameSet")]
   99         [Parameter(ParameterSetName = "MemberSet")]
  100         [Parameter(ParameterSetName = NotePropertySingleMemberSet)]
  101         [Parameter(ParameterSetName = NotePropertyMultiMemberSet)]
  102         [ValidateNotNullOrEmpty]
  103         public string TypeName
  104         {
  105             get { return _typeName; }
  106 
  107             set { _typeName = value; }
  108         }
  109 
  110         private bool _force;
  111         /// <summary>
  112         /// True if we should overwrite a possibly existing member.
  113         /// </summary>
  114         [Parameter(ParameterSetName = "MemberSet")]
  115         [Parameter(ParameterSetName = NotePropertySingleMemberSet)]
  116         [Parameter(ParameterSetName = NotePropertyMultiMemberSet)]
  117         public SwitchParameter Force
  118         {
  119             get { return _force; }
  120 
  121             set { _force = value; }
  122         }
  123 
  124         private bool _passThru /* = false */;
  125 
  126         /// <summary>
  127         /// Gets or sets the parameter -passThru which states output from the command should be placed in the pipeline.
  128         /// </summary>
  129         [Parameter(ParameterSetName = "MemberSet")]
  130         [Parameter(ParameterSetName = "TypeNameSet")]
  131         [Parameter(ParameterSetName = NotePropertySingleMemberSet)]
  132         [Parameter(ParameterSetName = NotePropertyMultiMemberSet)]
  133         public SwitchParameter PassThru
  134         {
  135             get { return _passThru; }
  136 
  137             set { _passThru = value; }
  138         }
  139 
  140         #region Simplifying NoteProperty Declaration
  141 
  142         private const string NotePropertySingleMemberSet = "NotePropertySingleMemberSet";
  143         private const string NotePropertyMultiMemberSet = "NotePropertyMultiMemberSet";
  144 
  145         private string _notePropertyName;
  146         /// <summary>
  147         /// The name of the new NoteProperty member.
  148         /// </summary>
  149         [Parameter(Mandatory = true, Position = 0, ParameterSetName = NotePropertySingleMemberSet)]
  150         [ValidateNotePropertyNameAttribute()]
  151         [NotePropertyTransformationAttribute()]
  152         [ValidateNotNullOrEmpty]
  153         public string NotePropertyName
  154         {
  155             get { return _notePropertyName; }
  156 
  157             set { _notePropertyName = value; }
  158         }
  159 
  160         private object _notePropertyValue;
  161         /// <summary>
  162         /// The value of the new NoteProperty member.
  163         /// </summary>
  164         [Parameter(Mandatory = true, Position = 1, ParameterSetName = NotePropertySingleMemberSet)]
  165         [AllowNull]
  166         public object NotePropertyValue
  167         {
  168             get { return _notePropertyValue; }
  169 
  170             set { _notePropertyValue = value; }
  171         }
  172 
  173         // Use IDictionary to support both Hashtable and OrderedHashtable
  174         private IDictionary _property;
  175 
  176         /// <summary>
  177         /// The NoteProperty members to be set.
  178         /// </summary>
  179         [Parameter(Mandatory = true, Position = 0, ParameterSetName = NotePropertyMultiMemberSet)]
  180         [ValidateNotNullOrEmpty]
  181         public IDictionary NotePropertyMembers
  182         {
  183             get { return _property; }
  184 
  185             set { _property = value; }
  186         }
  187 
  188         #endregion Simplifying NoteProperty Declaration
  189 
  190         private static object GetParameterType(object sourceValue, Type destinationType)
  191         {
  192             return LanguagePrimitives.ConvertTo(sourceValue, destinationType, CultureInfo.InvariantCulture);
  193         }
  194 
  195         private void EnsureValue1AndValue2AreNotBothNull()
  196         {
  197             if (_value1 == null &&
  198                (_value2 == null || !HasBeenSpecified(_value2)))
  199             {
  200                 ThrowTerminatingError(NewError("Value1AndValue2AreNotBothNull", "Value1AndValue2AreNotBothNull", null, _memberType));
  201             }
  202         }
  203 
  204         private void EnsureValue1IsNotNull()
  205         {
  206             if (_value1 == null)
  207             {
  208                 ThrowTerminatingError(NewError("Value1ShouldNotBeNull", "Value1ShouldNotBeNull", null, _memberType));
  209             }
  210         }
  211 
  212         private void EnsureValue2IsNotNull()
  213         {
  214             if (_value2 == null)
  215             {
  216                 ThrowTerminatingError(NewError("Value2ShouldNotBeNull", "Value2ShouldNotBeNull", null, _memberType));
  217             }
  218         }
  219 
  220         private void EnsureValue1HasBeenSpecified()
  221         {
  222             if (!HasBeenSpecified(_value1))
  223             {
  224                 Collection<FieldDescription> fdc = new();
  225                 fdc.Add(new FieldDescription("Value"));
  226                 string prompt = StringUtil.Format(AddMember.Value1Prompt, _memberType);
  227                 Dictionary<string, PSObject> result = this.Host.UI.Prompt(prompt, null, fdc);
  228                 if (result != null)
  229                 {
  230                     _value1 = result["Value"].BaseObject;
  231                 }
  232             }
  233         }
  234 
  235         private void EnsureValue2HasNotBeenSpecified()
  236         {
  237             if (HasBeenSpecified(_value2))
  238             {
  239                 ThrowTerminatingError(NewError("Value2ShouldNotBeSpecified", "Value2ShouldNotBeSpecified", null, _memberType));
  240             }
  241         }
  242 
  243         private PSMemberInfo GetAliasProperty()
  244         {
  245             EnsureValue1HasBeenSpecified();
  246             EnsureValue1IsNotNull();
  247 
  248             string value1Str = (string)GetParameterType(_value1, typeof(string));
  249             if (HasBeenSpecified(_value2))
  250             {
  251                 EnsureValue2IsNotNull();
  252                 Type value2Type = (Type)GetParameterType(_value2, typeof(Type));
  253                 return new PSAliasProperty(_memberName, value1Str, value2Type);
  254             }
  255 
  256             return new PSAliasProperty(_memberName, value1Str);
  257         }
  258 
  259         private PSMemberInfo GetCodeMethod()
  260         {
  261             EnsureValue1HasBeenSpecified();
  262             EnsureValue1IsNotNull();
  263             EnsureValue2HasNotBeenSpecified();
  264             MethodInfo value1MethodInfo = (MethodInfo)GetParameterType(_value1, typeof(MethodInfo));
  265             return new PSCodeMethod(_memberName, value1MethodInfo);
  266         }
  267 
  268         private PSMemberInfo GetCodeProperty()
  269         {
  270             EnsureValue1HasBeenSpecified();
  271             EnsureValue1AndValue2AreNotBothNull();
  272 
  273             MethodInfo value1MethodInfo = null;
  274             if (HasBeenSpecified(_value1))
  275             {
  276                 value1MethodInfo = (MethodInfo)GetParameterType(_value1, typeof(MethodInfo));
  277             }
  278 
  279             MethodInfo value2MethodInfo = null;
  280             if (HasBeenSpecified(_value2))
  281             {
  282                 value2MethodInfo = (MethodInfo)GetParameterType(_value2, typeof(MethodInfo));
  283             }
  284 
  285             return new PSCodeProperty(_memberName, value1MethodInfo, value2MethodInfo);
  286         }
  287 
  288         private PSMemberInfo GetMemberSet()
  289         {
  290             EnsureValue2HasNotBeenSpecified();
  291             if (_value1 == null || !HasBeenSpecified(_value1))
  292             {
  293                 return new PSMemberSet(_memberName);
  294             }
  295 
  296             Collection<PSMemberInfo> value1Collection =
  297                 (Collection<PSMemberInfo>)GetParameterType(_value1, typeof(Collection<PSMemberInfo>));
  298             return new PSMemberSet(_memberName, value1Collection);
  299         }
  300 
  301         private PSMemberInfo GetNoteProperty()
  302         {
  303             EnsureValue1HasBeenSpecified();
  304             EnsureValue2HasNotBeenSpecified();
  305             return new PSNoteProperty(_memberName, _value1);
  306         }
  307 
  308         private PSMemberInfo GetPropertySet()
  309         {
  310             EnsureValue2HasNotBeenSpecified();
  311             EnsureValue1HasBeenSpecified();
  312             EnsureValue1IsNotNull();
  313             Collection<string> value1Collection =
  314                 (Collection<string>)GetParameterType(_value1, typeof(Collection<string>));
  315             return new PSPropertySet(_memberName, value1Collection);
  316         }
  317 
  318         private PSMemberInfo GetScriptMethod()
  319         {
  320             EnsureValue2HasNotBeenSpecified();
  321             EnsureValue1HasBeenSpecified();
  322             EnsureValue1IsNotNull();
  323             ScriptBlock value1ScriptBlock = (ScriptBlock)GetParameterType(_value1, typeof(ScriptBlock));
  324             return new PSScriptMethod(_memberName, value1ScriptBlock);
  325         }
  326 
  327         private PSMemberInfo GetScriptProperty()
  328         {
  329             EnsureValue1HasBeenSpecified();
  330             EnsureValue1AndValue2AreNotBothNull();
  331 
  332             ScriptBlock value1ScriptBlock = null;
  333             if (HasBeenSpecified(_value1))
  334             {
  335                 value1ScriptBlock = (ScriptBlock)GetParameterType(_value1, typeof(ScriptBlock));
  336             }
  337 
  338             ScriptBlock value2ScriptBlock = null;
  339             if (HasBeenSpecified(_value2))
  340             {
  341                 value2ScriptBlock = (ScriptBlock)GetParameterType(_value2, typeof(ScriptBlock));
  342             }
  343 
  344             return new PSScriptProperty(_memberName, value1ScriptBlock, value2ScriptBlock);
  345         }
  346 
  347         /// <summary>
  348         /// This method implements the ProcessRecord method for add-member command.
  349         /// </summary>
  350         protected override void ProcessRecord()
  351         {
  352             if (_typeName != null && string.IsNullOrWhiteSpace(_typeName))
  353             {
  354                 ThrowTerminatingError(NewError("TypeNameShouldNotBeEmpty", "TypeNameShouldNotBeEmpty", _typeName));
  355             }
  356 
  357             if (ParameterSetName == "TypeNameSet")
  358             {
  359                 UpdateTypeNames();
  360 
  361                 if (_passThru)
  362                 {
  363                     WriteObject(_inputObject);
  364                 }
  365 
  366                 return;
  367             }
  368 
  369             if (ParameterSetName == NotePropertyMultiMemberSet)
  370             {
  371                 ProcessNotePropertyMultiMemberSet();
  372                 return;
  373             }
  374 
  375             PSMemberInfo member = null;
  376             if (ParameterSetName == NotePropertySingleMemberSet)
  377             {
  378                 member = new PSNoteProperty(_notePropertyName, _notePropertyValue);
  379             }
  380             else
  381             {
  382                 int memberCountHelper = (int)_memberType;
  383                 int memberCount = 0;
  384                 while (memberCountHelper != 0)
  385                 {
  386                     if ((memberCountHelper & 1) != 0)
  387                     {
  388                         memberCount++;
  389                     }
  390 
  391                     memberCountHelper >>= 1;
  392                 }
  393 
  394                 if (memberCount != 1)
  395                 {
  396                     ThrowTerminatingError(NewError("WrongMemberCount", "WrongMemberCount", null, _memberType.ToString()));
  397                     return;
  398                 }
  399 
  400                 switch (_memberType)
  401                 {
  402                     case PSMemberTypes.AliasProperty:
  403                         member = GetAliasProperty();
  404                         break;
  405                     case PSMemberTypes.CodeMethod:
  406                         member = GetCodeMethod();
  407                         break;
  408                     case PSMemberTypes.CodeProperty:
  409                         member = GetCodeProperty();
  410                         break;
  411                     case PSMemberTypes.MemberSet:
  412                         member = GetMemberSet();
  413                         break;
  414                     case PSMemberTypes.NoteProperty:
  415                         member = GetNoteProperty();
  416                         break;
  417                     case PSMemberTypes.PropertySet:
  418                         member = GetPropertySet();
  419                         break;
  420                     case PSMemberTypes.ScriptMethod:
  421                         member = GetScriptMethod();
  422                         break;
  423                     case PSMemberTypes.ScriptProperty:
  424                         member = GetScriptProperty();
  425                         break;
  426                     default:
  427                         ThrowTerminatingError(NewError("CannotAddMemberType", "CannotAddMemberType", null, _memberType.ToString()));
  428                         break;
  429                 }
  430             }
  431 
  432             if (member == null)
  433             {
  434                 return;
  435             }
  436 
  437             if (!AddMemberToTarget(member))
  438                 return;
  439 
  440             if (_typeName != null)
  441             {
  442                 UpdateTypeNames();
  443             }
  444 
  445             if (_passThru)
  446             {
  447                 WriteObject(_inputObject);
  448             }
  449         }
  450 
  451         /// <summary>
  452         /// Add the member to the target object.
  453         /// </summary>
  454         /// <param name="member"></param>
  455         /// <returns></returns>
  456         private bool AddMemberToTarget(PSMemberInfo member)
  457         {
  458             PSMemberInfo previousMember = _inputObject.Members[member.Name];
  459             if (previousMember != null)
  460             {
  461                 if (!_force)
  462                 {
  463                     WriteError(NewError("MemberAlreadyExists",
  464                         "MemberAlreadyExists",
  465                         _inputObject, member.Name));
  466                     return false;
  467                 }
  468                 else
  469                 {
  470                     if (previousMember.IsInstance)
  471                     {
  472                         _inputObject.Members.Remove(member.Name);
  473                     }
  474                     else
  475                     {
  476                         WriteError(NewError("CannotRemoveTypeDataMember",
  477                             "CannotRemoveTypeDataMember",
  478                             _inputObject, member.Name, previousMember.MemberType));
  479                         return false;
  480                     }
  481                 }
  482             }
  483 
  484             _inputObject.Members.Add(member);
  485             return true;
  486         }
  487 
  488         /// <summary>
  489         /// Process the 'NotePropertyMultiMemberSet' parameter set.
  490         /// </summary>
  491         private void ProcessNotePropertyMultiMemberSet()
  492         {
  493             bool result = false;
  494             foreach (DictionaryEntry prop in _property)
  495             {
  496                 string noteName = PSObject.ToStringParser(this.Context, prop.Key);
  497                 object noteValue = prop.Value;
  498 
  499                 if (string.IsNullOrEmpty(noteName))
  500                 {
  501                     WriteError(NewError("NotePropertyNameShouldNotBeNull",
  502                         "NotePropertyNameShouldNotBeNull", noteName));
  503                     continue;
  504                 }
  505 
  506                 PSMemberInfo member = new PSNoteProperty(noteName, noteValue);
  507                 if (AddMemberToTarget(member) && !result)
  508                     result = true;
  509             }
  510 
  511             if (result && _typeName != null)
  512             {
  513                 UpdateTypeNames();
  514             }
  515 
  516             if (result && _passThru)
  517             {
  518                 WriteObject(_inputObject);
  519             }
  520         }
  521 
  522         private void UpdateTypeNames()
  523         {
  524             // Respect the type shortcut
  525             Type type;
  526             string typeNameInUse = _typeName;
  527             if (LanguagePrimitives.TryConvertTo(_typeName, out type)) { typeNameInUse = type.FullName; }
  528 
  529             _inputObject.TypeNames.Insert(0, typeNameInUse);
  530         }
  531 
  532         private ErrorRecord NewError(string errorId, string resourceId, object targetObject, params object[] args)
  533         {
  534             ErrorDetails details = new(this.GetType().GetTypeInfo().Assembly,
  535                 "Microsoft.PowerShell.Commands.Utility.resources.AddMember", resourceId, args);
  536             ErrorRecord errorRecord = new(
  537                 new InvalidOperationException(details.Message),
  538                 errorId,
  539                 ErrorCategory.InvalidOperation,
  540                 targetObject);
  541             return errorRecord;
  542         }
  543 
  544         /// <summary>
  545         /// This ValidateArgumentsAttribute is used to guarantee the argument to be bound to
  546         /// -NotePropertyName parameter cannot be converted to the enum type PSMemberTypes.
  547         /// So when given a string or a number that can be converted, we make sure it gets
  548         /// bound to -MemberType, instead of -NotePropertyName.
  549         /// </summary>
  550         /// <remarks>
  551         /// This exception will be hidden in the positional binding phase. So we make sure
  552         /// if the argument can be converted to PSMemberTypes, it gets bound to the -MemberType
  553         /// parameter. We are sure that when this exception is thrown, the current positional
  554         /// argument can be successfully bound to.
  555         /// </remarks>
  556         private sealed class ValidateNotePropertyNameAttribute : ValidateArgumentsAttribute
  557         {
  558             protected override void Validate(object arguments, EngineIntrinsics engineIntrinsics)
  559             {
  560                 string notePropertyName = arguments as string;
  561                 PSMemberTypes memberType;
  562                 if (notePropertyName != null && LanguagePrimitives.TryConvertTo<PSMemberTypes>(notePropertyName, out memberType))
  563                 {
  564                     switch (memberType)
  565                     {
  566                         case PSMemberTypes.AliasProperty:
  567                         case PSMemberTypes.CodeMethod:
  568                         case PSMemberTypes.CodeProperty:
  569                         case PSMemberTypes.MemberSet:
  570                         case PSMemberTypes.NoteProperty:
  571                         case PSMemberTypes.PropertySet:
  572                         case PSMemberTypes.ScriptMethod:
  573                         case PSMemberTypes.ScriptProperty:
  574                             string errMsg = StringUtil.Format(AddMember.InvalidValueForNotePropertyName, typeof(PSMemberTypes).FullName);
  575                             throw new ValidationMetadataException(errMsg, true);
  576                         default:
  577                             break;
  578                     }
  579                 }
  580             }
  581         }
  582 
  583         /// <summary>
  584         /// Transform the integer arguments to strings for the parameter NotePropertyName.
  585         /// </summary>
  586         internal sealed class NotePropertyTransformationAttribute : ArgumentTransformationAttribute
  587         {
  588             public override object Transform(EngineIntrinsics engineIntrinsics, object inputData)
  589             {
  590                 object target = PSObject.Base(inputData);
  591                 if (target != null && target.GetType().IsNumeric())
  592                 {
  593                     var result = LanguagePrimitives.ConvertTo<string>(target);
  594                     return result;
  595                 }
  596 
  597                 return inputData;
  598             }
  599         }
  600     }
  601 }