/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Management.Automation; using System.Reflection; namespace Microsoft.Rest.ClientRuntime.PowerShell { internal static class PsExtensions { public static PSObject AddMultipleTypeNameIntoPSObject(this object obj, string multipleTag = "#Multiple") { var psObj = new PSObject(obj); psObj.TypeNames.Insert(0, $"{psObj.TypeNames[0]}{multipleTag}"); return psObj; } // https://stackoverflow.com/a/863944/294804 // https://stackoverflow.com/a/4452598/294804 // https://stackoverflow.com/a/28701974/294804 // Note: This will unwrap nested collections, but we don't generate nested collections. public static Type Unwrap(this Type type) { if (type.IsArray) { return type.GetElementType().Unwrap(); } var typeInfo = type.GetTypeInfo(); if (typeInfo.IsGenericType && (typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>) || typeof(IEnumerable<>).IsAssignableFrom(type))) { return typeInfo.GetGenericArguments().First().Unwrap(); } return type; } // https://stackoverflow.com/a/863944/294804 private static bool IsSimple(this Type type) { var typeInfo = type.GetTypeInfo(); return typeInfo.IsPrimitive || typeInfo.IsEnum || type == typeof(string) || type == typeof(decimal); } // https://stackoverflow.com/a/32025393/294804 private static bool HasImplicitConversion(this Type baseType, Type targetType) => baseType.GetMethods(BindingFlags.Public | BindingFlags.Static) .Where(mi => mi.Name == "op_Implicit" && mi.ReturnType == targetType) .Any(mi => mi.GetParameters().FirstOrDefault()?.ParameterType == baseType); public static bool IsPsSimple(this Type type) { var unwrappedType = type.Unwrap(); return unwrappedType.IsSimple() || unwrappedType == typeof(SwitchParameter) || unwrappedType == typeof(Hashtable) || unwrappedType == typeof(PSCredential) || unwrappedType == typeof(ScriptBlock) || unwrappedType == typeof(DateTime) || unwrappedType == typeof(Uri) || unwrappedType.HasImplicitConversion(typeof(string)); } public static string ToPsList(this IEnumerable items) => String.Join(", ", items.Select(i => $"'{i}'")); public static IEnumerable ToAliasNames(this IEnumerable attributes) => attributes.OfType().SelectMany(aa => aa.AliasNames).Distinct(); public static bool IsArrayAndElementTypeIsT(this object item) { var itemType = item.GetType(); var tType = typeof(T); return itemType.IsArray && !tType.IsArray && tType.IsAssignableFrom(itemType.GetElementType()); } public static bool IsTArrayAndElementTypeIsItem(this object item) { var itemType = item.GetType(); var tType = typeof(T); return !itemType.IsArray && tType.IsArray && (tType.GetElementType()?.IsAssignableFrom(itemType) ?? false); } public static bool IsTypeOrArrayOfType(this object item) => item is T || item.IsArrayAndElementTypeIsT() || item.IsTArrayAndElementTypeIsItem(); public static T NormalizeArrayType(this object item) { if (item is T result) { return result; } if (item.IsArrayAndElementTypeIsT()) { var array = (T[])Convert.ChangeType(item, typeof(T[])); return array.FirstOrDefault(); } if (item.IsTArrayAndElementTypeIsItem()) { var tType = typeof(T); var array = Array.CreateInstance(tType.GetElementType(), 1); array.SetValue(item, 0); return (T)Convert.ChangeType(array, tType); } return default(T); } public static T GetNestedProperty(this PSObject psObject, params string[] names) => psObject.Properties.GetNestedProperty(names); public static T GetNestedProperty(this PSMemberInfoCollection properties, params string[] names) { var lastName = names.Last(); var nestedProperties = names.Take(names.Length - 1).Aggregate(properties, (p, n) => p?.GetProperty(n)?.Properties); return nestedProperties != null ? nestedProperties.GetProperty(lastName) : default(T); } public static T GetProperty(this PSObject psObject, string name) => psObject.Properties.GetProperty(name); public static T GetProperty(this PSMemberInfoCollection properties, string name) { switch (properties[name]?.Value) { case PSObject psObject when psObject.BaseObject is PSCustomObject && psObject.ImmediateBaseObject.IsTypeOrArrayOfType(): return psObject.ImmediateBaseObject.NormalizeArrayType(); case PSObject psObject when psObject.BaseObject.IsTypeOrArrayOfType(): return psObject.BaseObject.NormalizeArrayType(); case object value when value.IsTypeOrArrayOfType(): return value.NormalizeArrayType(); default: return default(T); } } public static IEnumerable RunScript(this PSCmdlet cmdlet, string script) => PsHelpers.RunScript(cmdlet.InvokeCommand, script); public static void RunScript(this PSCmdlet cmdlet, string script) => cmdlet.RunScript(script); public static IEnumerable RunScript(this EngineIntrinsics engineIntrinsics, string script) => PsHelpers.RunScript(engineIntrinsics.InvokeCommand, script); public static void RunScript(this EngineIntrinsics engineIntrinsics, string script) => engineIntrinsics.RunScript(script); public static IEnumerable RunScript(this PSCmdlet cmdlet, ScriptBlock block) => PsHelpers.RunScript(cmdlet.InvokeCommand, block.ToString()); public static void RunScript(this PSCmdlet cmdlet, ScriptBlock block) => cmdlet.RunScript(block.ToString()); public static IEnumerable RunScript(this EngineIntrinsics engineIntrinsics, ScriptBlock block) => PsHelpers.RunScript(engineIntrinsics.InvokeCommand, block.ToString()); public static void RunScript(this EngineIntrinsics engineIntrinsics, ScriptBlock block) => engineIntrinsics.RunScript(block.ToString()); /// /// Returns if a parameter should be hidden by checking for . /// /// A PowerShell parameter. public static bool IsHidden(this Parameter parameter) { return parameter.Attributes.Any(attr => attr is DoNotExportAttribute); } } }