mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
1266 lines
49 KiB
C#
1266 lines
49 KiB
C#
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License.
|
|
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Collections.Specialized;
|
|
using System.ComponentModel;
|
|
using System.Globalization;
|
|
using System.Management.Automation.Internal;
|
|
using System.Text;
|
|
|
|
using Microsoft.PowerShell;
|
|
|
|
using Dbg = System.Management.Automation.Diagnostics;
|
|
|
|
#pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings
|
|
|
|
namespace System.Management.Automation
|
|
{
|
|
/// <summary>
|
|
/// Deals with ManagementObject objects.
|
|
/// This is a base class that interacts with other entities.
|
|
/// </summary>
|
|
internal abstract class BaseWMIAdapter : Adapter
|
|
{
|
|
#region WMIMethodCacheEntry
|
|
|
|
/// <summary>
|
|
/// Method information is cached for every unique ManagementClassPath created/used.
|
|
/// This structure stores information such as MethodDefinition as displayed
|
|
/// by Get-Member cmdlet, original MethodData and computed method information such
|
|
/// as whether a method is static etc.
|
|
/// </summary>
|
|
internal class WMIMethodCacheEntry
|
|
{
|
|
public string Name { get; }
|
|
|
|
public string ClassPath { get; }
|
|
|
|
public MethodInformation MethodInfoStructure { get; }
|
|
|
|
public string MethodDefinition { get; }
|
|
|
|
internal WMIMethodCacheEntry(string n, string cPath, MethodData mData)
|
|
{
|
|
Name = n;
|
|
ClassPath = cPath;
|
|
MethodInfoStructure = ManagementObjectAdapter.GetMethodInformation(mData);
|
|
MethodDefinition = ManagementObjectAdapter.GetMethodDefinition(mData);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region WMIParameterInformation
|
|
|
|
internal class WMIParameterInformation : ParameterInformation
|
|
{
|
|
public string Name { get; }
|
|
|
|
public WMIParameterInformation(string name, Type ty) : base(ty, true, null, false)
|
|
{
|
|
Name = name;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Member related Overrides
|
|
|
|
/// <summary>
|
|
/// Returns the TypeNameHierarchy using the __Derivation SystemProperties
|
|
/// and dotnetBaseType.
|
|
/// </summary>
|
|
/// <param name="managementObj"></param>
|
|
/// <param name="dotnetBaseType"></param>
|
|
/// <param name="shouldIncludeNamespace"></param>
|
|
/// <returns></returns>
|
|
private IEnumerable<string> GetTypeNameHierarchyFromDerivation(ManagementBaseObject managementObj,
|
|
string dotnetBaseType, bool shouldIncludeNamespace)
|
|
{
|
|
StringBuilder type = new StringBuilder(200);
|
|
// give the typename based on NameSpace and Class
|
|
type.Append(dotnetBaseType);
|
|
type.Append("#");
|
|
if (shouldIncludeNamespace)
|
|
{
|
|
type.Append(managementObj.SystemProperties["__NAMESPACE"].Value);
|
|
type.Append("\\");
|
|
}
|
|
|
|
type.Append(managementObj.SystemProperties["__CLASS"].Value);
|
|
yield return type.ToString();
|
|
|
|
// Win8: 186792: PSTypeNames does not include full WMI class derivation
|
|
// From MSDN: __Derivation; Data type: CIM_STRING array
|
|
// Access type: Read-only for both instances and classes
|
|
// Class hierarchy of the current class or instance. The first element is
|
|
// the immediate parent class, the next is its parent, and so on; the last element
|
|
// is the base class.
|
|
PropertyData derivationData = managementObj.SystemProperties["__Derivation"];
|
|
if (derivationData != null)
|
|
{
|
|
Dbg.Assert(derivationData.IsArray, "__Derivation must be a string array as per MSDN documentation");
|
|
|
|
// give the typenames based on NameSpace + __Derivation
|
|
string[] typeHierarchy = PropertySetAndMethodArgumentConvertTo(derivationData.Value, typeof(string[]), CultureInfo.InvariantCulture) as string[];
|
|
if (typeHierarchy != null)
|
|
{
|
|
foreach (string t in typeHierarchy)
|
|
{
|
|
type.Clear();
|
|
type.Append(dotnetBaseType);
|
|
type.Append("#");
|
|
if (shouldIncludeNamespace)
|
|
{
|
|
type.Append(managementObj.SystemProperties["__NAMESPACE"].Value);
|
|
type.Append("\\");
|
|
}
|
|
|
|
type.Append(t);
|
|
yield return type.ToString();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the TypeNameHierarchy out of an ManagementBaseObject.
|
|
/// </summary>
|
|
/// <param name="obj">Object to get the TypeNameHierarchy from.</param>
|
|
/// <remarks>
|
|
/// TypeName is of the format ObjectType#__Namespace\\__Class
|
|
/// </remarks>
|
|
protected override IEnumerable<string> GetTypeNameHierarchy(object obj)
|
|
{
|
|
ManagementBaseObject managementObj = obj as ManagementBaseObject;
|
|
|
|
bool isLoopStarted = false;
|
|
foreach (string baseType in GetDotNetTypeNameHierarchy(obj))
|
|
{
|
|
if (!isLoopStarted)
|
|
{
|
|
isLoopStarted = true;
|
|
// Win8: 186792 Return the hierarchy using the __Derivation property as well
|
|
// as NameSpace + Class.
|
|
foreach (string typeFromDerivation in GetTypeNameHierarchyFromDerivation(managementObj, baseType, true))
|
|
{
|
|
yield return typeFromDerivation;
|
|
}
|
|
|
|
// without namespace
|
|
foreach (string typeFromDerivation in GetTypeNameHierarchyFromDerivation(managementObj, baseType, false))
|
|
{
|
|
yield return typeFromDerivation;
|
|
}
|
|
}
|
|
|
|
yield return baseType;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns null if memberName is not a member in the adapter or
|
|
/// the corresponding PSMemberInfo.
|
|
/// </summary>
|
|
/// <param name="obj">Object to retrieve the PSMemberInfo from.</param>
|
|
/// <param name="memberName">Name of the member to be retrieved.</param>
|
|
/// <returns>The PSMemberInfo corresponding to memberName from obj.</returns>
|
|
protected override T GetMember<T>(object obj, string memberName)
|
|
{
|
|
tracer.WriteLine("Getting member with name {0}", memberName);
|
|
|
|
ManagementBaseObject mgmtObject = obj as ManagementBaseObject;
|
|
|
|
if (mgmtObject == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
PSProperty property = DoGetProperty(mgmtObject, memberName);
|
|
|
|
if (typeof(T).IsAssignableFrom(typeof(PSProperty)) && property != null)
|
|
{
|
|
return property as T;
|
|
}
|
|
|
|
if (typeof(T).IsAssignableFrom(typeof(PSMethod)))
|
|
{
|
|
T returnValue = GetManagementObjectMethod<T>(mgmtObject, memberName);
|
|
// We only return a method if there is no property by the same name
|
|
// to match the behavior we have in GetMembers
|
|
if (returnValue != null && property == null)
|
|
{
|
|
return returnValue;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
protected override T GetFirstMemberOrDefault<T>(object obj, MemberNamePredicate predicate)
|
|
{
|
|
if (obj is ManagementBaseObject wmiObject)
|
|
{
|
|
return GetFirstOrDefaultProperty<T>(wmiObject, predicate)
|
|
?? GetFirstOrDefaultMethod<T>(wmiObject, predicate);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves all the members available in the object.
|
|
/// The adapter implementation is encouraged to cache all properties/methods available
|
|
/// in the first call to GetMember and GetMembers so that subsequent
|
|
/// calls can use the cache.
|
|
/// In the case of the .NET adapter that would be a cache from the .NET type to
|
|
/// the public properties and fields available in that type.
|
|
/// In the case of the DirectoryEntry adapter, this could be a cache of the objectClass
|
|
/// to the properties available in it.
|
|
/// </summary>
|
|
/// <param name="obj">Object to get all the member information from.</param>
|
|
/// <returns>All members in obj.</returns>
|
|
protected override PSMemberInfoInternalCollection<T> GetMembers<T>(object obj)
|
|
{
|
|
// obj should never be null
|
|
Diagnostics.Assert(obj != null, "Input object is null");
|
|
|
|
ManagementBaseObject wmiObject = (ManagementBaseObject)obj;
|
|
PSMemberInfoInternalCollection<T> returnValue = new PSMemberInfoInternalCollection<T>();
|
|
AddAllProperties<T>(wmiObject, returnValue);
|
|
AddAllMethods<T>(wmiObject, returnValue);
|
|
return returnValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called after a non null return from GetMember to try to call
|
|
/// the method with the arguments.
|
|
/// </summary>
|
|
/// <param name="method">The non empty return from GetMethods.</param>
|
|
/// <param name="arguments">The arguments to use.</param>
|
|
/// <returns>The return value for the method.</returns>
|
|
protected override object MethodInvoke(PSMethod method, object[] arguments)
|
|
{
|
|
ManagementObject mgmtObject = method.baseObject as ManagementObject;
|
|
Diagnostics.Assert(mgmtObject != null,
|
|
"Object is not of ManagementObject type");
|
|
|
|
WMIMethodCacheEntry methodEntry = (WMIMethodCacheEntry)method.adapterData;
|
|
|
|
return AuxillaryInvokeMethod(mgmtObject, methodEntry, arguments);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called after a non null return from GetMember to return the overloads.
|
|
/// </summary>
|
|
/// <param name="method">The return of GetMember.</param>
|
|
/// <returns></returns>
|
|
protected override Collection<string> MethodDefinitions(PSMethod method)
|
|
{
|
|
WMIMethodCacheEntry methodEntry = (WMIMethodCacheEntry)method.adapterData;
|
|
Collection<string> returnValue = new Collection<string>();
|
|
returnValue.Add(methodEntry.MethodDefinition);
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if the property is settable.
|
|
/// </summary>
|
|
/// <param name="property">Property to check.</param>
|
|
/// <returns>True if the property is settable.</returns>
|
|
protected override bool PropertyIsSettable(PSProperty property)
|
|
{
|
|
ManagementBaseObject mObj = property.baseObject as ManagementBaseObject;
|
|
try
|
|
{
|
|
ManagementClass objClass = CreateClassFrmObject(mObj);
|
|
return (bool)objClass.GetPropertyQualifierValue(property.Name, "Write");
|
|
}
|
|
catch (ManagementException)
|
|
{
|
|
// A property that lacks the Write qualifier may still be writeable.
|
|
// The provider implementation may allow any properties in the provider
|
|
// classes to be changed, whether the Write qualifier is present or not.
|
|
return true;
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
// A property that lacks the Write qualifier may still be writeable.
|
|
// The provider implementation may allow any properties in the provider
|
|
// classes to be changed, whether the Write qualifier is present or not.
|
|
return true;
|
|
}
|
|
catch (System.Runtime.InteropServices.COMException)
|
|
{
|
|
// A property that lacks the Write qualifier may still be writeable.
|
|
// The provider implementation may allow any properties in the provider
|
|
// classes to be changed, whether the Write qualifier is present or not.
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if the property is gettable.
|
|
/// </summary>
|
|
/// <param name="property">Property to check.</param>
|
|
/// <returns>True if the property is gettable.</returns>
|
|
protected override bool PropertyIsGettable(PSProperty property)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the name of the type corresponding to the property.
|
|
/// </summary>
|
|
/// <param name="property">PSProperty obtained in a previous DoGetProperty.</param>
|
|
/// <param name="forDisplay">True if the result is for display purposes only.</param>
|
|
/// <returns>The name of the type corresponding to the property.</returns>
|
|
protected override string PropertyType(PSProperty property, bool forDisplay)
|
|
{
|
|
PropertyData pd = property.adapterData as PropertyData;
|
|
// GetDotNetType will never return null
|
|
Type dotNetType = GetDotNetType(pd);
|
|
string typeName;
|
|
|
|
// Display Embedded object type name to
|
|
// assist users in passing appropriate
|
|
// object
|
|
if (pd.Type == CimType.Object)
|
|
{
|
|
typeName = GetEmbeddedObjectTypeName(pd);
|
|
|
|
if (pd.IsArray)
|
|
{
|
|
typeName += "[]";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
typeName = forDisplay ? ToStringCodeMethods.Type(dotNetType) : dotNetType.ToString();
|
|
}
|
|
|
|
return typeName;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the value from a property coming from a previous call to DoGetProperty.
|
|
/// </summary>
|
|
/// <param name="property">PSProperty coming from a previous call to DoGetProperty.</param>
|
|
/// <returns>The value of the property.</returns>
|
|
protected override object PropertyGet(PSProperty property)
|
|
{
|
|
PropertyData pd = property.adapterData as PropertyData;
|
|
return pd.Value;
|
|
}
|
|
/// <summary>
|
|
/// Sets the value of a property coming from a previous call to DoGetProperty.
|
|
/// This method will only set the property on a particular instance. If you want
|
|
/// to update the WMI store, call Put().
|
|
/// </summary>
|
|
/// <param name="property">PSProperty coming from a previous call to DoGetProperty.</param>
|
|
/// <param name="setValue">Value to set the property with.</param>
|
|
/// <param name="convertIfPossible">Instructs the adapter to convert before setting, if the adapter supports conversion.</param>
|
|
protected override void PropertySet(PSProperty property, object setValue, bool convertIfPossible)
|
|
{
|
|
ManagementBaseObject mObj = property.baseObject as ManagementBaseObject;
|
|
if (mObj == null)
|
|
{
|
|
throw new SetValueInvocationException("CannotSetNonManagementObjectMsg",
|
|
null,
|
|
ExtendedTypeSystem.CannotSetNonManagementObject,
|
|
property.Name, property.baseObject.GetType().FullName,
|
|
typeof(ManagementBaseObject).FullName);
|
|
}
|
|
|
|
if (!PropertyIsSettable(property))
|
|
{
|
|
throw new SetValueException("ReadOnlyWMIProperty",
|
|
null,
|
|
ExtendedTypeSystem.ReadOnlyProperty,
|
|
property.Name);
|
|
}
|
|
|
|
PropertyData pd = property.adapterData as PropertyData;
|
|
|
|
if ((convertIfPossible) && (setValue != null))
|
|
{
|
|
// Convert only if value is not null
|
|
Type paramType = GetDotNetType(pd);
|
|
setValue = PropertySetAndMethodArgumentConvertTo(
|
|
setValue, paramType, CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
pd.Value = setValue;
|
|
return;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the string representation of the property in the object.
|
|
/// </summary>
|
|
/// <param name="property">Property obtained in a previous GetMember.</param>
|
|
/// <returns>The string representation of the property in the object.</returns>
|
|
protected override string PropertyToString(PSProperty property)
|
|
{
|
|
StringBuilder returnValue = new StringBuilder();
|
|
// if (PropertyIsStatic(property))
|
|
// {
|
|
// returnValue.Append("static ");
|
|
// }
|
|
|
|
returnValue.Append(PropertyType(property, forDisplay: true));
|
|
returnValue.Append(" ");
|
|
returnValue.Append(property.Name);
|
|
returnValue.Append(" {");
|
|
if (PropertyIsGettable(property))
|
|
{
|
|
returnValue.Append("get;");
|
|
}
|
|
|
|
if (PropertyIsSettable(property))
|
|
{
|
|
returnValue.Append("set;");
|
|
}
|
|
|
|
returnValue.Append("}");
|
|
return returnValue.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns an array with the property attributes.
|
|
/// </summary>
|
|
/// <param name="property">Property we want the attributes from.</param>
|
|
/// <returns>An array with the property attributes.</returns>
|
|
protected override AttributeCollection PropertyAttributes(PSProperty property)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private/Internal Methods
|
|
|
|
/// <summary>
|
|
/// Retrieves the table for instance methods.
|
|
/// </summary>
|
|
/// <param name="wmiObject">Object containing methods to load in typeTable.</param>
|
|
/// <param name="staticBinding">Controls what methods are adapted.</param>
|
|
protected static CacheTable GetInstanceMethodTable(ManagementBaseObject wmiObject,
|
|
bool staticBinding)
|
|
{
|
|
lock (s_instanceMethodCacheTable)
|
|
{
|
|
CacheTable typeTable = null;
|
|
|
|
// unique identifier for identifying this ManagementObject's type
|
|
ManagementPath classPath = wmiObject.ClassPath;
|
|
string key = string.Format(CultureInfo.InvariantCulture, "{0}#{1}", classPath.Path, staticBinding.ToString());
|
|
|
|
typeTable = (CacheTable)s_instanceMethodCacheTable[key];
|
|
if (typeTable != null)
|
|
{
|
|
tracer.WriteLine("Returning method information from internal cache");
|
|
return typeTable;
|
|
}
|
|
|
|
tracer.WriteLine("Method information not found in internal cache. Constructing one");
|
|
|
|
try
|
|
{
|
|
// try to populate method table..if there is any exception
|
|
// generating the method metadata..suppress the exception
|
|
// but dont store the info in the cache. This is to allow
|
|
// for method look up again in future (after the wmi object
|
|
// is fixed)
|
|
typeTable = new CacheTable();
|
|
// Construct a ManagementClass object for this object to get the member metadata
|
|
ManagementClass mgmtClass = wmiObject as ManagementClass ?? CreateClassFrmObject(wmiObject);
|
|
PopulateMethodTable(mgmtClass, typeTable, staticBinding);
|
|
s_instanceMethodCacheTable[key] = typeTable;
|
|
}
|
|
catch (ManagementException)
|
|
{
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
}
|
|
catch (System.Runtime.InteropServices.COMException)
|
|
{
|
|
}
|
|
|
|
return typeTable;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Populates methods of a ManagementClass in a CacheTable.
|
|
/// </summary>
|
|
/// <param name="mgmtClass">Class to get the method info from.</param>
|
|
/// <param name="methodTable">Cachetable to update.</param>
|
|
/// <param name="staticBinding">Controls what methods are adapted.</param>
|
|
/// <exception cref="UnauthorizedAccessException"></exception>
|
|
/// <exception cref="ManagementException"></exception>
|
|
private static void PopulateMethodTable(ManagementClass mgmtClass, CacheTable methodTable, bool staticBinding)
|
|
{
|
|
Dbg.Assert(mgmtClass != null, "ManagementClass cannot be null in this method");
|
|
MethodDataCollection mgmtMethods = mgmtClass.Methods;
|
|
if (mgmtMethods != null)
|
|
{
|
|
ManagementPath classPath = mgmtClass.ClassPath;
|
|
// new operation will never fail
|
|
foreach (MethodData mdata in mgmtMethods)
|
|
{
|
|
// is method static
|
|
bool isStatic = IsStaticMethod(mdata);
|
|
if (isStatic == staticBinding)
|
|
{
|
|
// a method is added depending on
|
|
// whether staticBinding is requested or not.
|
|
string methodName = mdata.Name;
|
|
WMIMethodCacheEntry mCache = new WMIMethodCacheEntry(methodName, classPath.Path, mdata);
|
|
methodTable.Add(methodName, mCache);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructs a ManagementClass object from the supplied mgmtBaseObject.
|
|
/// ManagementObject has scope, options, path which need to be carried over to the ManagementClass for
|
|
/// retrieving method/property/parameter metadata.
|
|
/// </summary>
|
|
/// <param name="mgmtBaseObject"></param>
|
|
/// <returns></returns>
|
|
private static ManagementClass CreateClassFrmObject(ManagementBaseObject mgmtBaseObject)
|
|
{
|
|
// Construct a ManagementClass object for this object to get the member metadata
|
|
ManagementClass mgmtClass = mgmtBaseObject as ManagementClass;
|
|
|
|
// try to use the actual object sent to this method..otherwise construct one
|
|
if (mgmtClass == null)
|
|
{
|
|
mgmtClass = new ManagementClass(mgmtBaseObject.ClassPath);
|
|
|
|
// inherit ManagementObject properties
|
|
ManagementObject mgmtObject = mgmtBaseObject as ManagementObject;
|
|
if (mgmtObject != null)
|
|
{
|
|
mgmtClass.Scope = mgmtObject.Scope;
|
|
mgmtClass.Options = mgmtObject.Options;
|
|
}
|
|
}
|
|
|
|
return mgmtClass;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the object type associated with a CimType:object.
|
|
/// </summary>
|
|
/// <param name="pData">PropertyData representing a parameter.</param>
|
|
/// <returns>
|
|
/// typeof(object)#EmbeddedObjectTypeName if one found
|
|
/// typeof(object) otherwise
|
|
/// </returns>
|
|
/// <remarks>
|
|
/// This helps users of WMI in identifying exactly what type
|
|
/// the underlying WMI provider will accept.
|
|
/// </remarks>
|
|
protected static string GetEmbeddedObjectTypeName(PropertyData pData)
|
|
{
|
|
string result = typeof(object).FullName;
|
|
|
|
if (pData == null)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
try
|
|
{
|
|
string cimType = (string)pData.Qualifiers["cimtype"].Value;
|
|
result = string.Format(CultureInfo.InvariantCulture, "{0}#{1}",
|
|
typeof(ManagementObject).FullName, cimType.Replace("object:", string.Empty));
|
|
}
|
|
catch (ManagementException)
|
|
{
|
|
}
|
|
catch (System.Runtime.InteropServices.COMException)
|
|
{
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the dotnet type of a given PropertyData.
|
|
/// </summary>
|
|
/// <param name="pData">PropertyData input.</param>
|
|
/// <returns>A string representing dotnet type.</returns>
|
|
protected static Type GetDotNetType(PropertyData pData)
|
|
{
|
|
Diagnostics.Assert(pData != null,
|
|
"Input PropertyData should not be null");
|
|
|
|
tracer.WriteLine("Getting DotNet Type for CimType : {0}", pData.Type);
|
|
|
|
string retValue;
|
|
switch (pData.Type)
|
|
{
|
|
case CimType.SInt8:
|
|
retValue = typeof(System.SByte).FullName;
|
|
break;
|
|
case CimType.UInt8:
|
|
retValue = typeof(System.Byte).FullName;
|
|
break;
|
|
case CimType.SInt16:
|
|
retValue = typeof(System.Int16).FullName;
|
|
break;
|
|
case CimType.UInt16:
|
|
retValue = typeof(System.UInt16).FullName;
|
|
break;
|
|
case CimType.SInt32:
|
|
retValue = typeof(System.Int32).FullName;
|
|
break;
|
|
case CimType.UInt32:
|
|
retValue = typeof(System.UInt32).FullName;
|
|
break;
|
|
case CimType.SInt64:
|
|
retValue = typeof(System.Int64).FullName;
|
|
break;
|
|
case CimType.UInt64:
|
|
retValue = typeof(System.UInt64).FullName;
|
|
break;
|
|
case CimType.Real32:
|
|
retValue = typeof(System.Single).FullName;
|
|
break;
|
|
case CimType.Real64:
|
|
retValue = typeof(double).FullName;
|
|
break;
|
|
case CimType.Boolean:
|
|
retValue = typeof(bool).FullName;
|
|
break;
|
|
case CimType.String:
|
|
retValue = typeof(string).FullName;
|
|
break;
|
|
case CimType.DateTime:
|
|
// this is actually a string
|
|
retValue = typeof(string).FullName;
|
|
break;
|
|
case CimType.Reference:
|
|
// this is actually a string
|
|
retValue = typeof(string).FullName;
|
|
break;
|
|
case CimType.Char16:
|
|
retValue = typeof(char).FullName;
|
|
break;
|
|
case CimType.Object:
|
|
default:
|
|
retValue = typeof(object).FullName;
|
|
break;
|
|
}
|
|
|
|
if (pData.IsArray)
|
|
{
|
|
retValue += "[]";
|
|
}
|
|
|
|
return Type.GetType(retValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks whether a given MethodData is static or not.
|
|
/// </summary>
|
|
/// <param name="mdata"></param>
|
|
/// <returns>
|
|
/// true, if static
|
|
/// </returns>
|
|
/// <remarks>
|
|
/// This method relies on the qualifier "static"
|
|
/// </remarks>
|
|
protected static bool IsStaticMethod(MethodData mdata)
|
|
{
|
|
try
|
|
{
|
|
QualifierData staticQualifier = mdata.Qualifiers["static"];
|
|
if (staticQualifier == null)
|
|
return false;
|
|
|
|
bool result = false;
|
|
LanguagePrimitives.TryConvertTo<bool>(staticQualifier.Value, out result);
|
|
|
|
return result;
|
|
}
|
|
catch (ManagementException)
|
|
{
|
|
}
|
|
catch (System.Runtime.InteropServices.COMException)
|
|
{
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private object AuxillaryInvokeMethod(ManagementObject obj, WMIMethodCacheEntry mdata, object[] arguments)
|
|
{
|
|
// Evaluate method and arguments
|
|
object[] verifiedArguments;
|
|
|
|
MethodInformation[] methods = new MethodInformation[1];
|
|
methods[0] = mdata.MethodInfoStructure;
|
|
|
|
// This will convert Null Strings to Empty Strings
|
|
GetBestMethodAndArguments(mdata.Name, methods, arguments, out verifiedArguments);
|
|
|
|
ParameterInformation[] parameterList = mdata.MethodInfoStructure.parameters;
|
|
|
|
// GetBestMethodAndArguments should fill verifiedArguments with
|
|
// correct values (even if some values are not specified)
|
|
tracer.WriteLine("Parameters found {0}. Arguments supplied {0}",
|
|
parameterList.Length, verifiedArguments.Length);
|
|
|
|
Diagnostics.Assert(parameterList.Length == verifiedArguments.Length,
|
|
"The number of parameters and arguments should match");
|
|
|
|
// we should not cache inParameters as we are updating
|
|
// inParameters object with argument values..Caching will
|
|
// have side effects in this scenario like we have to clear
|
|
// the values once the method is invoked.
|
|
// Also caching MethodData occupies lot of memory compared to
|
|
// caching string.
|
|
ManagementClass mClass = CreateClassFrmObject(obj);
|
|
ManagementBaseObject inParameters = mClass.GetMethodParameters(mdata.Name);
|
|
|
|
for (int i = 0; i < parameterList.Length; i++)
|
|
{
|
|
// this cast should always succeed
|
|
WMIParameterInformation pInfo = (WMIParameterInformation)parameterList[i];
|
|
|
|
// Should not convert null input arguments
|
|
// GetBestMethodAndArguments converts null strings to empty strings
|
|
// and also null ints to 0. But WMI providers do not like these
|
|
// conversions. So dont convert input arguments if they are null.
|
|
// We could have done this in the base adapter but the change would be
|
|
// costly for other adapters which dont mind the conversion.
|
|
if ((i < arguments.Length) && (arguments[i] == null))
|
|
{
|
|
verifiedArguments[i] = null;
|
|
}
|
|
|
|
inParameters[pInfo.Name] = verifiedArguments[i];
|
|
}
|
|
|
|
return InvokeManagementMethod(obj, mdata.Name, inParameters);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decode parameter information from the supplied object.
|
|
/// </summary>
|
|
/// <param name="parameters">A ManagementBaseObject describing the parameters.</param>
|
|
/// <param name="parametersList">A sorted list to store parameter information.</param>
|
|
/// <remarks>
|
|
/// Should not throw exceptions
|
|
/// </remarks>
|
|
internal static void UpdateParameters(ManagementBaseObject parameters,
|
|
SortedList parametersList)
|
|
{
|
|
// ManagementObject class do not populate parameters when there are none.
|
|
if (parameters == null)
|
|
return;
|
|
|
|
foreach (PropertyData data in parameters.Properties)
|
|
{
|
|
// parameter position..
|
|
int location = -1;
|
|
WMIParameterInformation pInfo = new WMIParameterInformation(data.Name, GetDotNetType(data));
|
|
|
|
try
|
|
{
|
|
location = (int)data.Qualifiers["ID"].Value;
|
|
}
|
|
catch (ManagementException)
|
|
{
|
|
// If there is an exception accessing location
|
|
// add the parameter to the end.
|
|
}
|
|
catch (System.Runtime.InteropServices.COMException)
|
|
{
|
|
// If there is an exception accessing location
|
|
// add the parameter to the end.
|
|
}
|
|
|
|
if (location < 0)
|
|
{
|
|
location = parametersList.Count;
|
|
}
|
|
|
|
parametersList[location] = pInfo;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets WMI method information.
|
|
/// </summary>
|
|
/// <param name="mData"></param>
|
|
/// <returns></returns>
|
|
/// <remarks>
|
|
/// Decodes only input parameters.
|
|
/// </remarks>
|
|
internal static MethodInformation GetMethodInformation(MethodData mData)
|
|
{
|
|
Diagnostics.Assert(mData != null, "MethodData should not be null");
|
|
|
|
// Get Method parameters
|
|
SortedList parameters = new SortedList();
|
|
UpdateParameters(mData.InParameters, parameters);
|
|
|
|
// parameters is never null
|
|
WMIParameterInformation[] pInfos = new WMIParameterInformation[parameters.Count];
|
|
if (parameters.Count > 0)
|
|
{
|
|
parameters.Values.CopyTo(pInfos, 0);
|
|
}
|
|
|
|
MethodInformation returnValue = new MethodInformation(false, true, pInfos);
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
internal static string GetMethodDefinition(MethodData mData)
|
|
{
|
|
// gather parameter information for this method.
|
|
// input and output parameters reside in 2 different groups..
|
|
// we dont know the order they appear on the arguments line..
|
|
SortedList parameters = new SortedList();
|
|
UpdateParameters(mData.InParameters, parameters);
|
|
|
|
StringBuilder inParameterString = new StringBuilder();
|
|
|
|
if (parameters.Count > 0)
|
|
{
|
|
foreach (WMIParameterInformation parameter in parameters.Values)
|
|
{
|
|
string typeName = parameter.parameterType.ToString();
|
|
|
|
PropertyData pData = mData.InParameters.Properties[parameter.Name];
|
|
if (pData.Type == CimType.Object)
|
|
{
|
|
typeName = GetEmbeddedObjectTypeName(pData);
|
|
|
|
if (pData.IsArray)
|
|
{
|
|
typeName += "[]";
|
|
}
|
|
}
|
|
|
|
inParameterString.Append(typeName);
|
|
inParameterString.Append(" ");
|
|
inParameterString.Append(parameter.Name);
|
|
inParameterString.Append(", ");
|
|
}
|
|
}
|
|
|
|
if (inParameterString.Length > 2)
|
|
{
|
|
inParameterString.Remove(inParameterString.Length - 2, 2);
|
|
}
|
|
|
|
tracer.WriteLine("Constructing method definition for method {0}", mData.Name);
|
|
StringBuilder builder = new StringBuilder();
|
|
|
|
builder.Append("System.Management.ManagementBaseObject ");
|
|
builder.Append(mData.Name);
|
|
builder.Append("(");
|
|
builder.Append(inParameterString.ToString());
|
|
builder.Append(")");
|
|
|
|
string returnValue = builder.ToString();
|
|
tracer.WriteLine("Definition constructed: {0}", returnValue);
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Abstract Methods
|
|
|
|
/// <summary>
|
|
/// Retrieves all the properties available in the object.
|
|
/// </summary>
|
|
/// <param name="wmiObject">Object to get all the property information from.</param>
|
|
/// <param name="members">Collection where the members will be added.</param>
|
|
protected abstract void AddAllProperties<T>(ManagementBaseObject wmiObject,
|
|
PSMemberInfoInternalCollection<T> members) where T : PSMemberInfo;
|
|
|
|
/// <summary>
|
|
/// Adds method information of the ManagementObject. This is done by accessing
|
|
/// the ManagementClass corresponding to this ManagementObject. All the method
|
|
/// information is cached for a particular ManagementObject.
|
|
/// </summary>
|
|
/// <typeparam name="T">PSMemberInfo</typeparam>
|
|
/// <param name="wmiObject">Object for which the members need to be retrieved.</param>
|
|
/// <param name="members">Method information is added to this.</param>
|
|
protected abstract void AddAllMethods<T>(ManagementBaseObject wmiObject,
|
|
PSMemberInfoInternalCollection<T> members) where T : PSMemberInfo;
|
|
|
|
protected abstract object InvokeManagementMethod(ManagementObject wmiObject,
|
|
string methodName, ManagementBaseObject inParams);
|
|
|
|
/// <summary>
|
|
/// Get a method object given method name.
|
|
/// </summary>
|
|
/// <typeparam name="T">PSMemberInfo</typeparam>
|
|
/// <param name="wmiObject">Object for which the method is required.</param>
|
|
/// <param name="methodName">Name of the method.</param>
|
|
/// <returns>
|
|
/// PsMemberInfo if method exists.
|
|
/// Null otherwise.
|
|
/// </returns>
|
|
protected abstract T GetManagementObjectMethod<T>(ManagementBaseObject wmiObject,
|
|
string methodName) where T : PSMemberInfo;
|
|
|
|
/// <summary>
|
|
/// Returns null if propertyName is not a property in the adapter or
|
|
/// the corresponding PSProperty with its adapterData set to information
|
|
/// to be used when retrieving the property.
|
|
/// </summary>
|
|
/// <param name="wmiObject">Object to retrieve the PSProperty from.</param>
|
|
/// <param name="propertyName">Name of the property to be retrieved.</param>
|
|
/// <returns>The PSProperty corresponding to propertyName from obj.</returns>
|
|
protected abstract PSProperty DoGetProperty(ManagementBaseObject wmiObject,
|
|
string propertyName);
|
|
|
|
/// <summary>
|
|
/// Returns the first property whose name matches the specified <see cref="MemberNamePredicate"/>
|
|
/// </summary>
|
|
protected abstract T GetFirstOrDefaultProperty<T>(ManagementBaseObject wmiObject, MemberNamePredicate predicate) where T : PSMemberInfo;
|
|
|
|
/// <summary>
|
|
/// Returns the first method whose name matches the specified <see cref="MemberNamePredicate"/>
|
|
/// </summary>
|
|
protected abstract T GetFirstOrDefaultMethod<T>(ManagementBaseObject wmiObject, MemberNamePredicate predicate) where T : PSMemberInfo;
|
|
|
|
#endregion
|
|
|
|
#region Private Data
|
|
|
|
private static HybridDictionary s_instanceMethodCacheTable = new HybridDictionary();
|
|
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deals with ManagementClass objects.
|
|
/// Adapts only static methods and SystemProperties of a
|
|
/// ManagementClass object.
|
|
/// </summary>
|
|
internal class ManagementClassApdapter : BaseWMIAdapter
|
|
{
|
|
protected override void AddAllProperties<T>(ManagementBaseObject wmiObject,
|
|
PSMemberInfoInternalCollection<T> members)
|
|
{
|
|
if (wmiObject.SystemProperties != null)
|
|
{
|
|
foreach (PropertyData property in wmiObject.SystemProperties)
|
|
{
|
|
members.Add(new PSProperty(property.Name, this, wmiObject, property) as T);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override PSProperty DoGetProperty(ManagementBaseObject wmiObject, string propertyName)
|
|
{
|
|
if (wmiObject.SystemProperties != null)
|
|
{
|
|
foreach (PropertyData property in wmiObject.SystemProperties)
|
|
{
|
|
if (propertyName.Equals(property.Name, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return new PSProperty(property.Name, this, wmiObject, property);
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes method represented by <paramref name="mdata"/> using supplied arguments.
|
|
/// </summary>
|
|
/// <param name="wmiObject">ManagementObject on which the method is invoked.</param>
|
|
/// <param name="methodName">Method data.</param>
|
|
/// <param name="inParams">Method arguments.</param>
|
|
/// <returns></returns>
|
|
protected override object InvokeManagementMethod(ManagementObject wmiObject,
|
|
string methodName, ManagementBaseObject inParams)
|
|
{
|
|
tracer.WriteLine("Invoking class method: {0}", methodName);
|
|
|
|
ManagementClass mClass = wmiObject as ManagementClass;
|
|
|
|
try
|
|
{
|
|
return mClass.InvokeMethod(methodName, inParams, null);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
throw new MethodInvocationException(
|
|
"WMIMethodException",
|
|
e,
|
|
ExtendedTypeSystem.WMIMethodInvocationException,
|
|
methodName, e.Message);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds method information of the ManagementClass. Only static methods are added for
|
|
/// an object of type ManagementClass.
|
|
/// </summary>
|
|
/// <typeparam name="T">PSMemberInfo</typeparam>
|
|
/// <param name="wmiObject">Object for which the members need to be retrieved.</param>
|
|
/// <param name="members">Method information is added to this.</param>
|
|
protected override void AddAllMethods<T>(ManagementBaseObject wmiObject,
|
|
PSMemberInfoInternalCollection<T> members)
|
|
{
|
|
Diagnostics.Assert((wmiObject != null) && (members != null),
|
|
"Input arguments should not be null.");
|
|
|
|
if (!typeof(T).IsAssignableFrom(typeof(PSMethod)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
CacheTable table;
|
|
table = GetInstanceMethodTable(wmiObject, true);
|
|
|
|
foreach (WMIMethodCacheEntry methodEntry in table.memberCollection)
|
|
{
|
|
if (members[methodEntry.Name] == null)
|
|
{
|
|
tracer.WriteLine("Adding method {0}", methodEntry.Name);
|
|
members.Add(new PSMethod(methodEntry.Name, this, wmiObject, methodEntry) as T);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns method information for a ManagementClass method.
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="wmiObject"></param>
|
|
/// <param name="methodName"></param>
|
|
/// <returns>
|
|
/// PSMethod if method exists and is static. Null otherwise.
|
|
/// </returns>
|
|
protected override T GetManagementObjectMethod<T>(ManagementBaseObject wmiObject, string methodName)
|
|
{
|
|
if (!typeof(T).IsAssignableFrom(typeof(PSMethod)))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
CacheTable typeTable = GetInstanceMethodTable(wmiObject, true);
|
|
WMIMethodCacheEntry method = (WMIMethodCacheEntry)typeTable[methodName];
|
|
|
|
if (method == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return new PSMethod(method.Name, this, wmiObject, method) as T;
|
|
}
|
|
|
|
protected override T GetFirstOrDefaultProperty<T>(ManagementBaseObject wmiObject, MemberNamePredicate predicate)
|
|
{
|
|
if (!typeof(T).IsAssignableFrom(typeof(PSProperty)))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (wmiObject.SystemProperties != null)
|
|
{
|
|
foreach (PropertyData property in wmiObject.SystemProperties)
|
|
{
|
|
if (predicate(property.Name))
|
|
{
|
|
return new PSProperty(property.Name, this, wmiObject, property) as T;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
protected override T GetFirstOrDefaultMethod<T>(ManagementBaseObject wmiObject, MemberNamePredicate predicate)
|
|
{
|
|
if (!typeof(T).IsAssignableFrom(typeof(PSMethod)))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
CacheTable table = GetInstanceMethodTable(wmiObject, true);
|
|
foreach (WMIMethodCacheEntry methodEntry in table.memberCollection)
|
|
{
|
|
if (predicate(methodEntry.Name))
|
|
{
|
|
return new PSMethod(methodEntry.Name, this, wmiObject, methodEntry) as T;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deals with ManagementObject objects.
|
|
/// This class do not adapt static methods.
|
|
/// </summary>
|
|
internal class ManagementObjectAdapter : ManagementClassApdapter
|
|
{
|
|
protected override void AddAllProperties<T>(ManagementBaseObject wmiObject,
|
|
PSMemberInfoInternalCollection<T> members)
|
|
{
|
|
// Add System properties
|
|
base.AddAllProperties(wmiObject, members);
|
|
|
|
if (wmiObject.Properties != null)
|
|
{
|
|
foreach (PropertyData property in wmiObject.Properties)
|
|
{
|
|
members.Add(new PSProperty(property.Name, this, wmiObject, property) as T);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override PSProperty DoGetProperty(ManagementBaseObject wmiObject, string propertyName)
|
|
{
|
|
PropertyData adapterData = null;
|
|
|
|
// First check whether we have any Class properties by this name
|
|
PSProperty returnValue = base.DoGetProperty(wmiObject, propertyName);
|
|
|
|
if (returnValue != null)
|
|
{
|
|
return returnValue;
|
|
}
|
|
|
|
try
|
|
{
|
|
adapterData = wmiObject.Properties[propertyName];
|
|
return new PSProperty(adapterData.Name, this, wmiObject, adapterData);
|
|
}
|
|
catch (ManagementException)
|
|
{
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
// TODO: Bug 251457. This is a workaround to unblock partners and find out the root cause.
|
|
Tracing.PSEtwLogProvider provider = new Tracing.PSEtwLogProvider();
|
|
|
|
provider.WriteEvent(PSEventId.Engine_Health,
|
|
PSChannel.Analytic,
|
|
PSOpcode.Exception,
|
|
PSLevel.Informational,
|
|
PSTask.None,
|
|
PSKeyword.UseAlwaysOperational,
|
|
string.Format(CultureInfo.InvariantCulture,
|
|
"ManagementBaseObjectAdapter::DoGetProperty::PropertyName:{0}, Exception:{1}, StackTrace:{2}",
|
|
propertyName, e.Message, e.StackTrace),
|
|
string.Empty,
|
|
string.Empty);
|
|
// ignore the exception.
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes method represented by <paramref name="mdata"/> using supplied arguments.
|
|
/// </summary>
|
|
/// <param name="obj">ManagementObject on which the method is invoked.</param>
|
|
/// <param name="methodName">Method data.</param>
|
|
/// <param name="inParams">Method arguments.</param>
|
|
/// <returns></returns>
|
|
protected override object InvokeManagementMethod(ManagementObject obj, string methodName, ManagementBaseObject inParams)
|
|
{
|
|
tracer.WriteLine("Invoking class method: {0}", methodName);
|
|
|
|
try
|
|
{
|
|
ManagementBaseObject robj = obj.InvokeMethod(methodName, inParams, null);
|
|
return robj;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
throw new MethodInvocationException(
|
|
"WMIMethodException",
|
|
e,
|
|
ExtendedTypeSystem.WMIMethodInvocationException,
|
|
methodName, e.Message);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds method information of the ManagementObject. Only instance methods are added for
|
|
/// a ManagementObject.
|
|
/// </summary>
|
|
/// <typeparam name="T">PSMemberInfo</typeparam>
|
|
/// <param name="wmiObject">Object for which the members need to be retrieved.</param>
|
|
/// <param name="members">Method information is added to this.</param>
|
|
protected override void AddAllMethods<T>(ManagementBaseObject wmiObject,
|
|
PSMemberInfoInternalCollection<T> members)
|
|
{
|
|
Diagnostics.Assert((wmiObject != null) && (members != null),
|
|
"Input arguments should not be null.");
|
|
|
|
if (!typeof(T).IsAssignableFrom(typeof(PSMethod)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
CacheTable table;
|
|
table = GetInstanceMethodTable(wmiObject, false);
|
|
|
|
foreach (WMIMethodCacheEntry methodEntry in table.memberCollection)
|
|
{
|
|
if (members[methodEntry.Name] == null)
|
|
{
|
|
tracer.WriteLine("Adding method {0}", methodEntry.Name);
|
|
members.Add(new PSMethod(methodEntry.Name, this, wmiObject, methodEntry) as T);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns method information for a ManagementObject method.
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="wmiObject"></param>
|
|
/// <param name="methodName"></param>
|
|
/// <returns>
|
|
/// PSMethod if method exists and is not static. Null otherwise.
|
|
/// </returns>
|
|
protected override T GetManagementObjectMethod<T>(ManagementBaseObject wmiObject, string methodName)
|
|
{
|
|
if (!typeof(T).IsAssignableFrom(typeof(PSMethod)))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
CacheTable typeTable;
|
|
WMIMethodCacheEntry method;
|
|
|
|
typeTable = GetInstanceMethodTable(wmiObject, false);
|
|
method = (WMIMethodCacheEntry)typeTable[methodName];
|
|
|
|
if (method == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return new PSMethod(method.Name, this, wmiObject, method) as T;
|
|
}
|
|
}
|
|
}
|