MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.Globalization;8using System.Management.Automation;9using System.Reflection;10 11using Microsoft.Management.Infrastructure;12 13using Dbg = System.Management.Automation.Diagnostics;14 15namespace Microsoft.PowerShell.Cim16{17 /// <summary>18 /// Adapter that deals with CimInstance objects.19 /// </summary>20 /// <remarks>21 /// Implementing the PropertyOnlyAdapter for the time being as CimInstanceTypeAdapter currently22 /// supports only properties. If method support is needed in future, this should derive from23 /// Adapter class.24 /// </remarks>25 public sealed class CimInstanceAdapter : PSPropertyAdapter26 {27 private static PSAdaptedProperty GetCimPropertyAdapter(CimProperty property, object baseObject, string propertyName)28 {29 PSAdaptedProperty propertyToAdd = new(propertyName, property);30 propertyToAdd.baseObject = baseObject;31 // propertyToAdd.adapter = this;32 return propertyToAdd;33 }34 35 private static PSAdaptedProperty GetCimPropertyAdapter(CimProperty property, object baseObject)36 {37 try38 {39 string propertyName = property.Name;40 return GetCimPropertyAdapter(property, baseObject, propertyName);41 }42 catch (CimException)43 {44 // ignore "Name" property access failures and move on.45 return null;46 }47 }48 49 private static PSAdaptedProperty GetPSComputerNameAdapter(CimInstance cimInstance)50 {51 PSAdaptedProperty psComputerNameProperty = new(RemotingConstants.ComputerNameNoteProperty, cimInstance);52 psComputerNameProperty.baseObject = cimInstance;53 // psComputerNameProperty.adapter = this;54 return psComputerNameProperty;55 }56 57 /// <summary>58 /// </summary>59 /// <param name="baseObject"></param>60 /// <returns></returns>61 public override System.Collections.ObjectModel.Collection<PSAdaptedProperty> GetProperties(object baseObject)62 {63 // baseObject should never be null64 if (baseObject is not CimInstance cimInstance)65 {66 string msg = string.Format(CultureInfo.InvariantCulture,67 CimInstanceTypeAdapterResources.BaseObjectNotCimInstance,68 "baseObject",69 typeof(CimInstance).ToString());70 throw new PSInvalidOperationException(msg);71 }72 73 Collection<PSAdaptedProperty> result = new();74 75 if (cimInstance.CimInstanceProperties != null)76 {77 foreach (CimProperty property in cimInstance.CimInstanceProperties)78 {79 PSAdaptedProperty propertyToAdd = GetCimPropertyAdapter(property, baseObject);80 if (propertyToAdd != null)81 {82 result.Add(propertyToAdd);83 }84 }85 }86 87 PSAdaptedProperty psComputerNameProperty = GetPSComputerNameAdapter(cimInstance);88 if (psComputerNameProperty != null)89 {90 result.Add(psComputerNameProperty);91 }92 93 return result;94 }95 96 /// <summary>97 /// </summary>98 /// <param name="baseObject"></param>99 /// <param name="propertyName"></param>100 /// <returns></returns>101 public override PSAdaptedProperty GetProperty(object baseObject, string propertyName)102 {103 if (propertyName == null)104 {105 throw new PSArgumentNullException(nameof(propertyName));106 }107 108 // baseObject should never be null109 if (baseObject is not CimInstance cimInstance)110 {111 string msg = string.Format(CultureInfo.InvariantCulture,112 CimInstanceTypeAdapterResources.BaseObjectNotCimInstance,113 "baseObject",114 typeof(CimInstance).ToString());115 throw new PSInvalidOperationException(msg);116 }117 118 CimProperty cimProperty = cimInstance.CimInstanceProperties[propertyName];119 if (cimProperty != null)120 {121 PSAdaptedProperty prop = GetCimPropertyAdapter(cimProperty, baseObject, propertyName);122 return prop;123 }124 125 if (propertyName.Equals(RemotingConstants.ComputerNameNoteProperty, StringComparison.OrdinalIgnoreCase))126 {127 PSAdaptedProperty prop = GetPSComputerNameAdapter(cimInstance);128 return prop;129 }130 131 return null;132 }133 134 /// <inheritdoc/>135 public override PSAdaptedProperty GetFirstPropertyOrDefault(object baseObject, MemberNamePredicate predicate)136 {137 if (predicate == null)138 {139 throw new PSArgumentNullException(nameof(predicate));140 }141 142 // baseObject should never be null143 if (baseObject is not CimInstance cimInstance)144 {145 string msg = string.Format(146 CultureInfo.InvariantCulture,147 CimInstanceTypeAdapterResources.BaseObjectNotCimInstance,148 "baseObject",149 typeof(CimInstance).ToString());150 throw new PSInvalidOperationException(msg);151 }152 153 if (predicate(RemotingConstants.ComputerNameNoteProperty))154 {155 PSAdaptedProperty prop = GetPSComputerNameAdapter(cimInstance);156 return prop;157 }158 159 foreach (CimProperty cimProperty in cimInstance.CimInstanceProperties)160 {161 if (cimProperty != null && predicate(cimProperty.Name))162 {163 PSAdaptedProperty prop = GetCimPropertyAdapter(cimProperty, baseObject, cimProperty.Name);164 return prop;165 }166 }167 168 return null;169 }170 171 internal static string CimTypeToTypeNameDisplayString(CimType cimType)172 {173 switch (cimType)174 {175 case CimType.DateTime:176 case CimType.Instance:177 case CimType.Reference:178 case CimType.DateTimeArray:179 case CimType.InstanceArray:180 case CimType.ReferenceArray:181 return "CimInstance#" + cimType.ToString();182 183 default:184 return ToStringCodeMethods.Type(185 CimConverter.GetDotNetType(cimType));186 }187 }188 189 /// <summary>190 /// </summary>191 /// <param name="adaptedProperty"></param>192 /// <returns></returns>193 public override string GetPropertyTypeName(PSAdaptedProperty adaptedProperty)194 {195 ArgumentNullException.ThrowIfNull(adaptedProperty);196 197 if (adaptedProperty.Tag is CimProperty cimProperty)198 {199 return CimTypeToTypeNameDisplayString(cimProperty.CimType);200 }201 202 if (adaptedProperty.Name.Equals(RemotingConstants.ComputerNameNoteProperty, StringComparison.OrdinalIgnoreCase))203 {204 return ToStringCodeMethods.Type(typeof(string));205 }206 207 throw new ArgumentNullException(nameof(adaptedProperty));208 }209 210 /// <summary>211 /// </summary>212 /// <param name="adaptedProperty"></param>213 /// <returns></returns>214 public override object GetPropertyValue(PSAdaptedProperty adaptedProperty)215 {216 ArgumentNullException.ThrowIfNull(adaptedProperty);217 218 if (adaptedProperty.Tag is CimProperty cimProperty)219 {220 return cimProperty.Value;221 }222 223 if (adaptedProperty.Name.Equals(RemotingConstants.ComputerNameNoteProperty, StringComparison.OrdinalIgnoreCase))224 {225 CimInstance cimInstance = (CimInstance)adaptedProperty.Tag;226 return cimInstance.GetCimSessionComputerName();227 }228 229 throw new ArgumentNullException(nameof(adaptedProperty));230 }231 232 private static void AddTypeNameHierarchy(IList<string> typeNamesWithNamespace, IList<string> typeNamesWithoutNamespace, string namespaceName, string className)233 {234 if (!string.IsNullOrEmpty(namespaceName))235 {236 string fullTypeName = string.Create(CultureInfo.InvariantCulture, $"Microsoft.Management.Infrastructure.CimInstance#{namespaceName}/{className}");237 typeNamesWithNamespace.Add(fullTypeName);238 }239 240 typeNamesWithoutNamespace.Add(string.Create(CultureInfo.InvariantCulture, $"Microsoft.Management.Infrastructure.CimInstance#{className}"));241 }242 243 private static List<CimClass> GetInheritanceChain(CimInstance cimInstance)244 {245 List<CimClass> inheritanceChain = new();246 CimClass cimClass = cimInstance.CimClass;247 Dbg.Assert(cimClass != null, "CimInstance should always have ClassDecl");248 while (cimClass != null)249 {250 inheritanceChain.Add(cimClass);251 try252 {253 cimClass = cimClass.CimSuperClass;254 }255 catch (CimException)256 {257 break;258 }259 }260 261 return inheritanceChain;262 }263 264 /// <summary>265 /// </summary>266 /// <param name="baseObject"></param>267 /// <returns></returns>268 public override Collection<string> GetTypeNameHierarchy(object baseObject)269 {270 if (baseObject is not CimInstance cimInstance)271 {272 throw new ArgumentNullException(nameof(baseObject));273 }274 275 var typeNamesWithNamespace = new List<string>();276 var typeNamesWithoutNamespace = new List<string>();277 278 IList<CimClass> inheritanceChain = GetInheritanceChain(cimInstance);279 if ((inheritanceChain == null) || (inheritanceChain.Count == 0))280 {281 AddTypeNameHierarchy(282 typeNamesWithNamespace,283 typeNamesWithoutNamespace,284 cimInstance.CimSystemProperties.Namespace,285 cimInstance.CimSystemProperties.ClassName);286 }287 else288 {289 foreach (CimClass cimClass in inheritanceChain)290 {291 AddTypeNameHierarchy(292 typeNamesWithNamespace,293 typeNamesWithoutNamespace,294 cimClass.CimSystemProperties.Namespace,295 cimClass.CimSystemProperties.ClassName);296 cimClass.Dispose();297 }298 }299 300 var result = new List<string>();301 result.AddRange(typeNamesWithNamespace);302 result.AddRange(typeNamesWithoutNamespace);303 304 if (baseObject != null)305 {306 for (Type type = baseObject.GetType(); type != null; type = type.BaseType)307 {308 result.Add(type.FullName);309 }310 }311 312 return new Collection<string>(result);313 }314 315 /// <summary>316 /// </summary>317 /// <param name="adaptedProperty"></param>318 /// <returns></returns>319 public override bool IsGettable(PSAdaptedProperty adaptedProperty)320 {321 /* I was explicitly asked to only use MI_FLAG_READONLY for now322 // based on DSP0004, version 2.6.0, section "5.5.3.41 Read" (page 85, lines 2881-2884)323 bool readQualifierValue = this.GetPropertyQualifierValue(adaptedProperty, "Read", defaultValue: true);324 return readQualifierValue;325 */326 return true;327 }328 329 /// <summary>330 /// </summary>331 /// <param name="adaptedProperty"></param>332 /// <returns></returns>333 public override bool IsSettable(PSAdaptedProperty adaptedProperty)334 {335 /* I was explicitly asked to only use MI_FLAG_READONLY for now336 // based on DSP0004, version 2.6.0, section "5.5.3.55 Write" (pages 89-90, lines 3056-3061)337 bool writeQualifierValue = this.GetPropertyQualifierValue(adaptedProperty, "Write", defaultValue: false);338 return writeQualifierValue;339 */340 341 if (adaptedProperty == null)342 {343 return false;344 }345 346 if (adaptedProperty.Tag is not CimProperty cimProperty)347 {348 return false;349 }350 351 bool isReadOnly = ((cimProperty.Flags & CimFlags.ReadOnly) == CimFlags.ReadOnly);352 bool isSettable = !isReadOnly;353 return isSettable;354 }355 356 /// <summary>357 /// </summary>358 /// <param name="adaptedProperty"></param>359 /// <param name="value"></param>360 public override void SetPropertyValue(PSAdaptedProperty adaptedProperty, object value)361 {362 ArgumentNullException.ThrowIfNull(adaptedProperty);363 364 if (!IsSettable(adaptedProperty))365 {366 throw new SetValueException("ReadOnlyCIMProperty",367 null,368 CimInstanceTypeAdapterResources.ReadOnlyCIMProperty,369 adaptedProperty.Name);370 }371 372 CimProperty cimProperty = adaptedProperty.Tag as CimProperty;373 object valueToSet = value;374 if (valueToSet != null)375 {376 // Convert only if value is not null377 Type paramType;378 switch (cimProperty.CimType)379 {380 case CimType.DateTime:381 paramType = typeof(object);382 break;383 case CimType.DateTimeArray:384 paramType = typeof(object[]);385 break;386 default:387 paramType = CimConverter.GetDotNetType(cimProperty.CimType);388 Dbg.Assert(paramType != null, "'default' case should only be used for well-defined CimType->DotNetType conversions");389 break;390 }391 392 valueToSet = Adapter.PropertySetAndMethodArgumentConvertTo(393 value, paramType, CultureInfo.InvariantCulture);394 }395 396 cimProperty.Value = valueToSet;397 return;398 }399 }400}401 