Ejemplo n.º 1
0
        private static void HandleErrorDataAdding(object sender, DataAddingEventArgs e)
        {
            HostSettingCommandMetadata commandMetadata;

            CommandMetadataTable.TryGetValue(e.PowerShellInstanceId, out commandMetadata);

            if (commandMetadata != null)
            {
                PowerShellInvocation_ErrorAdding(sender, e, commandMetadata);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Execution of PowerShell value activity.
        /// PowerShell expression will be evaluated using PowerShell runspace and the value of Type T will be returned.
        /// </summary>
        /// <param name="context"></param>
        protected override void Execute(NativeActivityContext context)
        {
            Token[]        tokens;
            ParseError[]   errors;
            ScriptBlockAst exprAst = Parser.ParseInput(Expression, out tokens, out errors);

            bool hasErrorActionPreference = false;
            bool hasWarningPreference     = false;
            bool hasInformationPreference = false;

            // Custom activity participant tracker for updating debugger with current variables and sequence stop points.
            // Regex looks for debugger sequence points like: Expression="'3:5:WFFunc1'".
            // We specifically disallow TimeSpan values that look like sequence points: Expression="'00:00:01'".
            bool isDebugSequencePoint = (!string.IsNullOrEmpty(Expression) && (System.Text.RegularExpressions.Regex.IsMatch(Expression, @"^'\d+:\d+:\S+'$")) &&
                                         (typeof(T) != typeof(System.TimeSpan)));
            var dataProperties = context.DataContext.GetProperties();

            if (isDebugSequencePoint || (dataProperties.Count > 0))
            {
                System.Activities.Tracking.CustomTrackingRecord customRecord = new System.Activities.Tracking.CustomTrackingRecord("PSWorkflowCustomUpdateDebugVariablesTrackingRecord");
                foreach (System.ComponentModel.PropertyDescriptor property in dataProperties)
                {
                    if (String.Equals(property.Name, "ParameterDefaults", StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    Object value = property.GetValue(context.DataContext);
                    if (value != null)
                    {
                        object tempValue = value;

                        PSDataCollection <PSObject> collectionObject = value as PSDataCollection <PSObject>;
                        if (collectionObject != null && collectionObject.Count == 1)
                        {
                            tempValue = collectionObject[0];
                        }

                        customRecord.Data.Add(property.Name, tempValue);
                    }
                }
                if (isDebugSequencePoint)
                {
                    customRecord.Data.Add("DebugSequencePoint", Expression);
                }
                context.Track(customRecord);
            }

            if (tokens != null)
            {
                foreach (Token token in tokens)
                {
                    VariableToken variable = token as VariableToken;

                    if (variable != null)
                    {
                        if (variable.Name.Equals("ErrorActionPreference", StringComparison.OrdinalIgnoreCase))
                        {
                            hasErrorActionPreference = true;
                        }
                        else if (variable.Name.Equals("WarningPreference", StringComparison.OrdinalIgnoreCase))
                        {
                            hasWarningPreference = true;
                        }
                        else if (variable.Name.Equals("InformationPreference", StringComparison.OrdinalIgnoreCase))
                        {
                            hasInformationPreference = true;
                        }
                    }
                }
            }

            if (string.IsNullOrEmpty(Expression))
            {
                throw new ArgumentException(ActivityResources.NullArgumentExpression);
            }


            if (_ci == null)
            {
                lock (syncroot)
                {
                    // Invoke using the CommandInfo for Invoke-Command directly, rather than going through
                    // command discovery (which is very slow).
                    if (_ci == null)
                    {
                        _ci = new CmdletInfo("Invoke-Command", typeof(Microsoft.PowerShell.Commands.InvokeCommandCommand));
                    }
                }
            }

            Collection <PSObject> returnedvalue;
            Runspace       runspace         = null;
            bool           borrowedRunspace = false;
            PSWorkflowHost workflowHost     = null;

            if (typeof(ScriptBlock).IsAssignableFrom(typeof(T)))
            {
                Result.Set(context, ScriptBlock.Create(Expression));
                return;
            }
            else if (typeof(ScriptBlock[]).IsAssignableFrom(typeof(T)))
            {
                Result.Set(context, new ScriptBlock[] { ScriptBlock.Create(Expression) });
                return;
            }

            PropertyDescriptorCollection col        = context.DataContext.GetProperties();
            HostParameterDefaults        hostValues = context.GetExtension <HostParameterDefaults>();

            // Borrow a runspace from the host if we're not trying to create a ScriptBlock.
            // If we are trying to create one, we need to keep it around so that it can be
            // invoked multiple times.
            if (hostValues != null)
            {
                workflowHost = hostValues.Runtime;
                try
                {
                    runspace         = workflowHost.UnboundedLocalRunspaceProvider.GetRunspace(null, 0, 0);
                    borrowedRunspace = true;
                }
                catch (Exception)
                {
                    // it is fine to catch generic exception here
                    // if the local runspace provider does not give us
                    // a runspace we will create one locally (fallback)
                }
            }

            if (runspace == null)
            {
                // Not running with the PowerShell workflow host so directly create the runspace...
                runspace = RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault2());
                runspace.Open();
            }

            using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create())
            {
                try
                {
                    ps.Runspace = runspace;

                    // Subscribe to DataAdding on the error stream so that we can add position tracking information
                    if (hostValues != null)
                    {
                        HostSettingCommandMetadata sourceCommandMetadata = hostValues.HostCommandMetadata;

                        CommandMetadataTable.TryAdd(ps.InstanceId, sourceCommandMetadata);
                        ps.Streams.Error.DataAdding += HandleErrorDataAdding;
                    }

                    // First, set the variables from the host defaults
                    if ((hostValues != null) && (hostValues.Parameters != null))
                    {
                        if (hostValues.Parameters.ContainsKey("PSCurrentDirectory"))
                        {
                            string path = hostValues.Parameters["PSCurrentDirectory"] as string;
                            if (path != null)
                            {
                                ps.Runspace.SessionStateProxy.Path.SetLocation(path);
                            }
                        }

                        foreach (string hostDefault in hostValues.Parameters.Keys)
                        {
                            string mappedHostDefault = hostDefault;

                            if (hostDefault.Equals("ErrorAction", StringComparison.OrdinalIgnoreCase))
                            {
                                if (hasErrorActionPreference)
                                {
                                    mappedHostDefault = "ErrorActionPreference";
                                }
                                else
                                {
                                    continue;
                                }
                            }
                            else if (hostDefault.Equals("WarningAction", StringComparison.OrdinalIgnoreCase))
                            {
                                if (hasWarningPreference)
                                {
                                    mappedHostDefault = "WarningPreference";
                                }
                                else
                                {
                                    continue;
                                }
                            }
                            else if (hostDefault.Equals("InformationAction", StringComparison.OrdinalIgnoreCase))
                            {
                                if (hasInformationPreference)
                                {
                                    mappedHostDefault = "InformationPreference";
                                }
                                else
                                {
                                    continue;
                                }
                            }

                            object propertyValue = hostValues.Parameters[hostDefault];
                            if (propertyValue != null)
                            {
                                ps.Runspace.SessionStateProxy.PSVariable.Set(mappedHostDefault, propertyValue);
                            }
                        }
                    }

                    // Then, set the variables from the workflow
                    foreach (PropertyDescriptor p in col)
                    {
                        string name  = p.Name;
                        object value = p.GetValue(context.DataContext);

                        if (value != null)
                        {
                            object tempValue = value;

                            PSDataCollection <PSObject> collectionObject = value as PSDataCollection <PSObject>;

                            if (collectionObject != null && collectionObject.Count == 1)
                            {
                                tempValue = collectionObject[0];
                            }

                            ps.Runspace.SessionStateProxy.PSVariable.Set(name, tempValue);
                        }
                    }

                    ps.AddCommand(_ci).AddParameter("NoNewScope").AddParameter("ScriptBlock", ExpressionScriptBlock);


                    // If this needs to consume input, take it from the host stream.
                    PSDataCollection <PSObject> inputStream = null;
                    if (UseDefaultInput)
                    {
                        // Retrieve our host overrides
                        hostValues = context.GetExtension <HostParameterDefaults>();

                        if (hostValues != null)
                        {
                            Dictionary <string, object> incomingArguments = hostValues.Parameters;
                            if (incomingArguments.ContainsKey("Input"))
                            {
                                inputStream = incomingArguments["Input"] as PSDataCollection <PSObject>;
                            }
                        }
                    }

                    // Now invoke the pipeline
                    try
                    {
                        if (inputStream != null)
                        {
                            returnedvalue = ps.Invoke(inputStream);
                            inputStream.Clear();
                        }
                        else
                        {
                            returnedvalue = ps.Invoke();
                        }
                    }
                    catch (CmdletInvocationException cie)
                    {
                        if (cie.ErrorRecord != null && cie.ErrorRecord.Exception != null)
                        {
                            throw cie.InnerException;
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
                finally
                {
                    if (hostValues != null)
                    {
                        ps.Streams.Error.DataAdding -= HandleErrorDataAdding;
                        HostSettingCommandMetadata removedValue;
                        CommandMetadataTable.TryRemove(ps.InstanceId, out removedValue);
                    }

                    if (borrowedRunspace)
                    {
                        workflowHost.UnboundedLocalRunspaceProvider.ReleaseRunspace(runspace);
                    }
                    else
                    {
                        // This will be disposed  when the command is done with it.
                        runspace.Dispose();
                        runspace = null;
                    }
                }


                if (ps.Streams.Error != null && ps.Streams.Error.Count > 0)
                {
                    PSDataCollection <ErrorRecord> errorStream = null;

                    // Retrieve our host overrides
                    hostValues = context.GetExtension <HostParameterDefaults>();

                    if (hostValues != null)
                    {
                        Dictionary <string, object> incomingArguments = hostValues.Parameters;
                        if (incomingArguments.ContainsKey("PSError"))
                        {
                            errorStream = incomingArguments["PSError"] as PSDataCollection <ErrorRecord>;
                        }
                    }

                    if (errorStream != null && errorStream.IsOpen)
                    {
                        foreach (ErrorRecord record in ps.Streams.Error)
                        {
                            errorStream.Add(record);
                        }
                    }
                }

                T valueToReturn = default(T);
                if (returnedvalue != null && returnedvalue.Count > 0)
                {
                    try
                    {
                        if (returnedvalue.Count == 1)
                        {
                            if (returnedvalue[0] != null)
                            {
                                Object result     = returnedvalue[0];
                                Object baseObject = ((PSObject)result).BaseObject;
                                if (!(baseObject is PSCustomObject))
                                {
                                    result = baseObject;
                                }

                                // Try regular PowerShell conversion
                                valueToReturn = LanguagePrimitives.ConvertTo <T>(result);
                            }
                        }
                        else
                        {
                            valueToReturn = LanguagePrimitives.ConvertTo <T>(returnedvalue);
                        }
                    }
                    catch (PSInvalidCastException)
                    {
                        // Handle the special case of emitting a PSDataCollection - use its array constructor.
                        // This special case is why we aren't using PowerShell.Invoke<T>
                        if (typeof(T) == typeof(PSDataCollection <PSObject>))
                        {
                            Object tempValueToReturn = new PSDataCollection <PSObject>(
                                new List <PSObject> {
                                LanguagePrimitives.ConvertTo <PSObject>(returnedvalue[0])
                            });
                            valueToReturn = (T)tempValueToReturn;
                        }
                        else
                        {
                            throw;
                        }
                    }

                    Result.Set(context, valueToReturn);
                }
            }
        }