MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections;6using System.Collections.Concurrent;7using System.Collections.Generic;8using System.Collections.ObjectModel;9using System.ComponentModel;10using System.Data;11using System.Diagnostics.CodeAnalysis;12using System.Dynamic;13using System.Globalization;14using System.Linq;15using System.Linq.Expressions;16using System.Management.Automation;17using System.Management.Automation.Internal;18using System.Management.Automation.Language;19using System.Management.Automation.Runspaces;20using System.Reflection;21using System.Runtime.CompilerServices;22using System.Runtime.Serialization;23using System.Text;24using System.Xml;25 26using Microsoft.Management.Infrastructure;27#if !UNIX28using System.DirectoryServices;29using System.Management;30#endif31 32#pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings33#pragma warning disable 5650034 35namespace System.Management.Automation36{37 /// <summary>38 /// Wraps an object providing alternate views of the available members39 /// and ways to extend them. Members can be methods, properties,40 /// parameterized properties, etc.41 /// </summary>42 /// <remarks>43 /// It is permitted to subclass <see cref="PSObject"/>44 /// but there is no established scenario for doing this, nor has it been tested.45 /// </remarks>46 [TypeDescriptionProvider(typeof(PSObjectTypeDescriptionProvider))]47 public class PSObject : IFormattable, IComparable, ISerializable, IDynamicMetaObjectProvider48 {49 #region constructors50 51 #region private to the constructors52 53 internal TypeTable GetTypeTable()54 {55 if (_typeTable != null && _typeTable.TryGetTarget(out TypeTable typeTable))56 {57 return typeTable;58 }59 60 ExecutionContext context = LocalPipeline.GetExecutionContextFromTLS();61 return context?.TypeTable;62 }63 64 internal static T TypeTableGetMemberDelegate<T>(PSObject msjObj, string name) where T : PSMemberInfo65 {66 TypeTable table = msjObj.GetTypeTable();67 return TypeTableGetMemberDelegate<T>(msjObj, table, name);68 }69 70 private static T TypeTableGetMemberDelegate<T>(PSObject msjObj, TypeTable typeTableToUse, string name) where T : PSMemberInfo71 {72 if (typeTableToUse == null)73 {74 return null;75 }76 77 PSMemberInfoInternalCollection<PSMemberInfo> allMembers = typeTableToUse.GetMembers<PSMemberInfo>(msjObj.InternalTypeNames);78 PSMemberInfo member = allMembers[name];79 if (member == null)80 {81 PSObject.MemberResolution.WriteLine("\"{0}\" NOT present in type table.", name);82 return null;83 }84 85 if (member is T memberAsT)86 {87 PSObject.MemberResolution.WriteLine("\"{0}\" present in type table.", name);88 return memberAsT;89 }90 91 PSObject.MemberResolution.WriteLine("\"{0}\" from types table ignored because it has type {1} instead of {2}.",92 name, member.GetType(), typeof(T));93 return null;94 }95 96 internal static PSMemberInfoInternalCollection<T> TypeTableGetMembersDelegate<T>(PSObject msjObj) where T : PSMemberInfo97 {98 TypeTable table = msjObj.GetTypeTable();99 return TypeTableGetMembersDelegate<T>(msjObj, table);100 }101 102 internal static PSMemberInfoInternalCollection<T> TypeTableGetMembersDelegate<T>(PSObject msjObj, TypeTable typeTableToUse) where T : PSMemberInfo103 {104 if (typeTableToUse == null)105 {106 return new PSMemberInfoInternalCollection<T>();107 }108 109 PSMemberInfoInternalCollection<T> members = typeTableToUse.GetMembers<T>(msjObj.InternalTypeNames);110 PSObject.MemberResolution.WriteLine("Type table members: {0}.", members.Count);111 return members;112 }113 114 internal static T TypeTableGetFirstMemberOrDefaultDelegate<T>(PSObject msjObj, MemberNamePredicate predicate) where T : PSMemberInfo115 {116 TypeTable table = msjObj.GetTypeTable();117 return TypeTableGetFirstOrDefaultMemberDelegate<T>(msjObj, table, predicate);118 }119 120 internal static T TypeTableGetFirstOrDefaultMemberDelegate<T>(PSObject msjObj, TypeTable typeTableToUse, MemberNamePredicate predicate) where T : PSMemberInfo121 {122 return typeTableToUse?.GetFirstMemberOrDefault<T>(msjObj.InternalTypeNames, predicate);123 }124 125 private static T AdapterGetMemberDelegate<T>(PSObject msjObj, string name) where T : PSMemberInfo126 {127 if (msjObj.IsDeserialized)128 {129 if (msjObj.AdaptedMembers == null)130 {131 return null;132 }133 134 T adaptedMember = msjObj.AdaptedMembers[name] as T;135 PSObject.MemberResolution.WriteLine("Serialized adapted member: {0}.", adaptedMember == null ? "not found" : adaptedMember.Name);136 return adaptedMember;137 }138 139 T retValue = msjObj.InternalAdapter.BaseGetMember<T>(msjObj.ImmediateBaseObject, name);140 PSObject.MemberResolution.WriteLine("Adapted member: {0}.", retValue == null ? "not found" : retValue.Name);141 return retValue;142 }143 144 private static T AdapterGetFirstMemberOrDefaultDelegate<T>(PSObject msjObj, MemberNamePredicate predicate) where T : PSMemberInfo145 {146 if (msjObj.IsDeserialized && typeof(T).IsAssignableFrom(typeof(PSPropertyInfo)))147 {148 if (msjObj.AdaptedMembers == null)149 {150 return null;151 }152 153 foreach (var adaptedMember in msjObj.AdaptedMembers)154 {155 if (predicate(adaptedMember.Name))156 {157 return adaptedMember as T;158 }159 }160 }161 162 T retValue = msjObj.InternalAdapter.BaseGetFirstMemberOrDefault<T>(msjObj._immediateBaseObject, predicate);163 return retValue;164 }165 166 internal static PSMemberInfoInternalCollection<TResult> TransformMemberInfoCollection<TSource, TResult>(PSMemberInfoCollection<TSource> source)167 where TSource : PSMemberInfo where TResult : PSMemberInfo168 {169 if (typeof(TSource) == typeof(TResult))170 {171 // If the types are the same, don't make a copy, return the cached collection.172 return source as PSMemberInfoInternalCollection<TResult>;173 }174 175 PSMemberInfoInternalCollection<TResult> returnValue = new PSMemberInfoInternalCollection<TResult>();176 foreach (TSource member in source)177 {178 if (member is TResult result)179 {180 returnValue.Add(result);181 }182 }183 184 return returnValue;185 }186 187 private static PSMemberInfoInternalCollection<T> AdapterGetMembersDelegate<T>(PSObject msjObj) where T : PSMemberInfo188 {189 if (msjObj.IsDeserialized)190 {191 if (msjObj.AdaptedMembers == null)192 {193 return new PSMemberInfoInternalCollection<T>();194 }195 196 PSObject.MemberResolution.WriteLine("Serialized adapted members: {0}.", msjObj.AdaptedMembers.Count);197 return TransformMemberInfoCollection<PSPropertyInfo, T>(msjObj.AdaptedMembers);198 }199 200 PSMemberInfoInternalCollection<T> retValue = msjObj.InternalAdapter.BaseGetMembers<T>(msjObj._immediateBaseObject);201 PSObject.MemberResolution.WriteLine("Adapted members: {0}.", retValue.VisibleCount);202 return retValue;203 }204 205 private static PSMemberInfoInternalCollection<T> DotNetGetMembersDelegate<T>(PSObject msjObj) where T : PSMemberInfo206 {207 // Don't lookup dotnet members if the object doesn't insist.208 if (msjObj.InternalBaseDotNetAdapter != null)209 {210 PSMemberInfoInternalCollection<T> retValue = msjObj.InternalBaseDotNetAdapter.BaseGetMembers<T>(msjObj._immediateBaseObject);211 PSObject.MemberResolution.WriteLine("DotNet members: {0}.", retValue.VisibleCount);212 return retValue;213 }214 215 return new PSMemberInfoInternalCollection<T>();216 }217 218 private static T DotNetGetMemberDelegate<T>(PSObject msjObj, string name) where T : PSMemberInfo219 {220 // Don't lookup dotnet member if the object doesn't insist.221 if (msjObj.InternalBaseDotNetAdapter != null)222 {223 T retValue = msjObj.InternalBaseDotNetAdapter.BaseGetMember<T>(msjObj._immediateBaseObject, name);224 PSObject.MemberResolution.WriteLine("DotNet member: {0}.", retValue == null ? "not found" : retValue.Name);225 return retValue;226 }227 228 return null;229 }230 231 private static T DotNetGetFirstMemberOrDefaultDelegate<T>(PSObject msjObj, MemberNamePredicate predicate) where T : PSMemberInfo232 {233 // Don't lookup dotnet member if the object doesn't insist.234 return msjObj.InternalBaseDotNetAdapter?.BaseGetFirstMemberOrDefault<T>(msjObj._immediateBaseObject, predicate);235 }236 237 /// <summary>238 /// A collection of delegates to get Extended/Adapted/Dotnet members based on the239 /// <paramref name="viewType"/>240 /// </summary>241 /// <param name="viewType">242 /// A filter to select Extended/Adapted/Dotnet view of the object243 /// </param>244 /// <returns></returns>245 internal static Collection<CollectionEntry<PSMemberInfo>> GetMemberCollection(PSMemberViewTypes viewType)246 {247 return GetMemberCollection(viewType, null);248 }249 250 /// <summary>251 /// A collection of delegates to get Extended/Adapted/Dotnet members based on the252 /// <paramref name="viewType"/>253 /// </summary>254 /// <param name="viewType">255 /// A filter to select Extended/Adapted/Dotnet view of the object256 /// </param>257 /// <param name="backupTypeTable">258 /// Backup type table to use if there is no execution context associated with the current thread259 /// </param>260 /// <returns></returns>261 internal static Collection<CollectionEntry<PSMemberInfo>> GetMemberCollection(262 PSMemberViewTypes viewType,263 TypeTable backupTypeTable)264 {265 Collection<CollectionEntry<PSMemberInfo>> returnValue = new Collection<CollectionEntry<PSMemberInfo>>();266 if ((viewType & PSMemberViewTypes.Extended) == PSMemberViewTypes.Extended)267 {268 if (backupTypeTable == null)269 {270 returnValue.Add(new CollectionEntry<PSMemberInfo>(271 PSObject.TypeTableGetMembersDelegate<PSMemberInfo>,272 PSObject.TypeTableGetMemberDelegate<PSMemberInfo>,273 PSObject.TypeTableGetFirstMemberOrDefaultDelegate<PSMemberInfo>,274 true, true, "type table members"));275 }276 else277 {278 returnValue.Add(new CollectionEntry<PSMemberInfo>(279 msjObj => TypeTableGetMembersDelegate<PSMemberInfo>(msjObj, backupTypeTable),280 (msjObj, name) => TypeTableGetMemberDelegate<PSMemberInfo>(msjObj, backupTypeTable, name),281 (msjObj, predicate) => TypeTableGetFirstOrDefaultMemberDelegate<PSMemberInfo>(msjObj, backupTypeTable, predicate),282 true, true, "type table members"));283 }284 }285 286 if ((viewType & PSMemberViewTypes.Adapted) == PSMemberViewTypes.Adapted)287 {288 returnValue.Add(new CollectionEntry<PSMemberInfo>(289 PSObject.AdapterGetMembersDelegate<PSMemberInfo>,290 PSObject.AdapterGetMemberDelegate<PSMemberInfo>,291 PSObject.AdapterGetFirstMemberOrDefaultDelegate<PSMemberInfo>,292 shouldReplicateWhenReturning: false,293 shouldCloneWhenReturning: false,294 collectionNameForTracing: "adapted members"));295 }296 297 if ((viewType & PSMemberViewTypes.Base) == PSMemberViewTypes.Base)298 {299 returnValue.Add(new CollectionEntry<PSMemberInfo>(300 PSObject.DotNetGetMembersDelegate<PSMemberInfo>,301 PSObject.DotNetGetMemberDelegate<PSMemberInfo>,302 PSObject.DotNetGetFirstMemberOrDefaultDelegate<PSMemberInfo>,303 shouldReplicateWhenReturning: false,304 shouldCloneWhenReturning: false,305 collectionNameForTracing: "clr members"));306 }307 308 return returnValue;309 }310 311 private static Collection<CollectionEntry<PSMethodInfo>> GetMethodCollection()312 {313 Collection<CollectionEntry<PSMethodInfo>> returnValue = new Collection<CollectionEntry<PSMethodInfo>>314 {315 new CollectionEntry<PSMethodInfo>(316 PSObject.TypeTableGetMembersDelegate<PSMethodInfo>,317 PSObject.TypeTableGetMemberDelegate<PSMethodInfo>,318 PSObject.TypeTableGetFirstMemberOrDefaultDelegate<PSMethodInfo>,319 shouldReplicateWhenReturning: true,320 shouldCloneWhenReturning: true,321 collectionNameForTracing: "type table members"),322 new CollectionEntry<PSMethodInfo>(323 PSObject.AdapterGetMembersDelegate<PSMethodInfo>,324 PSObject.AdapterGetMemberDelegate<PSMethodInfo>,325 PSObject.AdapterGetFirstMemberOrDefaultDelegate<PSMethodInfo>,326 shouldReplicateWhenReturning: false,327 shouldCloneWhenReturning: false,328 collectionNameForTracing: "adapted members"),329 new CollectionEntry<PSMethodInfo>(330 PSObject.DotNetGetMembersDelegate<PSMethodInfo>,331 PSObject.DotNetGetMemberDelegate<PSMethodInfo>,332 PSObject.DotNetGetFirstMemberOrDefaultDelegate<PSMethodInfo>,333 shouldReplicateWhenReturning: false,334 shouldCloneWhenReturning: false,335 collectionNameForTracing: "clr members")336 };337 return returnValue;338 }339 340 /// <summary>341 /// A collection of delegates to get Extended/Adapted/Dotnet properties based on the342 /// <paramref name="viewType"/>343 /// </summary>344 /// <param name="viewType">345 /// A filter to select Extended/Adapted/Dotnet view of the object346 /// </param>347 /// <returns></returns>348 internal static Collection<CollectionEntry<PSPropertyInfo>> GetPropertyCollection(349 PSMemberViewTypes viewType)350 {351 return GetPropertyCollection(viewType, null);352 }353 354 /// <summary>355 /// A collection of delegates to get Extended/Adapted/Dotnet properties based on the356 /// <paramref name="viewType"/>357 /// </summary>358 /// <param name="viewType">359 /// A filter to select Extended/Adapted/Dotnet view of the object360 /// </param>361 /// <param name="backupTypeTable">362 /// Backup type table to use if there is no execution context associated with the current thread363 /// </param>364 /// <returns></returns>365 internal static Collection<CollectionEntry<PSPropertyInfo>> GetPropertyCollection(366 PSMemberViewTypes viewType,367 TypeTable backupTypeTable)368 {369 Collection<CollectionEntry<PSPropertyInfo>> returnValue = new Collection<CollectionEntry<PSPropertyInfo>>();370 if ((viewType & PSMemberViewTypes.Extended) == PSMemberViewTypes.Extended)371 {372 if (backupTypeTable == null)373 {374 returnValue.Add(new CollectionEntry<PSPropertyInfo>(375 PSObject.TypeTableGetMembersDelegate<PSPropertyInfo>,376 PSObject.TypeTableGetMemberDelegate<PSPropertyInfo>,377 PSObject.TypeTableGetFirstMemberOrDefaultDelegate<PSPropertyInfo>,378 true, true, "type table members"));379 }380 else381 {382 returnValue.Add(new CollectionEntry<PSPropertyInfo>(383 msjObj => TypeTableGetMembersDelegate<PSPropertyInfo>(msjObj, backupTypeTable),384 (msjObj, name) => TypeTableGetMemberDelegate<PSPropertyInfo>(msjObj, backupTypeTable, name),385 PSObject.TypeTableGetFirstMemberOrDefaultDelegate<PSPropertyInfo>,386 true, true, "type table members"));387 }388 }389 390 if ((viewType & PSMemberViewTypes.Adapted) == PSMemberViewTypes.Adapted)391 {392 returnValue.Add(new CollectionEntry<PSPropertyInfo>(393 PSObject.AdapterGetMembersDelegate<PSPropertyInfo>,394 PSObject.AdapterGetMemberDelegate<PSPropertyInfo>,395 PSObject.AdapterGetFirstMemberOrDefaultDelegate<PSPropertyInfo>,396 false, false, "adapted members"));397 }398 399 if ((viewType & PSMemberViewTypes.Base) == PSMemberViewTypes.Base)400 {401 returnValue.Add(new CollectionEntry<PSPropertyInfo>(402 PSObject.DotNetGetMembersDelegate<PSPropertyInfo>,403 PSObject.DotNetGetMemberDelegate<PSPropertyInfo>,404 PSObject.DotNetGetFirstMemberOrDefaultDelegate<PSPropertyInfo>,405 false, false, "clr members"));406 }407 408 return returnValue;409 }410 411 private void CommonInitialization(object obj)412 {413 Diagnostics.Assert(obj != null, "checked by callers");414 if (obj is PSCustomObject)415 {416 this.ImmediateBaseObjectIsEmpty = true;417 }418 419 _immediateBaseObject = obj;420 var context = LocalPipeline.GetExecutionContextFromTLS();421 _typeTable = context?.TypeTableWeakReference;422 }423 424 #region Adapter Mappings425 426 private static readonly ConcurrentDictionary<Type, AdapterSet> s_adapterMapping = new ConcurrentDictionary<Type, AdapterSet>();427 428 private static readonly List<Func<object, AdapterSet>> s_adapterSetMappers = new List<Func<object, AdapterSet>>429 {430 MappedInternalAdapterSet431 };432 433 private static AdapterSet MappedInternalAdapterSet(object obj)434 {435 if (obj is PSMemberSet) { return PSObject.s_mshMemberSetAdapter; }436 437 if (obj is PSObject) { return PSObject.s_mshObjectAdapter; }438 439 if (obj is CimInstance) { return PSObject.s_cimInstanceAdapter; }440#if !UNIX441 if (obj is ManagementClass) { return PSObject.s_managementClassAdapter; }442 443 if (obj is ManagementBaseObject) { return PSObject.s_managementObjectAdapter; }444 445 if (obj is DirectoryEntry) { return PSObject.s_directoryEntryAdapter; }446#endif447 if (obj is DataRowView) { return PSObject.s_dataRowViewAdapter; }448 449 if (obj is DataRow) { return PSObject.s_dataRowAdapter; }450 451 if (obj is XmlNode) { return PSObject.s_xmlNodeAdapter; }452 453 return null;454 }455 456 /// <summary>457 /// Returns the adapter corresponding to obj.GetType()458 /// </summary>459 /// <returns>The adapter set corresponding to obj.GetType().</returns>460 internal static AdapterSet GetMappedAdapter(object obj, TypeTable typeTable)461 {462 Type objectType = obj.GetType();463 464 PSObject.AdapterSet adapter = typeTable?.GetTypeAdapter(objectType);465 466 if (adapter != null)467 {468 // We don't cache results found via the type table because type tables may differ b/w runspaces,469 // our cache is app domain wide, and the key is simply the type.470 return adapter;471 }472 473 if (s_adapterMapping.TryGetValue(objectType, out AdapterSet result))474 {475 return result;476 }477 478 lock (s_adapterSetMappers)479 {480 foreach (var mapper in s_adapterSetMappers)481 {482 result = mapper(obj);483 if (result != null)484 {485 break;486 }487 }488 }489 490 if (result == null)491 {492#if !UNIX493 if (objectType.IsCOMObject)494 {495 // All WinRT types are COM types.496 // All WinRT types would contain the TypeAttributes flag being set to WindowsRunTime.497 if (WinRTHelper.IsWinRTType(objectType))498 {499 result = PSObject.s_dotNetInstanceAdapterSet;500 }501 502 // We are not using IsAssignableFrom because we want to avoid503 // using the COM adapters for Primary Interop Assembly types504 // and they derive from System.__ComObject.505 // We are not using Type.Equals because System.__ComObject is506 // not public.507 else if (objectType.FullName.Equals("System.__ComObject"))508 {509 // We don't cache the adapter set for COM objects because the adapter varies depending on the COM object, but often510 // (typically), the runtime type is always the same. That's why this if statement is here and returns.511 512 ComTypeInfo info = ComTypeInfo.GetDispatchTypeInfo(obj);513 return info != null514 ? new AdapterSet(new ComAdapter(info), DotNetInstanceAdapter)515 : PSObject.s_dotNetInstanceAdapterSet;516 }517 else518 {519 ComTypeInfo info = ComTypeInfo.GetDispatchTypeInfo(obj);520 result = info != null521 ? new AdapterSet(new DotNetAdapterWithComTypeName(info), null)522 : PSObject.s_dotNetInstanceAdapterSet;523 }524 }525 else526 {527 result = PSObject.s_dotNetInstanceAdapterSet;528 }529#else530 result = PSObject.s_dotNetInstanceAdapterSet;531#endif532 }533 534 var existingOrNew = s_adapterMapping.GetOrAdd(objectType, result);535 Diagnostics.Assert(existingOrNew == result, "There is a logic error in caching adapter sets.");536 537 return result;538 }539 540 #endregion541 542 internal static AdapterSet CreateThirdPartyAdapterSet(Type adaptedType, PSPropertyAdapter adapter)543 {544 return new AdapterSet(new ThirdPartyAdapter(adaptedType, adapter), s_baseAdapterForAdaptedObjects);545 }546 547 #endregion private to the constructors548 549 /// <summary>550 /// Initializes a new instance of PSObject with an PSCustomObject BaseObject.551 /// </summary>552 public PSObject()553 {554 CommonInitialization(PSCustomObject.SelfInstance);555 }556 557 /// <summary>558 /// Initializes a new instance of PSObject with an PSCustomObject BaseObject559 /// with an initial capacity for members.560 /// </summary>561 /// <param name="instanceMemberCapacity">The initial capacity for the instance member collection.</param>562 public PSObject(int instanceMemberCapacity) : this()563 {564 _instanceMembers = new PSMemberInfoInternalCollection<PSMemberInfo>(instanceMemberCapacity);565 }566 567 /// <summary>568 /// Initializes a new instance of PSObject wrapping obj (accessible through BaseObject).569 /// </summary>570 /// <param name="obj">Object we are wrapping.</param>571 /// <exception cref="ArgumentNullException">If <paramref name="obj"/> is null.</exception>572 [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "This is shipped as part of V1. Retaining this for backward compatibility.")]573 public PSObject(object obj)574 {575 if (obj == null)576 {577 throw PSTraceSource.NewArgumentNullException(nameof(obj));578 }579 580 CommonInitialization(obj);581 }582 583 /// <summary>584 /// Creates a PSObject from an ISerializable context.585 /// </summary>586 /// <param name="info">Serialization information for this instance.</param>587 /// <param name="context">The streaming context for this instance.</param>588 protected PSObject(SerializationInfo info, StreamingContext context)589 {590 if (info == null)591 {592 throw PSTraceSource.NewArgumentNullException(nameof(info));593 }594 595 if (info.GetValue("CliXml", typeof(string)) is not string serializedData)596 {597 throw PSTraceSource.NewArgumentNullException(nameof(info));598 }599 600 PSObject result = PSObject.AsPSObject(PSSerializer.Deserialize(serializedData));601 CommonInitialization(result.ImmediateBaseObject);602 603 CopyDeserializerFields(source: result, target: this);604 }605 606 internal static PSObject ConstructPSObjectFromSerializationInfo(SerializationInfo info, StreamingContext context)607 {608 return new PSObject(info, context);609 }610 611 #endregion constructors612 613 #region fields614 615 #region instance fields616 617 private readonly object _lockObject = new object();618 619 private ConsolidatedString _typeNames;620 621 /// <summary>622 /// This is the main field in the class representing623 /// the System.Object we are encapsulating.624 /// </summary>625 private object _immediateBaseObject;626 627 private WeakReference<TypeTable> _typeTable;628 private AdapterSet _adapterSet;629 private PSMemberInfoInternalCollection<PSMemberInfo> _instanceMembers;630 private PSMemberInfoIntegratingCollection<PSMemberInfo> _members;631 private PSMemberInfoIntegratingCollection<PSPropertyInfo> _properties;632 private PSMemberInfoIntegratingCollection<PSMethodInfo> _methods;633 634 private PSObjectFlags _flags;635 636 #endregion instance fields637 638 private static readonly PSTraceSource s_memberResolution = PSTraceSource.GetTracer("MemberResolution", "Traces the resolution from member name to the member. A member can be a property, method, etc.", false);639 640 private static readonly ConditionalWeakTable<object, ConsolidatedString> s_typeNamesResurrectionTable = new ConditionalWeakTable<object, ConsolidatedString>();641 642 private static readonly Collection<CollectionEntry<PSMemberInfo>> s_memberCollection = GetMemberCollection(PSMemberViewTypes.All);643 private static readonly Collection<CollectionEntry<PSMethodInfo>> s_methodCollection = GetMethodCollection();644 private static readonly Collection<CollectionEntry<PSPropertyInfo>> s_propertyCollection = GetPropertyCollection(PSMemberViewTypes.All);645 646 private static readonly DotNetAdapter s_dotNetInstanceAdapter = new DotNetAdapter();647 private static readonly DotNetAdapter s_baseAdapterForAdaptedObjects = new BaseDotNetAdapterForAdaptedObjects();648 private static readonly DotNetAdapter s_dotNetStaticAdapter = new DotNetAdapter(true);649 650 private static readonly AdapterSet s_dotNetInstanceAdapterSet = new AdapterSet(DotNetInstanceAdapter, null);651 private static readonly AdapterSet s_mshMemberSetAdapter = new AdapterSet(new PSMemberSetAdapter(), null);652 private static readonly AdapterSet s_mshObjectAdapter = new AdapterSet(new PSObjectAdapter(), null);653 654 private static readonly PSObject.AdapterSet s_cimInstanceAdapter =655 new PSObject.AdapterSet(new ThirdPartyAdapter(typeof(Microsoft.Management.Infrastructure.CimInstance),656 new Microsoft.PowerShell.Cim.CimInstanceAdapter()),657 PSObject.DotNetInstanceAdapter);658 659#if !UNIX660 private static readonly AdapterSet s_managementObjectAdapter = new AdapterSet(new ManagementObjectAdapter(), DotNetInstanceAdapter);661 private static readonly AdapterSet s_managementClassAdapter = new AdapterSet(new ManagementClassApdapter(), DotNetInstanceAdapter);662 private static readonly AdapterSet s_directoryEntryAdapter = new AdapterSet(new DirectoryEntryAdapter(), DotNetInstanceAdapter);663#endif664 private static readonly AdapterSet s_dataRowViewAdapter = new AdapterSet(new DataRowViewAdapter(), s_baseAdapterForAdaptedObjects);665 private static readonly AdapterSet s_dataRowAdapter = new AdapterSet(new DataRowAdapter(), s_baseAdapterForAdaptedObjects);666 private static readonly AdapterSet s_xmlNodeAdapter = new AdapterSet(new XmlNodeAdapter(), s_baseAdapterForAdaptedObjects);667 668 #endregion fields669 670 #region properties671 672 internal PSMemberInfoInternalCollection<PSMemberInfo> InstanceMembers673 {674 get675 {676 if (_instanceMembers == null)677 {678 lock (_lockObject)679 {680 _instanceMembers ??=681 s_instanceMembersResurrectionTable.GetValue(682 GetKeyForResurrectionTables(this),683 _ => new PSMemberInfoInternalCollection<PSMemberInfo>());684 }685 }686 687 return _instanceMembers;688 }689 690 set => _instanceMembers = value;691 }692 693 /// <summary>694 /// This is the adapter that will depend on the type of baseObject.695 /// </summary>696 internal Adapter InternalAdapter => InternalAdapterSet.OriginalAdapter;697 698 /// <summary>699 /// This is the adapter that is used to resolve the base dotnet members for an700 /// adapted object. If an object is not adapted, this will be null.701 /// </summary>702 /// <remarks>703 /// If an object is not adapted, InternalAdapter will use the dotnet adapter.704 /// So there is no point falling back to the same dotnet adapter.705 ///706 /// If an object is adapted, this adapter will be used to resolve the dotnet707 /// members.708 /// </remarks>709 internal Adapter InternalBaseDotNetAdapter => InternalAdapterSet.DotNetAdapter;710 711 /// <summary>712 /// This is the adapter set that will contain the adapter of the baseObject713 /// and the ultimate .net member lookup adapter.714 /// See <see cref="PSObject.AdapterSet"/> for explanation.715 /// </summary>716 private AdapterSet InternalAdapterSet717 {718 get719 {720 if (_adapterSet == null)721 {722 lock (_lockObject)723 {724 _adapterSet ??= GetMappedAdapter(_immediateBaseObject, GetTypeTable());725 }726 }727 728 return _adapterSet;729 }730 }731 732 /// <summary>733 /// Gets the member collection.734 /// </summary>735 public PSMemberInfoCollection<PSMemberInfo> Members736 {737 get738 {739 if (_members == null)740 {741 lock (_lockObject)742 {743 _members ??= new PSMemberInfoIntegratingCollection<PSMemberInfo>(this, s_memberCollection);744 }745 }746 747 return _members;748 }749 }750 751 /// <summary>752 /// Gets the Property collection, or the members that are actually properties.753 /// </summary>754 public PSMemberInfoCollection<PSPropertyInfo> Properties755 {756 get757 {758 if (_properties == null)759 {760 lock (_lockObject)761 {762 _properties ??= new PSMemberInfoIntegratingCollection<PSPropertyInfo>(this, s_propertyCollection);763 }764 }765 766 return _properties;767 }768 }769 770 /// <summary>771 /// Gets the Method collection, or the members that are actually methods.772 /// </summary>773 public PSMemberInfoCollection<PSMethodInfo> Methods774 {775 get776 {777 if (_methods == null)778 {779 lock (_lockObject)780 {781 _methods ??= new PSMemberInfoIntegratingCollection<PSMethodInfo>(this, s_methodCollection);782 }783 }784 785 return _methods;786 }787 }788 789 /// <summary>790 /// Gets the object we are directly wrapping.791 /// </summary>792 /// <remarks>If the ImmediateBaseObject is another PSObject,793 /// that PSObject will be returned.</remarks>794 public object ImmediateBaseObject => _immediateBaseObject;795 796 /// <summary>797 /// Gets the object we are wrapping.798 /// </summary>799 /// <remarks>If the ImmediateBaseObject is another PSObject, this property800 /// will return its BaseObject.</remarks>801 public object BaseObject802 {803 get804 {805 object returnValue;806 PSObject mshObj = this;807 do808 {809 returnValue = mshObj._immediateBaseObject;810 mshObj = returnValue as PSObject;811 } while (mshObj != null);812 813 return returnValue;814 }815 }816 817 /// <summary>818 /// Gets the type names collection initially containing the object type hierarchy.819 /// </summary>820 public Collection<string> TypeNames821 {822 get823 {824 var result = InternalTypeNames;825 if (result.IsReadOnly)826 {827 lock (_lockObject)828 {829 // Check again after acquiring the lock to ensure some other thread didn't make the copy.830 if (result.IsReadOnly)831 {832 _typeNames = s_typeNamesResurrectionTable.GetValue(833 GetKeyForResurrectionTables(this),834 _ => new ConsolidatedString(_typeNames));835 836 object baseObj = BaseObject;837 // In most cases, the TypeNames will be modified after it's returned838 if (baseObj != null) { PSVariableAssignmentBinder.NoteTypeHasInstanceMemberOrTypeName(baseObj.GetType()); }839 840 return _typeNames;841 }842 }843 }844 845 return result;846 }847 }848 849 internal ConsolidatedString InternalTypeNames850 {851 get852 {853 if (_typeNames == null)854 {855 lock (_lockObject)856 {857 if (_typeNames == null)858 {859 if (!s_typeNamesResurrectionTable.TryGetValue(GetKeyForResurrectionTables(this), out _typeNames))860 {861 // We don't cache this typename in the resurrection table because it's cached in the psobject,862 // and the assumption is we'll usually get the value directly from the PSObject, so it's not863 // needed in the resurrection table.864 //865 // If we hand out the typename to a client that could change it (through the public property866 // TypeNames), then we'll need to store the copy in the resurrection table.867 _typeNames = InternalAdapter.BaseGetTypeNameHierarchy(_immediateBaseObject);868 }869 }870 }871 }872 873 return _typeNames;874 }875 876 set => _typeNames = value;877 }878 879 internal static ConsolidatedString GetTypeNames(object obj)880 {881 if (obj is PSObject psobj)882 {883 return psobj.InternalTypeNames;884 }885 886 if (HasInstanceTypeName(obj, out ConsolidatedString result))887 {888 return result;889 }890 891 return PSObject.GetMappedAdapter(obj, null).OriginalAdapter.BaseGetTypeNameHierarchy(obj);892 }893 894 internal static bool HasInstanceTypeName(object obj, out ConsolidatedString result)895 {896 return s_typeNamesResurrectionTable.TryGetValue(GetKeyForResurrectionTables(obj), out result);897 }898 899 #endregion properties900 901 #region static methods902 internal static bool HasInstanceMembers(object obj, out PSMemberInfoInternalCollection<PSMemberInfo> instanceMembers)903 {904 if (obj is PSObject psobj)905 {906 lock (psobj)907 {908 if (psobj._instanceMembers == null)909 {910 s_instanceMembersResurrectionTable.TryGetValue(GetKeyForResurrectionTables(psobj), out psobj._instanceMembers);911 }912 }913 914 instanceMembers = psobj._instanceMembers;915 }916 else if (obj != null)917 {918 s_instanceMembersResurrectionTable.TryGetValue(GetKeyForResurrectionTables(obj), out instanceMembers);919 }920 else921 {922 instanceMembers = null;923 }924 925 return instanceMembers != null && instanceMembers.Count > 0;926 }927 928 private static readonly ConditionalWeakTable<object, PSMemberInfoInternalCollection<PSMemberInfo>> s_instanceMembersResurrectionTable =929 new ConditionalWeakTable<object, PSMemberInfoInternalCollection<PSMemberInfo>>();930 931 /// <summary>932 /// </summary>933 /// <param name="valueToConvert"></param>934 /// <returns></returns>935 public static implicit operator PSObject(int valueToConvert)936 {937 return PSObject.AsPSObject(valueToConvert);938 }939 940 /// <summary>941 /// </summary>942 /// <param name="valueToConvert"></param>943 /// <returns></returns>944 public static implicit operator PSObject(string valueToConvert)945 {946 return PSObject.AsPSObject(valueToConvert);947 }948 949 /// <summary>950 /// </summary>951 /// <param name="valueToConvert"></param>952 /// <returns></returns>953 public static implicit operator PSObject(Hashtable valueToConvert)954 {955 return PSObject.AsPSObject(valueToConvert);956 }957 958 /// <summary>959 /// </summary>960 /// <param name="valueToConvert"></param>961 /// <returns></returns>962 public static implicit operator PSObject(double valueToConvert)963 {964 return PSObject.AsPSObject(valueToConvert);965 }966 967 /// <summary>968 /// </summary>969 /// <param name="valueToConvert"></param>970 /// <returns></returns>971 public static implicit operator PSObject(bool valueToConvert)972 {973 return PSObject.AsPSObject(valueToConvert);974 }975 976 /// <summary>977 /// If obj is not an PSObject, it is returned. Otherwise, retrieves978 /// the first non PSObject or PSObject with CustomBaseObject979 /// in the PSObject - BaseObject chain.980 /// </summary>981 internal static object Base(object obj)982 {983 if (obj is not PSObject mshObj)984 {985 return obj;986 }987 988 if (mshObj == AutomationNull.Value)989 return null;990 if (mshObj.ImmediateBaseObjectIsEmpty)991 {992 return obj;993 }994 995 object returnValue;996 do997 {998 returnValue = mshObj._immediateBaseObject;999 mshObj = returnValue as PSObject;1000 } while ((mshObj != null) && (!mshObj.ImmediateBaseObjectIsEmpty));1001 1002 return returnValue;1003 }1004 1005 internal static PSMemberInfo GetStaticCLRMember(object obj, string methodName)1006 {1007 obj = PSObject.Base(obj);1008 if (obj == null || methodName == null || methodName.Length == 0)1009 {1010 return null;1011 }1012 1013 var objType = obj as Type ?? obj.GetType();1014 return DotNetStaticAdapter.BaseGetMember<PSMemberInfo>(objType, methodName);1015 }1016 1017 /// <summary>1018 /// If obj is an PSObject it will be returned as is, otherwise1019 /// a new PSObject will be created based on obj.1020 /// </summary>1021 /// <param name="obj">Object to be wrapped.</param>1022 /// <returns>1023 /// obj or a new PSObject whose BaseObject is obj1024 /// </returns>1025 /// <exception cref="ArgumentNullException">If <paramref name="obj"/> is null.</exception>1026 [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "This is shipped as part of V1. Retaining this for backward compatibility.")]1027 public static PSObject AsPSObject(object obj)1028 {1029 return AsPSObject(obj, false);1030 }1031 1032 /// <summary>1033 /// If obj is a PSObject, it will be returned as is, otherwise a new1034 /// PSObject will be created on obj. Its InstanceMembers and TypeNames1035 /// will be initialized if we are not going to use the ResurrectionTables1036 /// for this PSObject instance.1037 /// </summary>1038 /// <param name="obj"></param>1039 /// <param name="storeTypeNameAndInstanceMembersLocally"></param>1040 /// <returns></returns>1041 [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "AsPSObject is shipped as part of V1. This is a new overload method.")]1042 internal static PSObject AsPSObject(object obj, bool storeTypeNameAndInstanceMembersLocally)1043 {1044 if (obj == null)1045 {1046 throw PSTraceSource.NewArgumentNullException(nameof(obj));1047 }1048 1049 if (obj is PSObject so)1050 {1051 return so;1052 }1053 1054 return new PSObject(obj) { StoreTypeNameAndInstanceMembersLocally = storeTypeNameAndInstanceMembersLocally };1055 }1056 1057 /// <summary>1058 /// Returns an object that should be used as a key for getting 1) instance members and 2) type names1059 /// - If base object is a PSCustomObject or a string or a type1060 /// then the most nested wrapping PSObject is returned (the PSObject where immediateBaseObject=PSCustomObject/string/type)1061 /// - Otherwise the base object is returned1062 /// This is a temporary fix for Win8 : 254345 - Job Failed By Throwing ExtendedTypeSystemException.1063 /// </summary>1064 /// <returns></returns>1065 internal static object GetKeyForResurrectionTables(object obj)1066 {1067 if (obj is not PSObject pso)1068 {1069 return obj;1070 }1071 1072 PSObject psObjectAboveBase = pso;1073 while (psObjectAboveBase.ImmediateBaseObject is PSObject)1074 {1075 psObjectAboveBase = (PSObject)psObjectAboveBase.ImmediateBaseObject;1076 }1077 1078 if (psObjectAboveBase.ImmediateBaseObject is PSCustomObject1079 || psObjectAboveBase.ImmediateBaseObject is string1080 || pso.StoreTypeNameAndInstanceMembersLocally)1081 {1082 return psObjectAboveBase;1083 }1084 1085 return psObjectAboveBase.ImmediateBaseObject;1086 }1087 1088 #endregion static methods1089 1090 #region instance methods1091 #region ToString1092 1093 private static string GetSeparator(ExecutionContext context, string separator)1094 {1095 if (separator != null)1096 {1097 return separator;1098 }1099 1100 object obj = context?.GetVariableValue(SpecialVariables.OFSVarPath);1101 if (obj != null)1102 {1103 return obj.ToString();1104 }1105 1106 return " ";1107 }1108 1109 internal static string ToStringEnumerator(ExecutionContext context, IEnumerator enumerator, string separator, string format, IFormatProvider formatProvider)1110 {1111 StringBuilder returnValue = new StringBuilder();1112 string separatorToUse = GetSeparator(context, separator);1113 while (enumerator.MoveNext())1114 {1115 object obj = enumerator.Current;1116 returnValue.Append(PSObject.ToString(context, obj, separator, format, formatProvider, false, false));1117 returnValue.Append(separatorToUse);1118 }1119 1120 if (returnValue.Length == 0)1121 {1122 return string.Empty;1123 }1124 1125 int separatorLength = separatorToUse.Length;1126 returnValue.Remove(returnValue.Length - separatorLength, separatorLength);1127 return returnValue.ToString();1128 }1129 1130 internal static string ToStringEnumerable(ExecutionContext context, IEnumerable enumerable, string separator, string format, IFormatProvider formatProvider)1131 {1132 StringBuilder returnValue = new StringBuilder();1133 string separatorToUse = GetSeparator(context, separator);1134 foreach (object obj in enumerable)1135 {1136 if (obj != null)1137 {1138 PSObject mshObj = PSObject.AsPSObject(obj);1139 returnValue.Append(PSObject.ToString(context, mshObj, separator, format, formatProvider, false, false));1140 }1141 1142 returnValue.Append(separatorToUse);1143 }1144 1145 if (returnValue.Length == 0)1146 {1147 return string.Empty;1148 }1149 1150 int separatorLength = separatorToUse.Length;1151 returnValue.Remove(returnValue.Length - separatorLength, separatorLength);1152 return returnValue.ToString();1153 }1154 1155 private static string ToStringEmptyBaseObject(ExecutionContext context, PSObject mshObj, string separator, string format, IFormatProvider formatProvider)1156 {1157 StringBuilder returnValue = new StringBuilder("@{");1158 bool isFirst = true;1159 foreach (PSPropertyInfo property in mshObj.Properties)1160 {1161 if (!isFirst)1162 {1163 returnValue.Append("; ");1164 }1165 1166 isFirst = false;1167 returnValue.Append(property.Name);1168 returnValue.Append('=');1169 1170 // Don't evaluate script properties during a ToString() operation.1171 var propertyValue = property is PSScriptProperty ? property.GetType().FullName : property.Value;1172 1173 returnValue.Append(PSObject.ToString(context, propertyValue, separator, format, formatProvider, false, false));1174 }1175 1176 if (isFirst)1177 {1178 return string.Empty;1179 }1180 1181 returnValue.Append('}');1182 return returnValue.ToString();1183 }1184 1185 /// <summary>1186 /// Returns the string representation of obj.1187 /// </summary>1188 /// <param name="context">ExecutionContext used to fetch the separator.</param>1189 /// <param name="obj">1190 /// object we are trying to call ToString on. If this is not an PSObject we try1191 /// enumerating and if that fails we call obj.ToString.1192 /// If this is an PSObject, we look for a brokered ToString.1193 /// If it is not present, and the BaseObject is null we try listing the properties.1194 /// If the BaseObject is not null we try enumerating. If that fails we try the BaseObject's ToString.1195 /// </param>1196 /// <returns>A string representation of the object.</returns>1197 /// <exception cref="ExtendedTypeSystemException">1198 /// When there is a brokered ToString but it failed, or when the ToString on obj throws an exception.1199 /// </exception>1200 internal static string ToStringParser(ExecutionContext context, object obj)