/// <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);
        }
示例#4
0
        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}");