/// <summary> /// Execute the given cmdlet in powershell with the given parameters after injecting the given exception. It is expected that the cmdlet has a runtime that can be used for receiving output /// </summary> /// <typeparam name="T"></typeparam> /// <param name="cmdlet">The cmdlet to execute</param> /// <param name="name">The name of the cmdlet</param> /// <param name="exception">The exception to inject into the error stream</param> /// <param name="cmdletParameters">The parameters to pass to the cmdlet on the pipeline</param> public static void ExecuteCmdletWithExceptionInPipeline <T>(this PSCmdlet cmdlet, string name, Exception exception, params KeyValuePair <string, object>[] cmdletParameters) { List <T> output = new List <T>(); using (System.Management.Automation.PowerShell powershell = System.Management.Automation.PowerShell.Create(RunspaceMode.NewRunspace)) { var info = new CmdletInfo(name, cmdlet.GetType()); powershell.AddCommand("Write-Error"); powershell.AddParameter("Exception", exception); powershell.Invoke(); powershell.Commands.Clear(); powershell.AddCommand(info); foreach (var pair in cmdletParameters) { if (pair.Value == null) { powershell.AddParameter(pair.Key); } else { powershell.AddParameter(pair.Key, pair.Value); } } Collection <T> result = powershell.Invoke <T>(); powershell.Streams.Error.ForEach(cmdlet.WriteError); powershell.Streams.Debug.ForEach(d => cmdlet.WriteDebug(d.Message)); powershell.Streams.Verbose.ForEach(v => cmdlet.WriteWarning(v.Message)); powershell.Streams.Warning.ForEach(w => cmdlet.WriteWarning(w.Message)); if (result != null && result.Count > 0) { result.ForEach(r => cmdlet.WriteObject(r)); } } }
/// <summary> /// Gets all the properties declared on this class. /// </summary> /// <param name="cmdlet">The cmdlet to get the properties from</param> /// <param name="includeInherited">Whether or not to include inherited properties (defaults to true)</param> /// <returns>The properties that are defined on this cmdlet.</returns> internal static IEnumerable <PropertyInfo> GetProperties(this PSCmdlet cmdlet, bool includeInherited) { // Create the binding flags BindingFlags bindingFlags = BindingFlags.Instance | // ignore static/const properties BindingFlags.Public; // only include public properties if (!includeInherited) { bindingFlags |= BindingFlags.DeclaredOnly; // ignore inherited properties } // Get the properties on this cmdlet IEnumerable <PropertyInfo> result = cmdlet.GetType().GetProperties(bindingFlags); return(result); }
/// <summary> /// Execute the given cmdlet in powershell usign the given pipeline parameters. /// </summary> /// <typeparam name="T">The output type for the cmdlet</typeparam> /// <param name="cmdlet">The cmdlet to execute</param> /// <param name="name">The name of the cmdlet</param> /// <param name="cmdletParameters">The parameters to pass to the cmdlet on the pipeline</param> /// <returns>The output of executing the cmdlet</returns> public static List <T> ExecuteCmdletInPipeline <T>(this PSCmdlet cmdlet, string name, params object[] cmdletParameters) { List <T> output = new List <T>(); using (System.Management.Automation.PowerShell powershell = System.Management.Automation.PowerShell.Create(RunspaceMode.NewRunspace)) { var info = new CmdletInfo(name, cmdlet.GetType()); Collection <T> result = powershell.AddCommand(info).Invoke <T>(cmdletParameters); if (powershell.Streams.Error != null && powershell.Streams.Error.Count > 0) { StringBuilder details = new StringBuilder(); powershell.Streams.Error.ForEach(e => details.AppendFormat("Error: {0}\n", e.ToString())); throw new InvalidOperationException(string.Format("Errors while running cmdlet:\n {0}", details.ToString())); } if (result != null && result.Count > 0) { result.ForEach(output.Add); } } return(output); }
public static void RunCmdlet(this PSCmdlet cmdlet, string parameterSet, KeyValuePair <string, object[]>[] incomingValues) { var cmdletType = cmdlet.GetType(); parameterSetFieldInfo.SetValue(cmdlet, parameterSet); beginProcessingMethodInfo.Invoke(cmdlet, emptyParameters); var parameterProperties = incomingValues.Select(x => new Tuple <PropertyInfo, object[]>( cmdletType.GetProperty(x.Key), x.Value)).ToArray(); for (int i = 0; i < incomingValues[0].Value.Length; i++) { foreach (var parameter in parameterProperties) { parameter.Item1.SetValue(cmdlet, parameter.Item2[i], null); } processRecordMethodInfo.Invoke(cmdlet, emptyParameters); } endProcessingMethodInfo.Invoke(cmdlet, emptyParameters); }
internal static (T, bool) ApplySetParameters <T>(this PSCmdlet cmdlet, T dto) { var cmdletParams = cmdlet.GetType() .GetProperties() .Select(pi => new { Property = pi, SetParameter = pi.GetCustomAttribute <SetParameterAttribute>() }) .Where(p => p.SetParameter != null); var dtoProps = typeof(T).GetProperties(); var boundParams = cmdlet.MyInvocation.BoundParameters; var toApply = cmdletParams .Join(dtoProps, cp => cp.SetParameter.DtoProperty ?? cp.Property.Name, pi => pi.Name, (cp, pi) => new { Parameter = cp, DtoProperty = pi }) .Join(boundParams, cp => cp.Parameter.Property.Name, kv => kv.Key, (cp, kv) => new { cp.Parameter, cp.DtoProperty, kv.Value }); var anyChanges = false; foreach (var p in toApply) { var value = p.Value; var dtoPropertyType = p.DtoProperty.PropertyType; if (dtoPropertyType.IsGenericType && dtoPropertyType.GetGenericTypeDefinition() == typeof(Nullable <>)) { dtoPropertyType = Nullable.GetUnderlyingType(dtoPropertyType); } //Convert SwitchParameters to bool value if (value is SwitchParameter switchValue) { value = switchValue.ToBool(); } // Convert strings to enums if (dtoPropertyType.IsEnum && value is string stringValue) { value = Enum.Parse(p.DtoProperty.PropertyType, stringValue); } // Convert flag enums (turn on-off bits) if (dtoPropertyType.IsEnum && value is bool boolValue) { var names = Enum.GetNames(dtoPropertyType); var bits = Enum.GetValues(dtoPropertyType); var enumValueType = dtoPropertyType.GetEnumUnderlyingType(); var flagIndex = Array.IndexOf(names, p.Parameter.Property.Name); var flagValue = bits.GetValue(flagIndex); var currentValue = p.DtoProperty.GetValue(dto); // For arithmetic we need numerics var longValue = Convert.ToInt64(currentValue); var bitValue = Convert.ToInt64(flagValue); if (boolValue) { longValue |= bitValue; // turn the flag on } else { longValue &= ~bitValue; //turn the flag off } value = Enum.ToObject(dtoPropertyType, longValue); } p.DtoProperty.SetValue(dto, value); anyChanges = true; } return(dto, anyChanges); }
/// <summary> /// Use this method to build a standardized ID for error records returned to the user. /// </summary> /// <param name="cmdlet">The cmdlet executing at the time the error was encountered.</param> /// <param name="resourceTarget">The type of resources being operated on at the time the error occured</param> /// <param name="errorReason">The Reason the error occured. If no reason is provided then "UnknownError" will be used /// instead.</param> /// <returns>The standard error ID</returns> /// <remarks>The standard ID will be formatted as such: "AzureDevOpsMgmt.Cmdlet.{Resource Target Type}.{Cmdlet Class /// Name}.{Failure Reason}</remarks> public static string BuildStandardErrorId( this PSCmdlet cmdlet, DevOpsModelTarget resourceTarget, string errorReason = "UnknownError") => CmdletHelpers.BuildStandardErrorIdInternal( $"{resourceTarget.ToString()}.{cmdlet.GetType().Name}.{errorReason}");