/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Management.Automation.Language;
using System.Reflection;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
using System.Xml;
using System.Management.Automation;
using System.Management.Automation.Internal;
using System.Management.Automation.Runspaces;
using System.Runtime.Serialization;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Management.Infrastructure;
#if !CORECLR
using System.DirectoryServices;
#endif
#pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings
#pragma warning disable 56500
namespace System.Management.Automation
{
///
/// Wraps an object providing alternate views of the available members
/// and ways to extend them. Members can be methods, properties,
/// parameterized properties, etc.
///
///
/// It is permitted to subclass
/// but there is no established scenario for doing this, nor has it been tested.
///
[TypeDescriptionProvider(typeof(PSObjectTypeDescriptionProvider))]
[Serializable]
public class PSObject : IFormattable, IComparable, ISerializable, IDynamicMetaObjectProvider
{
#region constructors
#region private to the constructors
internal TypeTable GetTypeTable()
{
TypeTable typeTable;
if (_typeTable != null && _typeTable.TryGetTarget(out typeTable))
{
return typeTable;
}
ExecutionContext context = LocalPipeline.GetExecutionContextFromTLS();
if (context != null)
{
return context.TypeTable;
}
return null;
}
internal static T TypeTableGetMemberDelegate(PSObject msjObj, string name) where T : PSMemberInfo
{
TypeTable table = msjObj.GetTypeTable();
return TypeTableGetMemberDelegate(msjObj, table, name);
}
private static T TypeTableGetMemberDelegate(PSObject msjObj, TypeTable typeTableToUse, string name) where T : PSMemberInfo
{
if (typeTableToUse == null)
{
return null;
}
PSMemberInfoInternalCollection allMembers = typeTableToUse.GetMembers(msjObj.InternalTypeNames);
PSMemberInfo member = allMembers[name];
if (member == null)
{
PSObject.memberResolution.WriteLine("\"{0}\" NOT present in type table.", name);
return null;
}
T memberAsT = member as T;
if (memberAsT != null)
{
PSObject.memberResolution.WriteLine("\"{0}\" present in type table.", name);
return memberAsT;
}
PSObject.memberResolution.WriteLine("\"{0}\" from types table ignored because it has type {1} instead of {2}.",
name, member.GetType(), typeof(T));
return null;
}
internal static PSMemberInfoInternalCollection TypeTableGetMembersDelegate(PSObject msjObj) where T : PSMemberInfo
{
TypeTable table = msjObj.GetTypeTable();
return TypeTableGetMembersDelegate(msjObj, table);
}
internal static PSMemberInfoInternalCollection TypeTableGetMembersDelegate(PSObject msjObj, TypeTable typeTableToUse) where T : PSMemberInfo
{
if (typeTableToUse == null)
{
return new PSMemberInfoInternalCollection();
}
PSMemberInfoInternalCollection members = typeTableToUse.GetMembers(msjObj.InternalTypeNames);
PSObject.memberResolution.WriteLine("Type table members: {0}.", members.Count);
return members;
}
private static T AdapterGetMemberDelegate(PSObject msjObj, string name) where T : PSMemberInfo
{
if (msjObj.isDeserialized)
{
if (msjObj.adaptedMembers == null)
{
return null;
}
T adaptedMember = msjObj.adaptedMembers[name] as T;
PSObject.memberResolution.WriteLine("Serialized adapted member: {0}.", adaptedMember == null ? "not found" : adaptedMember.Name);
return adaptedMember;
}
T retValue = msjObj.InternalAdapter.BaseGetMember(msjObj._immediateBaseObject, name);
PSObject.memberResolution.WriteLine("Adapted member: {0}.", retValue == null ? "not found" : retValue.Name);
return retValue;
}
internal static PSMemberInfoInternalCollection TransformMemberInfoCollection(PSMemberInfoCollection source) where T : PSMemberInfo where U : PSMemberInfo
{
if (typeof(T) == typeof(U))
{
// If the types are the same, don't make a copy, return the cached collection.
return source as PSMemberInfoInternalCollection;
}
PSMemberInfoInternalCollection returnValue = new PSMemberInfoInternalCollection();
foreach (T member in source)
{
U tAsU = member as U;
if (tAsU != null)
{
returnValue.Add(tAsU);
}
}
return returnValue;
}
private static PSMemberInfoInternalCollection AdapterGetMembersDelegate(PSObject msjObj) where T : PSMemberInfo
{
if (msjObj.isDeserialized)
{
if (msjObj.adaptedMembers == null)
{
return new PSMemberInfoInternalCollection();
}
PSObject.memberResolution.WriteLine("Serialized adapted members: {0}.", msjObj.adaptedMembers.Count);
return TransformMemberInfoCollection(msjObj.adaptedMembers);
}
PSMemberInfoInternalCollection retValue = msjObj.InternalAdapter.BaseGetMembers(msjObj._immediateBaseObject);
PSObject.memberResolution.WriteLine("Adapted members: {0}.", retValue.VisibleCount);
return retValue;
}
private static PSMemberInfoInternalCollection DotNetGetMembersDelegate(PSObject msjObj) where T : PSMemberInfo
{
// Don't lookup dotnet members if the object doesn't insist.
if (null != msjObj.InternalAdapterSet.DotNetAdapter)
{
PSMemberInfoInternalCollection retValue = msjObj.InternalAdapterSet.DotNetAdapter.BaseGetMembers(msjObj._immediateBaseObject);
PSObject.memberResolution.WriteLine("DotNet members: {0}.", retValue.VisibleCount);
return retValue;
}
return new PSMemberInfoInternalCollection();
}
private static T DotNetGetMemberDelegate(PSObject msjObj, string name) where T : PSMemberInfo
{
// Don't lookup dotnet member if the object doesn't insist.
if (null != msjObj.InternalAdapterSet.DotNetAdapter)
{
T retValue = msjObj.InternalAdapterSet.DotNetAdapter.BaseGetMember(msjObj._immediateBaseObject, name);
PSObject.memberResolution.WriteLine("DotNet member: {0}.", retValue == null ? "not found" : retValue.Name);
return retValue;
}
return null;
}
private static Collection> s_memberCollection = GetMemberCollection(PSMemberViewTypes.All);
private static Collection> s_methodCollection = GetMethodCollection();
private static Collection> s_propertyCollection = GetPropertyCollection(PSMemberViewTypes.All);
///
/// A collection of delegates to get Extended/Adapted/Dotnet members based on the
///
///
///
/// A filter to select Extended/Adapted/Dotnet view of the object
///
///
internal static Collection> GetMemberCollection(PSMemberViewTypes viewType)
{
return GetMemberCollection(viewType, null);
}
///
/// A collection of delegates to get Extended/Adapted/Dotnet members based on the
///
///
///
/// A filter to select Extended/Adapted/Dotnet view of the object
///
///
/// Backup type table to use if there is no execution context associated with the current thread
///
///
internal static Collection> GetMemberCollection(
PSMemberViewTypes viewType,
TypeTable backupTypeTable)
{
Collection> returnValue = new Collection>();
if ((viewType & PSMemberViewTypes.Extended) == PSMemberViewTypes.Extended)
{
if (backupTypeTable == null)
{
returnValue.Add(new CollectionEntry(
PSObject.TypeTableGetMembersDelegate,
PSObject.TypeTableGetMemberDelegate,
true, true, "type table members"));
}
else
{
returnValue.Add(new CollectionEntry(
delegate (PSObject msjObj)
{
return TypeTableGetMembersDelegate(msjObj, backupTypeTable);
},
delegate (PSObject msjObj, string name)
{
return TypeTableGetMemberDelegate(msjObj, backupTypeTable, name);
},
true, true, "type table members"));
}
}
if ((viewType & PSMemberViewTypes.Adapted) == PSMemberViewTypes.Adapted)
{
returnValue.Add(new CollectionEntry(
PSObject.AdapterGetMembersDelegate,
PSObject.AdapterGetMemberDelegate,
false, false, "adapted members"));
}
if ((viewType & PSMemberViewTypes.Base) == PSMemberViewTypes.Base)
{
returnValue.Add(new CollectionEntry(
PSObject.DotNetGetMembersDelegate,
PSObject.DotNetGetMemberDelegate,
false, false, "clr members"));
}
return returnValue;
}
private static Collection> GetMethodCollection()
{
Collection> returnValue = new Collection>();
returnValue.Add(new CollectionEntry(
PSObject.TypeTableGetMembersDelegate,
PSObject.TypeTableGetMemberDelegate,
true, true, "type table members"));
returnValue.Add(new CollectionEntry(
PSObject.AdapterGetMembersDelegate,
PSObject.AdapterGetMemberDelegate,
false, false, "adapted members"));
returnValue.Add(new CollectionEntry(
PSObject.DotNetGetMembersDelegate,
PSObject.DotNetGetMemberDelegate,
false, false, "clr members"));
return returnValue;
}
///
/// A collection of delegates to get Extended/Adapted/Dotnet properties based on the
///
///
///
/// A filter to select Extended/Adapted/Dotnet view of the object
///
///
internal static Collection> GetPropertyCollection(
PSMemberViewTypes viewType)
{
return GetPropertyCollection(viewType, null);
}
///
/// A collection of delegates to get Extended/Adapted/Dotnet properties based on the
///
///
///
/// A filter to select Extended/Adapted/Dotnet view of the object
///
///
/// Backup type table to use if there is no execution context associated with the current thread
///
///
internal static Collection> GetPropertyCollection(
PSMemberViewTypes viewType,
TypeTable backupTypeTable)
{
Collection> returnValue = new Collection>();
if ((viewType & PSMemberViewTypes.Extended) == PSMemberViewTypes.Extended)
{
if (backupTypeTable == null)
{
returnValue.Add(new CollectionEntry(
PSObject.TypeTableGetMembersDelegate,
PSObject.TypeTableGetMemberDelegate,
true, true, "type table members"));
}
else
{
returnValue.Add(new CollectionEntry(
delegate (PSObject msjObj)
{
return TypeTableGetMembersDelegate(msjObj, backupTypeTable);
},
delegate (PSObject msjObj, string name)
{
return TypeTableGetMemberDelegate(msjObj, backupTypeTable, name);
},
true, true, "type table members"));
}
}
if ((viewType & PSMemberViewTypes.Adapted) == PSMemberViewTypes.Adapted)
{
returnValue.Add(new CollectionEntry(
PSObject.AdapterGetMembersDelegate,
PSObject.AdapterGetMemberDelegate,
false, false, "adapted members"));
}
if ((viewType & PSMemberViewTypes.Base) == PSMemberViewTypes.Base)
{
returnValue.Add(new CollectionEntry(
PSObject.DotNetGetMembersDelegate,
PSObject.DotNetGetMemberDelegate,
false, false, "clr members"));
}
return returnValue;
}
private void CommonInitialization(object obj)
{
Diagnostics.Assert(obj != null, "checked by callers");
if (obj is PSCustomObject)
{
this.immediateBaseObjectIsEmpty = true;
}
_immediateBaseObject = obj;
var context = LocalPipeline.GetExecutionContextFromTLS();
_typeTable = context != null ? context.TypeTableWeakReference : null;
}
internal static readonly DotNetAdapter dotNetInstanceAdapter = new DotNetAdapter();
private static readonly DotNetAdapter s_baseAdapterForAdaptedObjects = new BaseDotNetAdapterForAdaptedObjects();
internal static readonly DotNetAdapter dotNetStaticAdapter = new DotNetAdapter(true);
private static readonly AdapterSet s_dotNetInstanceAdapterSet = new AdapterSet(dotNetInstanceAdapter, null);
private static readonly AdapterSet s_mshMemberSetAdapter = new AdapterSet(new PSMemberSetAdapter(), null);
private static readonly AdapterSet s_mshObjectAdapter = new AdapterSet(new PSObjectAdapter(), null);
private static PSObject.AdapterSet s_cimInstanceAdapter =
new PSObject.AdapterSet(new ThirdPartyAdapter(typeof(Microsoft.Management.Infrastructure.CimInstance),
new Microsoft.PowerShell.Cim.CimInstanceAdapter()),
PSObject.dotNetInstanceAdapter);
#if !CORECLR // WMIv1/ADSI Adapters Not Supported in PowerShell Core
private static readonly AdapterSet managementObjectAdapter = new AdapterSet(new ManagementObjectAdapter(), dotNetInstanceAdapter);
private static readonly AdapterSet managementClassAdapter = new AdapterSet(new ManagementClassApdapter(), dotNetInstanceAdapter);
private static readonly AdapterSet directoryEntryAdapter = new AdapterSet(new DirectoryEntryAdapter(), dotNetInstanceAdapter);
#endif
private static readonly AdapterSet dataRowViewAdapter = new AdapterSet(new DataRowViewAdapter(), s_baseAdapterForAdaptedObjects);
private static readonly AdapterSet dataRowAdapter = new AdapterSet(new DataRowAdapter(), s_baseAdapterForAdaptedObjects);
private static readonly AdapterSet s_xmlNodeAdapter = new AdapterSet(new XmlNodeAdapter(), s_baseAdapterForAdaptedObjects);
#region Adapter Mappings
private static readonly ConcurrentDictionary s_adapterMapping = new ConcurrentDictionary();
private static readonly List> s_adapterSetMappers = new List>
{
MappedInternalAdapterSet
};
internal static void RegisterAdapterMapping(Func