/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System.Linq;
using System.Management.Automation.Language;
using System.Reflection;
using System.Globalization;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections;
using System.ComponentModel;
using System.Text;
using System.Management.Automation.Internal;
using Microsoft.PowerShell;
using TypeTable = System.Management.Automation.Runspaces.TypeTable;
#pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings
#pragma warning disable 56503
namespace System.Management.Automation
{
#region PSMemberInfo
///
/// Enumerates all possible types of members
///
[TypeConverterAttribute(typeof(LanguagePrimitives.EnumMultipleTypeConverter))]
[FlagsAttribute()]
public enum PSMemberTypes
{
///
/// An alias to another member
///
AliasProperty = 1,
///
/// A property defined as a reference to a method
///
CodeProperty = 2,
///
/// A property from the BaseObject
///
Property = 4,
///
/// A prorperty defined by a Name-Value pair
///
NoteProperty = 8,
///
/// A property defined by script language
///
ScriptProperty = 16,
///
/// A set of properties
///
PropertySet = 32,
///
/// A method from the BaseObject
///
Method = 64,
///
/// A method defined as a reference to another method
///
CodeMethod = 128,
///
/// A method defined as a script
///
ScriptMethod = 256,
///
/// A member that acts like a Property that takes parameters. This is not consider to be a property or a method.
///
ParameterizedProperty = 512,
///
/// A set of members
///
MemberSet = 1024,
///
/// All events
///
Event = 2048,
///
/// All dynamic members (where PowerShell cannot know the type of the member)
///
Dynamic = 4096,
///
/// All property member types
///
Properties = AliasProperty | CodeProperty | Property | NoteProperty | ScriptProperty,
///
/// All method member types
///
Methods = CodeMethod | Method | ScriptMethod,
///
/// All member types
///
All = Properties | Methods | Event | PropertySet | MemberSet | ParameterizedProperty | Dynamic
}
///
/// Enumerator for all possible views available on a PSObject.
///
[TypeConverterAttribute(typeof(LanguagePrimitives.EnumMultipleTypeConverter))]
[FlagsAttribute()]
public enum PSMemberViewTypes
{
///
/// Extended methods / properties
///
Extended = 1,
///
/// Adapted methods / properties
///
Adapted = 2,
///
/// Base methods / properties
///
Base = 4,
///
/// All methods / properties
///
All = Extended | Adapted | Base
}
///
/// Match options
///
[FlagsAttribute]
internal enum MshMemberMatchOptions
{
///
/// No options
///
None = 0,
///
/// Hidden members should be displayed
///
IncludeHidden = 1,
///
/// Only include members with property set to true
///
OnlySerializable = 2
}
///
/// Serves as the base class for all members of an PSObject
///
public abstract class PSMemberInfo
{
internal object instance;
internal string name;
internal bool ShouldSerialize { get; set; }
internal virtual void ReplicateInstance(object particularInstance)
{
this.instance = particularInstance;
}
internal void SetValueNoConversion(object setValue)
{
PSProperty thisAsProperty = this as PSProperty;
if (thisAsProperty == null)
{
this.Value = setValue;
return;
}
thisAsProperty.SetAdaptedValue(setValue, false);
}
///
/// Initializes a new instance of an PSMemberInfo derived class
///
protected PSMemberInfo()
{
ShouldSerialize = true;
IsInstance = true;
}
internal void CloneBaseProperties(PSMemberInfo destiny)
{
destiny.name = name;
destiny.IsHidden = IsHidden;
destiny.IsReservedMember = IsReservedMember;
destiny.IsInstance = IsInstance;
destiny.instance = instance;
destiny.ShouldSerialize = ShouldSerialize;
}
///
/// Gets the member type
///
public abstract PSMemberTypes MemberType { get; }
///
/// Gets the member name
///
public string Name
{
get
{
return this.name;
}
}
///
/// Allows a derived class to set the member name...
///
///
protected void SetMemberName(string name)
{
if (string.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
}
///
/// True if this is one of the reserved members
///
internal bool IsReservedMember { get; set; }
///
/// True if the member should be hidden when searching with PSMemberInfoInternalCollection's Match
/// or enumerating a collection.
/// This should not be settable as it would make the count of hidden properties in
/// PSMemberInfoInternalCollection invalid.
/// For now, we are carefully setting this.isHidden before adding
/// the members toPSObjectMembersetCollection. In the future, we might need overload for all
/// PSMemberInfo constructors to take isHidden.
///
internal bool IsHidden { get; set; }
///
/// True if this member has been added to the instance as opposed to
/// coming from the adapter or from type data
///
public bool IsInstance { get; internal set; }
///
/// Gets and Sets the value of this member
///
/// When getting the value of a property throws an exception.
/// This exception is also thrown if the property is an and there
/// is no Runspace to run the script.
/// When setting the value of a property throws an exception.
/// This exception is also thrown if the property is an and there
/// is no Runspace to run the script.
/// When some problem other then getting/setting the value happened
public abstract object Value { get; set; }
///
/// Gets the type of the value for this member
///
/// When there was a problem getting the property
public abstract string TypeNameOfValue { get; }
///
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
///
/// a new PSMemberInfo that is a copy of this PSMemberInfo
public abstract PSMemberInfo Copy();
internal bool MatchesOptions(MshMemberMatchOptions options)
{
if (this.IsHidden && (0 == (options & MshMemberMatchOptions.IncludeHidden)))
{
return false;
}
if (!this.ShouldSerialize && (0 != (options & MshMemberMatchOptions.OnlySerializable)))
{
return false;
}
return true;
}
}
///
/// Serves as a base class for all members that behave like properties.
///
public abstract class PSPropertyInfo : PSMemberInfo
{
///
/// Initializes a new instance of an PSPropertyInfo derived class
///
protected PSPropertyInfo() { }
///
/// Gets true if this property can be set
///
public abstract bool IsSettable { get; }
///
/// Gets true if this property can be read
///
public abstract bool IsGettable { get; }
internal Exception NewSetValueException(Exception e, string errorId)
{
return new SetValueInvocationException(errorId,
e,
ExtendedTypeSystem.ExceptionWhenSetting,
this.Name, e.Message);
}
internal Exception NewGetValueException(Exception e, string errorId)
{
return new GetValueInvocationException(errorId,
e,
ExtendedTypeSystem.ExceptionWhenGetting,
this.Name, e.Message);
}
}
///
/// Serves as an alias to another member
///
///
/// It is permitted to subclass
/// but there is no established scenario for doing this, nor has it been tested.
///
public class PSAliasProperty : PSPropertyInfo
{
///
/// Returns the string representation of this property
///
/// This property as a string
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(this.Name);
returnValue.Append(" = ");
if (ConversionType != null)
{
returnValue.Append("(");
returnValue.Append(ConversionType);
returnValue.Append(")");
}
returnValue.Append(ReferencedMemberName);
return returnValue.ToString();
}
///
/// Initializes a new instance of PSAliasProperty setting the name of the alias
/// and the name of the member this alias refers to.
///
/// name of the alias
/// name of the member this alias refers to
/// for invalid arguments
public PSAliasProperty(string name, string referencedMemberName)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (String.IsNullOrEmpty(referencedMemberName))
{
throw PSTraceSource.NewArgumentException("referencedMemberName");
}
ReferencedMemberName = referencedMemberName;
}
///
/// Initializes a new instance of PSAliasProperty setting the name of the alias,
/// the name of the member this alias refers to and the type to convert the referenced
/// member's value.
///
/// name of the alias
/// name of the member this alias refers to
/// the type to convert the referenced member's value
/// for invalid arguments
public PSAliasProperty(string name, string referencedMemberName, Type conversionType)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (String.IsNullOrEmpty(referencedMemberName))
{
throw PSTraceSource.NewArgumentException("referencedMemberName");
}
ReferencedMemberName = referencedMemberName;
// conversionType is optional and can be null
ConversionType = conversionType;
}
///
/// Gets the name of the member this alias refers to
///
public string ReferencedMemberName { get; }
///
/// Gets the member this alias refers to
///
internal PSMemberInfo ReferencedMember
{
get
{
return this.LookupMember(ReferencedMemberName);
}
}
///
/// Gets the the type to convert the referenced member's value. It might be
/// null when no conversion is done.
///
public Type ConversionType { get; private set; }
#region virtual implementation
///
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
///
/// a new PSMemberInfo that is a copy of this PSMemberInfo
public override PSMemberInfo Copy()
{
PSAliasProperty alias = new PSAliasProperty(name, ReferencedMemberName);
alias.ConversionType = ConversionType;
CloneBaseProperties(alias);
return alias;
}
///
/// Gets the member type
///
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.AliasProperty;
}
}
///
/// Gets the type of the value for this member
///
///
/// When
/// the alias has not been added to an PSObject or
/// the alias has a cycle or
/// an aliased member is not present
///
public override string TypeNameOfValue
{
get
{
if (ConversionType != null)
{
return ConversionType.FullName;
}
return this.ReferencedMember.TypeNameOfValue;
}
}
///
/// Gets true if this property can be set
///
///
/// When
/// the alias has not been added to an PSObject or
/// the alias has a cycle or
/// an aliased member is not presen
///
public override bool IsSettable
{
get
{
PSPropertyInfo memberProperty = this.ReferencedMember as PSPropertyInfo;
if (memberProperty != null)
{
return memberProperty.IsSettable;
}
return false;
}
}
///
/// Gets true if this property can be read
///
///
/// When
/// the alias has not been added to an PSObject or
/// the alias has a cycle or
/// an aliased member is not present
///
public override bool IsGettable
{
get
{
PSPropertyInfo memberProperty = this.ReferencedMember as PSPropertyInfo;
if (memberProperty != null)
{
return memberProperty.IsGettable;
}
return false;
}
}
private PSMemberInfo LookupMember(string name)
{
bool hasCycle;
PSMemberInfo returnValue;
LookupMember(name, new HashSet(StringComparer.OrdinalIgnoreCase), out returnValue, out hasCycle);
if (hasCycle)
{
throw new
ExtendedTypeSystemException(
"CycleInAliasLookup",
null,
ExtendedTypeSystem.CycleInAlias,
this.Name);
}
return returnValue;
}
private void LookupMember(string name, HashSet visitedAliases, out PSMemberInfo returnedMember, out bool hasCycle)
{
returnedMember = null;
if (this.instance == null)
{
throw new ExtendedTypeSystemException("AliasLookupMemberOutsidePSObject",
null,
ExtendedTypeSystem.AccessMemberOutsidePSObject,
name);
}
PSMemberInfo member = PSObject.AsPSObject(this.instance).Properties[name];
if (member == null)
{
throw new ExtendedTypeSystemException(
"AliasLookupMemberNotPresent",
null,
ExtendedTypeSystem.MemberNotPresent,
name);
}
PSAliasProperty aliasMember = member as PSAliasProperty;
if (aliasMember == null)
{
hasCycle = false;
returnedMember = member;
return;
}
if (visitedAliases.Contains(name))
{
hasCycle = true;
return;
}
visitedAliases.Add(name);
LookupMember(aliasMember.ReferencedMemberName, visitedAliases, out returnedMember, out hasCycle);
}
///
/// Gets and Sets the value of this member
///
///
/// When
/// the alias has not been added to an PSObject or
/// the alias has a cycle or
/// an aliased member is not present
///
/// When getting the value of a property throws an exception
/// When setting the value of a property throws an exception
public override object Value
{
get
{
object returnValue = this.ReferencedMember.Value;
if (ConversionType != null)
{
returnValue = LanguagePrimitives.ConvertTo(returnValue, ConversionType, CultureInfo.InvariantCulture);
}
return returnValue;
}
set
{
this.ReferencedMember.Value = value;
}
}
#endregion virtual implementation
}
///
/// Serves as a property implemented with references to methods for getter and setter.
///
///
/// It is permitted to subclass
/// but there is no established scenario for doing this, nor has it been tested.
///
public class PSCodeProperty : PSPropertyInfo
{
///
/// Returns the string representation of this property
///
/// This property as a string
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(this.TypeNameOfValue);
returnValue.Append(" ");
returnValue.Append(this.Name);
returnValue.Append("{");
if (this.IsGettable)
{
returnValue.Append("get=");
returnValue.Append(GetterCodeReference.Name);
returnValue.Append(";");
}
if (this.IsSettable)
{
returnValue.Append("set=");
returnValue.Append(SetterCodeReference.Name);
returnValue.Append(";");
}
returnValue.Append("}");
return returnValue.ToString();
}
///
/// Called from TypeTableUpdate before SetSetterFromTypeTable is called
///
internal void SetGetterFromTypeTable(Type type, string methodName)
{
MethodInfo methodAsMember = null;
try
{
methodAsMember = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase);
}
catch (AmbiguousMatchException)
{
// Ignore the AmbiguousMatchException.
// We will generate error below if we cannot find exactly one match method.
}
if (methodAsMember == null)
{
throw new ExtendedTypeSystemException(
"GetterFormatFromTypeTable",
null,
ExtendedTypeSystem.CodePropertyGetterFormat);
}
SetGetter(methodAsMember);
}
///
/// Called from TypeTableUpdate after SetGetterFromTypeTable is called
///
internal void SetSetterFromTypeTable(Type type, string methodName)
{
MethodInfo methodAsMember = null;
try
{
methodAsMember = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase);
}
catch (AmbiguousMatchException)
{
// Ignore the AmbiguousMatchException.
// We will generate error below if we cannot find exactly one match method.
}
if (methodAsMember == null)
{
throw new ExtendedTypeSystemException(
"SetterFormatFromTypeTable",
null,
ExtendedTypeSystem.CodePropertySetterFormat);
}
SetSetter(methodAsMember, GetterCodeReference);
}
///
/// Used from TypeTable with the internal constructor
///
internal void SetGetter(MethodInfo methodForGet)
{
if (methodForGet == null)
{
GetterCodeReference = null;
return;
}
if (!CheckGetterMethodInfo(methodForGet))
{
throw new ExtendedTypeSystemException(
"GetterFormat",
null,
ExtendedTypeSystem.CodePropertyGetterFormat);
}
GetterCodeReference = methodForGet;
}
internal static bool CheckGetterMethodInfo(MethodInfo methodForGet)
{
ParameterInfo[] parameters = methodForGet.GetParameters();
return methodForGet.IsPublic
&& methodForGet.IsStatic
&& methodForGet.ReturnType != typeof(void)
&& parameters.Length == 1
&& parameters[0].ParameterType == typeof(PSObject);
}
///
/// Used from TypeTable with the internal constructor
///
private void SetSetter(MethodInfo methodForSet, MethodInfo methodForGet)
{
if (methodForSet == null)
{
if (methodForGet == null)
{
throw new ExtendedTypeSystemException(
"SetterAndGetterNullFormat",
null,
ExtendedTypeSystem.CodePropertyGetterAndSetterNull);
}
SetterCodeReference = null;
return;
}
if (!CheckSetterMethodInfo(methodForSet, methodForGet))
{
throw new ExtendedTypeSystemException(
"SetterFormat",
null,
ExtendedTypeSystem.CodePropertySetterFormat);
}
SetterCodeReference = methodForSet;
}
internal static bool CheckSetterMethodInfo(MethodInfo methodForSet, MethodInfo methodForGet)
{
ParameterInfo[] parameters = methodForSet.GetParameters();
return methodForSet.IsPublic
&& methodForSet.IsStatic
&& methodForSet.ReturnType == typeof(void)
&& parameters.Length == 2
&& parameters[0].ParameterType == typeof(PSObject)
&& (methodForGet == null || methodForGet.ReturnType == parameters[1].ParameterType);
}
///
/// Used from TypeTable to delay setting getter and setter
///
internal PSCodeProperty(string name)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
}
///
/// Initializes a new instance of the PSCodeProperty class as a read only property.
///
/// name of the property
/// This should be a public static non void method taking one PSObject parameter.
/// if namme is null or empty or getterCodeReference is null
/// if getterCodeReference doesn't have the right format.
public PSCodeProperty(string name, MethodInfo getterCodeReference)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (getterCodeReference == null)
{
throw PSTraceSource.NewArgumentNullException("getterCodeReference");
}
SetGetter(getterCodeReference);
}
///
/// Initializes a new instance of the PSCodeProperty class. Setter or getter can be null, but both cannot be null.
///
/// name of the property
/// This should be a public static non void method taking one PSObject parameter.
/// This should be a public static void method taking 2 parameters, where the first is an PSObject.
/// when methodForGet and methodForSet are null
///
/// if:
/// - getterCodeReference doesn't have the right format,
/// - setterCodeReference doesn't have the right format,
/// - both getterCodeReference and setterCodeReference are null.
///
public PSCodeProperty(string name, MethodInfo getterCodeReference, MethodInfo setterCodeReference)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (getterCodeReference == null && setterCodeReference == null)
{
throw PSTraceSource.NewArgumentNullException("getterCodeReference setterCodeReference");
}
SetGetter(getterCodeReference);
SetSetter(setterCodeReference, getterCodeReference);
}
///
/// Gets the method used for the properties' getter. It might be null.
///
public MethodInfo GetterCodeReference { get; private set; }
///
/// Gets the method used for the properties' setter. It might be null.
///
public MethodInfo SetterCodeReference { get; private set; }
#region virtual implementation
///
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
///
/// a new PSMemberInfo that is a copy of this PSMemberInfo
public override PSMemberInfo Copy()
{
PSCodeProperty property = new PSCodeProperty(name, GetterCodeReference, SetterCodeReference);
CloneBaseProperties(property);
return property;
}
///
/// Gets the member type
///
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.CodeProperty;
}
}
///
/// Gets true if this property can be set
///
public override bool IsSettable
{
get
{
return this.SetterCodeReference != null;
}
}
///
/// Gets true if this property can be read
///
public override bool IsGettable
{
get
{
return GetterCodeReference != null;
}
}
///
/// Gets and Sets the value of this member
///
/// When getting and there is no getter or when the getter throws an exception
/// When setting and there is no setter or when the setter throws an exception
public override object Value
{
get
{
if (GetterCodeReference == null)
{
throw new GetValueException("GetWithoutGetterFromCodePropertyValue",
null,
ExtendedTypeSystem.GetWithoutGetterException,
this.Name);
}
try
{
return GetterCodeReference.Invoke(null, new object[1] { this.instance });
}
catch (TargetInvocationException ex)
{
Exception inner = ex.InnerException ?? ex;
throw new GetValueInvocationException("CatchFromCodePropertyGetTI",
inner,
ExtendedTypeSystem.ExceptionWhenGetting,
this.name, inner.Message);
}
catch (Exception e)
{
if (e is GetValueException)
{
throw;
}
CommandProcessorBase.CheckForSevereException(e);
throw new GetValueInvocationException("CatchFromCodePropertyGet",
e,
ExtendedTypeSystem.ExceptionWhenGetting,
this.name, e.Message);
}
}
set
{
if (SetterCodeReference == null)
{
throw new SetValueException("SetWithoutSetterFromCodeProperty",
null,
ExtendedTypeSystem.SetWithoutSetterException,
this.Name);
}
try
{
SetterCodeReference.Invoke(null, new object[2] { this.instance, value });
}
catch (TargetInvocationException ex)
{
Exception inner = ex.InnerException ?? ex;
throw new SetValueInvocationException("CatchFromCodePropertySetTI",
inner,
ExtendedTypeSystem.ExceptionWhenSetting,
this.name, inner.Message);
}
catch (Exception e)
{
if (e is SetValueException)
{
throw;
}
CommandProcessorBase.CheckForSevereException(e);
throw new SetValueInvocationException("CatchFromCodePropertySet",
e,
ExtendedTypeSystem.ExceptionWhenSetting,
this.name, e.Message);
}
}
}
///
/// Gets the type of the value for this member
///
/// If there is no property getter
public override string TypeNameOfValue
{
get
{
if (GetterCodeReference == null)
{
throw new GetValueException("GetWithoutGetterFromCodePropertyTypeOfValue",
null,
ExtendedTypeSystem.GetWithoutGetterException,
this.Name);
}
return GetterCodeReference.ReturnType.FullName;
}
}
#endregion virtual implementation
}
///
/// Used to access the adapted or base properties from the BaseObject
///
public class PSProperty : PSPropertyInfo
{
///
/// Returns the string representation of this property
///
/// This property as a string
public override string ToString()
{
if (this.isDeserialized)
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(this.TypeNameOfValue);
returnValue.Append(" {get;set;}");
return returnValue.ToString();
}
Diagnostics.Assert((this.baseObject != null) && (this.adapter != null), "if it is deserialized, it should have all these properties set");
return adapter.BasePropertyToString(this);
}
///
/// used by the adapters to keep intermediate data used between DoGetProperty and
/// DoGetValue or DoSetValue
///
internal string typeOfValue;
internal object serializedValue;
internal bool isDeserialized;
///
/// This will be either instance.adapter or instance.clrAdapter
///
internal Adapter adapter;
internal object adapterData;
internal object baseObject;
///
/// Constructs a property from a serialized value
///
/// name of the property
/// value of the property
internal PSProperty(string name, object serializedValue)
{
this.isDeserialized = true;
this.serializedValue = serializedValue;
this.name = name;
}
///
/// Constructs this proprerty
///
/// name of the property
/// adapter used in DoGetProperty
/// object passed to DoGetProperty
/// adapter specific data
/// for invalid arguments
internal PSProperty(string name, Adapter adapter, object baseObject, object adapterData)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
this.adapter = adapter;
this.adapterData = adapterData;
this.baseObject = baseObject;
}
#region virtual implementation
///
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
///
/// a new PSMemberInfo that is a copy of this PSMemberInfo
public override PSMemberInfo Copy()
{
PSProperty property = new PSProperty(this.name, this.adapter, this.baseObject, this.adapterData);
CloneBaseProperties(property);
property.typeOfValue = this.typeOfValue;
property.serializedValue = this.serializedValue;
property.isDeserialized = this.isDeserialized;
return property;
}
///
/// Gets the member type
///
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.Property;
}
}
private object GetAdaptedValue()
{
if (this.isDeserialized)
{
return serializedValue;
}
Diagnostics.Assert((this.baseObject != null) && (this.adapter != null), "if it is deserialized, it should have all these properties set");
object o = adapter.BasePropertyGet(this);
return o;
}
internal void SetAdaptedValue(object setValue, bool shouldConvert)
{
if (this.isDeserialized)
{
serializedValue = setValue;
return;
}
Diagnostics.Assert((this.baseObject != null) && (this.adapter != null), "if it is deserialized, it should have all these properties set");
adapter.BasePropertySet(this, setValue, shouldConvert);
}
///
/// Gets or sets the value of this property
///
/// When getting the value of a property throws an exception
/// When setting the value of a property throws an exception
public override object Value
{
get
{
return GetAdaptedValue();
}
set
{
SetAdaptedValue(value, true);
}
}
///
/// Gets true if this property can be set
///
public override bool IsSettable
{
get
{
if (this.isDeserialized)
{
return true;
}
Diagnostics.Assert((this.baseObject != null) && (this.adapter != null), "if it is deserialized, it should have all these properties set");
return adapter.BasePropertyIsSettable(this);
}
}
///
/// Gets true if this property can be read
///
public override bool IsGettable
{
get
{
if (this.isDeserialized)
{
return true;
}
Diagnostics.Assert((this.baseObject != null) && (this.adapter != null), "if it is deserialized, it should have all these properties set");
return adapter.BasePropertyIsGettable(this);
}
}
///
/// Gets the type of the value for this member
///
public override string TypeNameOfValue
{
get
{
if (this.isDeserialized)
{
if (serializedValue == null)
{
return String.Empty;
}
PSObject serializedValueAsPSObject = serializedValue as PSObject;
if (serializedValueAsPSObject != null)
{
var typeNames = serializedValueAsPSObject.InternalTypeNames;
if ((typeNames != null) && (typeNames.Count >= 1))
{
// type name at 0-th index is the most specific type (i.e. deserialized.system.io.directoryinfo)
// type names at other indices are less specific (i.e. deserialized.system.object)
return typeNames[0];
}
}
return serializedValue.GetType().FullName;
}
Diagnostics.Assert((this.baseObject != null) && (this.adapter != null), "if it is deserialized, it should have all these properties set");
return adapter.BasePropertyType(this);
}
}
#endregion virtual implementation
}
///
/// A property created by a user-defined PSPropertyAdapter
///
public class PSAdaptedProperty : PSProperty
{
///
/// Creates a property for the given base object
///
/// name of the property
/// an adapter can use this object to keep any arbitrary data it needs
/// for invalid arguments
public PSAdaptedProperty(string name, object tag)
: base(name, null, null, tag)
{
//
// Note that the constructor sets the adapter and base object to null; the ThirdPartyAdapter managing this property must set these values
//
}
internal PSAdaptedProperty(string name, Adapter adapter, object baseObject, object adapterData)
: base(name, adapter, baseObject, adapterData)
{
}
///
/// Copy an adapted property.
///
public override PSMemberInfo Copy()
{
PSAdaptedProperty property = new PSAdaptedProperty(this.name, this.adapter, this.baseObject, this.adapterData);
CloneBaseProperties(property);
property.typeOfValue = this.typeOfValue;
property.serializedValue = this.serializedValue;
property.isDeserialized = this.isDeserialized;
return property;
}
///
/// Gets the object the property belongs to
///
public object BaseObject
{
get
{
return this.baseObject;
}
}
///
/// Gets the data attached to this property
///
public object Tag
{
get
{
return this.adapterData;
}
}
}
///
/// Serves as a property that is a simple name-value pair.
///
public class PSNoteProperty : PSPropertyInfo
{
///
/// Returns the string representation of this property
///
/// This property as a string
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(GetDisplayTypeNameOfValue(this.Value));
returnValue.Append(" ");
returnValue.Append(this.Name);
returnValue.Append("=");
returnValue.Append(this.noteValue == null ? "null" : this.noteValue.ToString());
return returnValue.ToString();
}
internal object noteValue;
///
/// Initiializes a new instance of the PSNoteProperty class.
///
/// name of the property
/// value of the property
/// for an empty or null name
public PSNoteProperty(string name, object value)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
// value can be null
this.noteValue = value;
}
#region virtual implementation
///
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
///
/// a new PSMemberInfo that is a copy of this PSMemberInfo
public override PSMemberInfo Copy()
{
PSNoteProperty property = new PSNoteProperty(this.name, this.noteValue);
CloneBaseProperties(property);
return property;
}
///
/// Gets PSMemberTypes.NoteProperty
///
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.NoteProperty;
}
}
///
/// Gets true since the value of an PSNoteProperty can always be set
///
public override bool IsSettable
{
get
{
return this.IsInstance;
}
}
///
/// Gets true since the value of an PSNoteProperty can always be obtained
///
public override bool IsGettable
{
get
{
return true;
}
}
///
/// Gets or sets the value of this property
///
public override object Value
{
get
{
return this.noteValue;
}
set
{
if (!this.IsInstance)
{
throw new SetValueException("ChangeValueOfStaticNote",
null,
ExtendedTypeSystem.ChangeStaticMember,
this.Name);
}
this.noteValue = value;
}
}
///
/// Gets the type of the value for this member
///
public override string TypeNameOfValue
{
get
{
object val = this.Value;
if (val == null)
{
return typeof(object).FullName;
}
PSObject valAsPSObject = val as PSObject;
if (valAsPSObject != null)
{
var typeNames = valAsPSObject.InternalTypeNames;
if ((typeNames != null) && (typeNames.Count >= 1))
{
// type name at 0-th index is the most specific type (i.e. system.string)
// type names at other indices are less specific (i.e. system.object)
return typeNames[0];
}
}
return val.GetType().FullName;
}
}
#endregion virtual implementation
internal static string GetDisplayTypeNameOfValue(object val)
{
string displayTypeName = null;
PSObject valAsPSObject = val as PSObject;
if (valAsPSObject != null)
{
var typeNames = valAsPSObject.InternalTypeNames;
if ((typeNames != null) && (typeNames.Count >= 1))
{
displayTypeName = typeNames[0];
}
}
if (string.IsNullOrEmpty(displayTypeName))
{
displayTypeName = val == null
? "object"
: ToStringCodeMethods.Type(val.GetType(), dropNamespaces: true);
}
return displayTypeName;
}
}
///
/// Serves as a property that is a simple name-value pair.
///
///
/// It is permitted to subclass
/// but there is no established scenario for doing this, nor has it been tested.
///
public class PSVariableProperty : PSNoteProperty
{
///
/// Returns the string representation of this property
///
/// This property as a string
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(GetDisplayTypeNameOfValue(_variable.Value));
returnValue.Append(" ");
returnValue.Append(_variable.Name);
returnValue.Append("=");
returnValue.Append(_variable.Value ?? "null");
return returnValue.ToString();
}
internal PSVariable _variable;
///
/// Initiializes a new instance of the PSVariableProperty class. This is
/// a subclass of the NoteProperty that wraps a variable instead of a simple value.
///
/// The variable to wrap
/// for an empty or null name
public PSVariableProperty(PSVariable variable)
: base(variable != null ? variable.Name : null, null)
{
if (variable == null)
{
throw PSTraceSource.NewArgumentException("variable");
}
_variable = variable;
}
#region virtual implementation
///
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo,
/// Note that it returns another reference to the variable, not a reference
/// to a new variable...
///
/// a new PSMemberInfo that is a copy of this PSMemberInfo
public override PSMemberInfo Copy()
{
PSNoteProperty property = new PSVariableProperty(_variable);
CloneBaseProperties(property);
return property;
}
///
/// Gets PSMemberTypes.NoteProperty
///
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.NoteProperty;
}
}
///
/// True if the underlying variable is settable...
///
public override bool IsSettable
{
get
{
return (_variable.Options & (ScopedItemOptions.Constant | ScopedItemOptions.ReadOnly)) == ScopedItemOptions.None;
}
}
///
/// Gets true since the value of an PSNoteProperty can always be obtained
///
public override bool IsGettable
{
get
{
return true;
}
}
///
/// Gets or sets the value of this property
///
public override object Value
{
get
{
return _variable.Value;
}
set
{
if (!this.IsInstance)
{
throw new SetValueException("ChangeValueOfStaticNote",
null,
ExtendedTypeSystem.ChangeStaticMember,
this.Name);
}
_variable.Value = value;
}
}
///
/// Gets the type of the value for this member
///
public override string TypeNameOfValue
{
get
{
object val = _variable.Value;
if (val == null)
{
return typeof(object).FullName;
}
PSObject valAsPSObject = val as PSObject;
if (valAsPSObject != null)
{
var typeNames = valAsPSObject.InternalTypeNames;
if ((typeNames != null) && (typeNames.Count >= 1))
{
// type name at 0-th index is the most specific type (i.e. system.string)
// type names at other indices are less specific (i.e. system.object)
return typeNames[0];
}
}
return val.GetType().FullName;
}
}
#endregion virtual implementation
}
///
/// Serves as a property implemented with getter and setter scripts.
///
///
/// It is permitted to subclass
/// but there is no established scenario for doing this, nor has it been tested.
///
public class PSScriptProperty : PSPropertyInfo
{
///
/// Returns the string representation of this property
///
/// This property as a string
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(this.TypeNameOfValue);
returnValue.Append(" ");
returnValue.Append(this.Name);
returnValue.Append(" {");
if (this.IsGettable)
{
returnValue.Append("get=");
returnValue.Append(this.GetterScript.ToString());
returnValue.Append(";");
}
if (this.IsSettable)
{
returnValue.Append("set=");
returnValue.Append(this.SetterScript.ToString());
returnValue.Append(";");
}
returnValue.Append("}");
return returnValue.ToString();
}
private Nullable _languageMode;
private string _getterScriptText;
private ScriptBlock _getterScript;
private string _setterScriptText;
private ScriptBlock _setterScript;
private bool _shouldCloneOnAccess;
///
/// Gets the script used for the property getter. It might be null.
///
public ScriptBlock GetterScript
{
get
{
// If we don't have a script block for the getter, see if we
// have the text for it (to support delayed script compilation).
if ((_getterScript == null) && (_getterScriptText != null))
{
_getterScript = ScriptBlock.Create(_getterScriptText);
if (_languageMode.HasValue)
{
_getterScript.LanguageMode = _languageMode;
}
_getterScript.DebuggerStepThrough = true;
}
if (_getterScript == null)
{
return null;
}
if (_shouldCloneOnAccess)
{
// returning a clone as TypeTable might be shared between multiple
// runspaces and ScriptBlock is not shareable. We decided to
// Clone as needed instead of Cloning whenever a shared TypeTable is
// attached to a Runspace to save on Memory.
ScriptBlock newGetterScript = _getterScript.Clone();
newGetterScript.LanguageMode = _getterScript.LanguageMode;
return newGetterScript;
}
else
{
return _getterScript;
}
}
}
///
/// Gets the script used for the property setter. It might be null.
///
public ScriptBlock SetterScript
{
get
{
// If we don't have a script block for the setter, see if we
// have the text for it (to support delayed script compilation).
if ((_setterScript == null) && (_setterScriptText != null))
{
_setterScript = ScriptBlock.Create(_setterScriptText);
if (_languageMode.HasValue)
{
_setterScript.LanguageMode = _languageMode;
}
_setterScript.DebuggerStepThrough = true;
}
if (_setterScript == null)
{
return null;
}
if (_shouldCloneOnAccess)
{
// returning a clone as TypeTable might be shared between multiple
// runspaces and ScriptBlock is not shareable. We decided to
// Clone as needed instead of Cloning whenever a shared TypeTable is
// attached to a Runspace to save on Memory.
ScriptBlock newSetterScript = _setterScript.Clone();
newSetterScript.LanguageMode = _setterScript.LanguageMode;
return newSetterScript;
}
else
{
return _setterScript;
}
}
}
///
/// Initializes an instance of the PSScriptProperty class as a read only property.
///
/// name of the property
/// script to be used for the property getter. $this will be this PSObject.
/// for invalid arguments
public PSScriptProperty(string name, ScriptBlock getterScript)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (getterScript == null)
{
throw PSTraceSource.NewArgumentNullException("getterScript");
}
_getterScript = getterScript;
}
///
/// Initializes an instance of the PSScriptProperty class as a read only
/// property. getterScript or setterScript can be null, but not both.
///
/// Name of this property
/// script to be used for the property getter. $this will be this PSObject.
/// script to be used for the property setter. $this will be this PSObject and $args(1) will be the value to set.
/// for invalid arguments
public PSScriptProperty(string name, ScriptBlock getterScript, ScriptBlock setterScript)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (getterScript == null && setterScript == null)
{
// we only do not allow both getterScript and setterScript to be null
throw PSTraceSource.NewArgumentException("getterScript setterScript");
}
if (getterScript != null)
{
getterScript.DebuggerStepThrough = true;
}
if (setterScript != null)
{
setterScript.DebuggerStepThrough = true;
}
_getterScript = getterScript;
_setterScript = setterScript;
}
///
/// Initializes an instance of the PSScriptProperty class as a read only
/// property, using the text of the properties to support lazy initialization.
///
/// Name of this property
/// script to be used for the property getter. $this will be this PSObject.
/// script to be used for the property setter. $this will be this PSObject and $args(1) will be the value to set.
/// Language mode to be used during script block evaluation.
/// for invalid arguments
internal PSScriptProperty(string name, string getterScript, string setterScript, Nullable languageMode)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (getterScript == null && setterScript == null)
{
// we only do not allow both getterScript and setterScript to be null
throw PSTraceSource.NewArgumentException("getterScript setterScript");
}
_getterScriptText = getterScript;
_setterScriptText = setterScript;
_languageMode = languageMode;
}
internal PSScriptProperty(string name, ScriptBlock getterScript, ScriptBlock setterScript, bool shouldCloneOnAccess)
: this(name, getterScript, setterScript)
{
_shouldCloneOnAccess = shouldCloneOnAccess;
}
internal PSScriptProperty(string name, string getterScript, string setterScript, Nullable languageMode, bool shouldCloneOnAccess)
: this(name, getterScript, setterScript, languageMode)
{
_shouldCloneOnAccess = shouldCloneOnAccess;
}
#region virtual implementation
///
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
///
/// a new PSMemberInfo that is a copy of this PSMemberInfo
public override PSMemberInfo Copy()
{
PSScriptProperty property;
property = new PSScriptProperty(name, this.GetterScript, this.SetterScript);
property._shouldCloneOnAccess = _shouldCloneOnAccess;
CloneBaseProperties(property);
return property;
}
///
/// Gets the member type
///
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.ScriptProperty;
}
}
///
/// Gets true if this property can be set
///
public override bool IsSettable
{
get
{
return this.SetterScript != null;
}
}
///
/// Gets true if this property can be read
///
public override bool IsGettable
{
get
{
return this.GetterScript != null;
}
}
///
/// Gets and Sets the value of this property
///
/// When getting and there is no getter,
/// when the getter throws an exception or when there is no Runspace to run the script.
///
/// When setting and there is no setter,
/// when the setter throws an exception or when there is no Runspace to run the script.
public override object Value
{
get
{
if (this.GetterScript == null)
{
throw new GetValueException("GetWithoutGetterFromScriptPropertyValue",
null,
ExtendedTypeSystem.GetWithoutGetterException,
this.Name);
}
return InvokeGetter(this.instance);
}
set
{
if (this.SetterScript == null)
{
throw new SetValueException("SetWithoutSetterFromScriptProperty",
null,
ExtendedTypeSystem.SetWithoutSetterException,
this.Name);
}
InvokeSetter(this.instance, value);
}
}
internal object InvokeSetter(object scriptThis, object value)
{
try
{
SetterScript.DoInvokeReturnAsIs(
useLocalScope: true,
errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToExternalErrorPipe,
dollarUnder: AutomationNull.Value,
input: AutomationNull.Value,
scriptThis: scriptThis,
args: new object[] { value });
return value;
}
catch (SessionStateOverflowException e)
{
throw NewSetValueException(e, "ScriptSetValueSessionStateOverflowException");
}
catch (RuntimeException e)
{
throw NewSetValueException(e, "ScriptSetValueRuntimeException");
}
catch (TerminateException)
{
// The debugger is terminating the execution; let the exception bubble up
throw;
}
catch (FlowControlException e)
{
throw NewSetValueException(e, "ScriptSetValueFlowControlException");
}
catch (PSInvalidOperationException e)
{
throw NewSetValueException(e, "ScriptSetValueInvalidOperationException");
}
}
internal object InvokeGetter(object scriptThis)
{
try
{
return GetterScript.DoInvokeReturnAsIs(
useLocalScope: true,
errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.SwallowErrors,
dollarUnder: AutomationNull.Value,
input: AutomationNull.Value,
scriptThis: scriptThis,
args: Utils.EmptyArray