From 580fb7baf5aad7bce9a0278e705be06695df9f2e Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 16 Aug 2017 17:35:36 -0700 Subject: [PATCH] Remove src\Microsoft.PowerShell.Activities (#4582) --- .../Activities/ActivityGenerator.cs | 795 -- .../GetCimAssociatedInstanceActivity.cs | 135 - .../Activities/GetCimClassActivity.cs | 131 - .../Activities/GetCimInstanceActivity.cs | 177 - .../Activities/GetPSWorkflowData.cs | 338 - .../Activities/InlineScript.cs | 812 -- .../Activities/InlineScriptDesigner.xaml.cs | 35 - .../Activities/InvokeCimMethodActivity.cs | 170 - .../Activities/IsArgumentSet.cs | 41 - .../Activities/NewCimInstanceActivity.cs | 163 - .../Activities/NewCimSessionActivity.cs | 148 - .../Activities/NewCimSessionOptionActivity.cs | 286 - .../Activities/PSPersist.cs | 43 - .../Activities/Pipeline.cs | 296 - .../Activities/PipelineDesigner.xaml.cs | 23 - .../Activities/PowerShellValue.cs | 564 -- .../Activities/RemoveCimInstanceActivity.cs | 120 - .../Activities/SetCimInstanceActivity.cs | 148 - .../Activities/SetHostValue.cs | 602 -- .../Activities/ThrottledParallelForeach.cs | 130 - .../Activities/WmiActivities.cs | 242 - .../Activities/WorkflowJobConverter.cs | 8151 ----------------- .../AssemblyInfo.cs | 25 - .../Xamls/InlineScriptDesigner.xaml | 38 - .../Xamls/PipelineDesigner.xaml | 37 - .../resources/ActivityResources.resx | 561 -- 26 files changed, 14211 deletions(-) delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/ActivityGenerator.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/GetCimAssociatedInstanceActivity.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/GetCimClassActivity.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/GetCimInstanceActivity.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/GetPSWorkflowData.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/InlineScript.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/InlineScriptDesigner.xaml.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/InvokeCimMethodActivity.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/IsArgumentSet.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/NewCimInstanceActivity.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/NewCimSessionActivity.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/NewCimSessionOptionActivity.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/PSPersist.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/Pipeline.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/PipelineDesigner.xaml.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/PowerShellValue.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/RemoveCimInstanceActivity.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/SetCimInstanceActivity.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/SetHostValue.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/ThrottledParallelForeach.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/WmiActivities.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Activities/WorkflowJobConverter.cs delete mode 100644 src/Microsoft.PowerShell.Activities/AssemblyInfo.cs delete mode 100644 src/Microsoft.PowerShell.Activities/Xamls/InlineScriptDesigner.xaml delete mode 100644 src/Microsoft.PowerShell.Activities/Xamls/PipelineDesigner.xaml delete mode 100644 src/Microsoft.PowerShell.Activities/resources/ActivityResources.resx diff --git a/src/Microsoft.PowerShell.Activities/Activities/ActivityGenerator.cs b/src/Microsoft.PowerShell.Activities/Activities/ActivityGenerator.cs deleted file mode 100644 index 1657310a3..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/ActivityGenerator.cs +++ /dev/null @@ -1,795 +0,0 @@ -// -// Copyright (C) Microsoft. All rights reserved. -// -using System; -using System.Management.Automation; -using System.Management.Automation.Runspaces; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Reflection; -using Microsoft.CSharp; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using Microsoft.PowerShell.Cmdletization; -using Microsoft.PowerShell.Cmdletization.Xml; -using System.Xml; -using System.Xml.Serialization; -using System.Xml.Schema; -using System.CodeDom.Compiler; -using System.CodeDom; - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Generates an activity that corresponds to a PowerShell command - /// - public static class ActivityGenerator - { - private static readonly Lazy xmlSerializer = new Lazy(ConstructXmlSerializer); - private static readonly Lazy xmlReaderSettings = new Lazy(ConstructXmlReaderSettings); - - static XmlSerializer ConstructXmlSerializer() - { - XmlSerializer xmlSerializer = new Microsoft.PowerShell.Cmdletization.Xml.PowerShellMetadataSerializer(); - return xmlSerializer; - } - - static XmlReaderSettings ConstructXmlReaderSettings() - { - // - // XmlReaderSettings - // - XmlReaderSettings result = new XmlReaderSettings(); - // general settings - result.CheckCharacters = true; - result.CloseInput = false; - result.ConformanceLevel = ConformanceLevel.Document; - result.IgnoreComments = true; - result.IgnoreProcessingInstructions = true; - result.IgnoreWhitespace = false; - result.MaxCharactersFromEntities = 16384; // generous guess for the upper bound - result.MaxCharactersInDocument = 128 * 1024 * 1024; // generous guess for the upper bound - result.DtdProcessing = DtdProcessing.Parse; // Allowing DTD parsing with limits of MaxCharactersFromEntities/MaxCharactersInDocument - result.XmlResolver = null; // do not fetch external documents - // xsd schema related settings - result.ValidationFlags = XmlSchemaValidationFlags.ProcessIdentityConstraints | - XmlSchemaValidationFlags.ReportValidationWarnings; - result.ValidationType = ValidationType.Schema; - string cmdletizationXsd = ActivityResources.Xml_cmdletsOverObjectsXsd; - XmlReader cmdletizationSchemaReader = XmlReader.Create(new StringReader(cmdletizationXsd), result); - result.Schemas = new XmlSchemaSet(); - result.Schemas.Add(null, cmdletizationSchemaReader); - result.Schemas.XmlResolver = null; // do not fetch external documents - - return result; - } - - static string templateCommand = @" -using Microsoft.PowerShell.Activities; -using System.Management.Automation; -using System.Activities; -using System.Collections.Generic; -using System.ComponentModel; - - -namespace {0} -{{ - /// - /// Activity to invoke the {1} command in a Workflow. - /// - [System.CodeDom.Compiler.GeneratedCode(""Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromName"", ""3.0"")] - public sealed class {2} : {6} - {{ - /// - /// Gets the display name of the command invoked by this activity. - /// - public {2}() - {{ - this.DisplayName = ""{8}""; - }} - - /// - /// Gets the fully qualified name of the command invoked by this activity. - /// - public override string PSCommandName {{ get {{ return ""{4}""; }} }} - - // Arguments - {3} - - // Module defining this command - {7} - - // Optional custom code for this activity - {9} - - /// - /// Returns a configured instance of System.Management.Automation.PowerShell, pre-populated with the command to run. - /// - /// The NativeActivityContext for the currently running activity. - /// A populated instance of System.Management.Automation.PowerShell - /// The infrastructure takes responsibility for closing and disposing the PowerShell instance returned. - protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) - {{ - System.Management.Automation.PowerShell invoker = global::System.Management.Automation.PowerShell.Create(); - System.Management.Automation.PowerShell targetCommand = invoker.AddCommand(PSCommandName); - - // Initialize the arguments - {5} - - return new ActivityImplementationContext() {{ PowerShellInstance = invoker }}; - }} - }} -}}"; - - const string templateParameter = @" - /// - /// Provides access to the {1} parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument<{0}> {1} {{ get; set; }}"; - - const string templateParameterSetter = @" - if({0}.Expression != null) - {{ - targetCommand.AddParameter(""{1}"", {0}.Get(context)); - }}"; - - const string customRemotingMapping = @" - if(GetIsComputerNameSpecified(context) && (PSRemotingBehavior.Get(context) == RemotingBehavior.Custom)) - { - targetCommand.AddParameter(""ComputerName"", PSComputerName.Get(context)); - }"; - - const string supportsCustomRemoting = @" - /// - /// Declares that this activity supports its own remoting. - /// - protected override bool SupportsCustomRemoting { get { return true; } }"; - - /// - /// Generate an activity for the named command. - /// - /// The command name to generate. - /// The namespace that will contain the command - for example, - /// Microsoft.PowerShell.Activities. - /// - /// A string representing the C# source code of the generated activity. - public static string GenerateFromName(string command, string activityNamespace) - { - return GenerateFromName(command, activityNamespace, false); - } - - /// - /// Generate an activity for the named command. - /// - /// The command name to generate. - /// The namespace that will contain the command - for example, - /// Microsoft.PowerShell.Activities. - /// - /// True if remoting-related parameters should be suppressed. This - /// should only be specified for commands that offer no value when run on a remote computer. - /// - /// A string representing the C# source code of the generated activity. - public static string GenerateFromName(string command, string activityNamespace, bool shouldRunLocally) - { - StringBuilder output = new StringBuilder(); - - // Get the command from the runspace - using (System.Management.Automation.PowerShell invoker = System.Management.Automation.PowerShell.Create()) - { - invoker.AddCommand("Get-Command").AddParameter("Name", command); - Collection result = invoker.Invoke(); - - if (result.Count == 0) - { - string message = String.Format(CultureInfo.InvariantCulture, ActivityResources.ActivityNameNotFound, command); - throw new ArgumentException(message, "command"); - } - - foreach (CommandInfo commandToGenerate in result) - { - output.AppendLine(GenerateFromCommandInfo(commandToGenerate, activityNamespace, shouldRunLocally)); - } - } - - return output.ToString().Trim(); - } - - - /// - /// By default, the activity wrapper uses the remoting command base. - /// - /// The command name to generate. - /// The namespace that will contain the command - for example, - /// Microsoft.PowerShell.Activities. - /// - /// - public static string GenerateFromCommandInfo(CommandInfo command, string activityNamespace) - { - return GenerateFromCommandInfo(command, activityNamespace, false); - } - - /// - /// By default, the activity wrapper uses the remoting command base. - /// - /// The command name to generate. - /// The namespace that will contain the command - for example, - /// Microsoft.PowerShell.Activities. - /// - /// True if remoting-related parameters should be suppressed. This - /// should only be specified for commands that offer no value when run on a remote computer. - /// - /// - public static string GenerateFromCommandInfo(CommandInfo command, string activityNamespace, bool shouldRunLocally) - { - string activityBaseClass = "PSRemotingActivity"; - if (shouldRunLocally || (command.RemotingCapability == RemotingCapability.None)) - { - activityBaseClass = "PSActivity"; - } - - return GenerateFromCommandInfo(command, activityNamespace, activityBaseClass, null, null, String.Empty); - } - - /// - /// Generate an activity for the given command. - /// - /// The command to use as the basis of the generated activity. - /// The namespace that will contain the command - for example, - /// Microsoft.PowerShell.Activities. - /// - /// The class to use as the base class for this activity - /// - /// A list of parameters on the command being wrapped that should not - /// be copied to the activity. - /// - /// The module that contains the wrapped command - /// Addition text to inset in the class definition - /// A string representing the C# source code of the generated activity. - public static string GenerateFromCommandInfo( - CommandInfo command, - string activityNamespace, - string activityBaseClass, - string[] parametersToExclude, - string moduleToLoad, - string moduleDefinitionText - ) - { - if (command == null) - { - throw new ArgumentNullException("command"); - } - - if (String.IsNullOrEmpty(activityNamespace)) - { - throw new ArgumentNullException("activityNamespace"); - } - - - if (String.IsNullOrEmpty(activityBaseClass)) - { - throw new ArgumentNullException("activityBaseClass"); - } - - StringBuilder parameterBlock = new StringBuilder(); - StringBuilder parameterInitialization = new StringBuilder(); - string commandName = command.Name; - commandName = commandName.Substring(0, 1).ToUpper(CultureInfo.CurrentCulture) + commandName.Substring(1); - string activityName = command.Name.Replace("-", ""); - activityName = activityName.Substring(0, 1).ToUpper(CultureInfo.CurrentCulture) + activityName.Substring(1); - - String displayName = commandName; - - // Verify that the activity name doesn't conflict with anything in the inheritance hierarchy - Type testType = typeof(PSRemotingActivity); - while (testType != null) - { - if (String.Equals(testType.Name, activityName, StringComparison.OrdinalIgnoreCase)) - { - string message = String.Format(CultureInfo.InvariantCulture, ActivityResources.ActivityNameConflict, activityName); - throw new ArgumentException(message, "command"); - } - - testType = testType.BaseType; - } - - // The default list of parameters that need to be ignored. - List ignoredParameters = new List(Cmdlet.CommonParameters.Concat(Cmdlet.OptionalCommonParameters)); - - // Add in any additional parameters the caller requested to ignore - if (parametersToExclude != null && parametersToExclude.Length > 0) - { - ignoredParameters.AddRange(parametersToExclude); - } - - // If this activity supports its own remoting, ignore the ComputerName - // parameter (we will add special handling for that later) - if (command.RemotingCapability == RemotingCapability.SupportedByCommand) - { - ignoredParameters.Add("ComputerName"); - } - - // Avoid properties in parent classes. - List parentProperties = new List(); - testType = typeof(PSRemotingActivity); - while (testType != typeof(PSActivity).BaseType) - { - parentProperties.AddRange( - from property in testType.GetProperties() select property.Name - ); - - testType = testType.BaseType; - } - - foreach(KeyValuePair parameter in command.Parameters) - { - // Get the name (with capitalized first letter) - string name = parameter.Key; - name = name.Substring(0, 1).ToUpper(CultureInfo.CurrentCulture) + name.Substring(1); - - // Ignore the common parameters - if(ignoredParameters.Contains(name, StringComparer.OrdinalIgnoreCase)) - { - continue; - } - - // Avoid parameters used by the parent activity, currently "Id" and - // "DisplayName". If the command has a noun, we name it: - // NounId and NounDisplayName - for example, ProcessId, and - // ServiceDisplayName. - string originalName = name; - if (parentProperties.Contains(name, StringComparer.OrdinalIgnoreCase)) - { - if (commandName.Contains('-')) - { - string[] commandParts = commandName.Split('-'); - string noun = commandParts[1]; - noun = noun.Substring(0, 1).ToUpper(CultureInfo.CurrentCulture) + noun.Substring(1); - name = noun + name; - } - else - { - name = commandName + name; - } - } - - // If the parameter name is the same as the command name, add "Activity" - // to the command name. Otherwise, we run afoul of the error: - // "Member names cannot be the same as their enclosing type". - if (String.Equals(name, activityName, StringComparison.OrdinalIgnoreCase)) - { - activityName += "Activity"; - } - - // And the type - string type = parameter.Value.ParameterType.ToString(); - - // Fix generic types - if(type.Contains('`')) - { - type = System.Text.RegularExpressions.Regex.Replace(type, "`[\\d]+", ""); - type = System.Text.RegularExpressions.Regex.Replace(type, "\\[", "<"); - type = System.Text.RegularExpressions.Regex.Replace(type, "\\]", ">"); - } - - // Fix nested classes... - if (type.Contains('+')) - { - type = System.Text.RegularExpressions.Regex.Replace(type, "\\+", "."); - } - - // Append the parameter ( InArgument Name { get; set } ... ) - parameterBlock.AppendLine( - String.Format(CultureInfo.InvariantCulture, - templateParameter, - type, - name)); - - // Append the parameter initializer (... Parameters.Add(...) ) - // This may have to be mapped from name to originalName when the - // parameter has a conflict with the parent activity. - parameterInitialization.AppendLine( - String.Format(CultureInfo.InvariantCulture, - templateParameterSetter, - name, - originalName)); - } - - // Append the remoting support to parameter initialization - if (command.RemotingCapability == RemotingCapability.SupportedByCommand) - { - parameterBlock.AppendLine(supportsCustomRemoting); - parameterInitialization.AppendLine(customRemotingMapping); - } - - - // If no module definition string has been included then add the defining module - // to the list of modules and make use a module-qualified name - string psDefiningModule = ""; - if (string.IsNullOrEmpty(moduleDefinitionText)) - { - // Prefer the module to load that was passed in over the module that - // eventually defined the cmdlet... - if (!string.IsNullOrEmpty(moduleToLoad)) - { - commandName = moduleToLoad + "\\" + commandName; - } - else if (!String.IsNullOrEmpty(command.ModuleName)) - { - commandName = command.ModuleName + "\\" + commandName; - } - - if (!String.IsNullOrEmpty(moduleToLoad)) - { - psDefiningModule = " /// \n/// Script module contents for this activity`n/// \n" + - @"protected override string PSDefiningModule { get { return """ + moduleToLoad + @"""; } }"; - } - } - - return String.Format(CultureInfo.InvariantCulture, - templateCommand, - activityNamespace, - commandName, - activityName, - parameterBlock.ToString(), - commandName.Replace("\\", "\\\\"), - parameterInitialization.ToString(), - activityBaseClass, - psDefiningModule, - displayName, - moduleDefinitionText); - } - - /// - /// Generates a complete activity source file from a module. - /// - /// - /// The namespace to use for the target classes - /// An array of code elements to compile into an assembly - static public string[] GenerateFromModuleInfo(PSModuleInfo moduleToProcess, string activityNamespace) - { - if (moduleToProcess == null) - throw new ArgumentNullException("moduleToProcess"); - - List codeToCompile = new List(); - - // Cmdlets and function need to exist in separate namespaces... - if (moduleToProcess.ExportedCmdlets != null) - { - string namespaceToUse = ! string.IsNullOrEmpty(activityNamespace) ? activityNamespace : moduleToProcess.Name + "_Cmdlet_Activities"; - foreach (CmdletInfo ci in moduleToProcess.ExportedCmdlets.Values) - { - string code = Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromCommandInfo(ci, namespaceToUse, "PSRemotingActivity", null, null, ""); - codeToCompile.Add(code); - } - } - - Dictionary modules = new Dictionary(); - PSModuleInfo cimModule = moduleToProcess; - - if (moduleToProcess.ExportedFunctions != null) - { - string namespaceToUse = !string.IsNullOrEmpty(activityNamespace) ? activityNamespace : moduleToProcess.Name + "_Function_Activities"; - foreach (FunctionInfo fi in moduleToProcess.ExportedFunctions.Values) - { - string moduleName = null; - string moduleDefinition = null; - - // Save the module defining this function - we may need to extract - // embedded types further on - if (fi.ScriptBlock.Module != null && !string.IsNullOrEmpty(fi.ScriptBlock.Module.Definition)) - { - moduleName = fi.ScriptBlock.Module.Name; - moduleDefinition = fi.ScriptBlock.Module.Definition; - } - - string code; - if (fi.ScriptBlock.Module.ModuleType == ModuleType.Cim) - { - // Special-case CIM activities - string embeddedDefinition = ""; - - // Embed the module definition in the activity... - if (moduleDefinition != null) - { - // Remove all of the calls to Export-ModuleMember and getcommand - string editedDefinition = System.Text.RegularExpressions.Regex.Replace(moduleDefinition, @"Microsoft.PowerShell.Core\\Export-ModuleMember[^\n]*\n", ""); - editedDefinition = System.Text.RegularExpressions.Regex.Replace(editedDefinition, - @"if \(\$\(Microsoft.PowerShell.Core\\Get-Command Set-StrictMode[^\n]*\n", ""); - - embeddedDefinition = "protected override string ModuleDefinition { get { return _moduleDefinition; } }\r\n const string _moduleDefinition = @\"" - + editedDefinition.Replace("\"", "\"\"") + "\";"; - } - code = Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromCommandInfo( - fi, namespaceToUse, "PSGeneratedCIMActivity", new string[] { "Computer", "AsJob", "CimSession" }, null, embeddedDefinition); - - cimModule = fi.ScriptBlock.Module; - } - else - { - code = Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromCommandInfo( - fi, namespaceToUse, "PSRemotingActivity", new string[] { "Computer", "AsJob" }, moduleToProcess.Name, ""); - } - codeToCompile.Add(code); - - if (moduleName != null && !modules.ContainsKey(fi.ScriptBlock.Module.Name)) - { - modules.Add(moduleName, moduleDefinition); - } - - - } - } - - string fileName = cimModule.Path; - - // See if there are any embedded types to extract - if (Path.GetExtension(fileName).Equals(".cdxml", StringComparison.OrdinalIgnoreCase)) - { - // generate cmdletization proxies - using (FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read)) - { - XmlReader xmlReader = XmlReader.Create(file, xmlReaderSettings.Value); - - PowerShellMetadata cmdletizationMetadata = (PowerShellMetadata)xmlSerializer.Value.Deserialize(xmlReader); - - if (cmdletizationMetadata != null && cmdletizationMetadata.Enums != null) - { - foreach (EnumMetadataEnum enumMetadata in cmdletizationMetadata.Enums) - { - codeToCompile.Add(GetCSharpCode(enumMetadata)); - } - } - } - } - - return codeToCompile.ToArray(); - } - - internal static string GetCSharpCode(EnumMetadataEnum enumMetadata) - { - var codeCompileUnit = CreateCodeCompileUnit(enumMetadata); - - var stringWriter = new StringWriter(CultureInfo.InvariantCulture); - CodeDomProvider.CreateProvider("C#").GenerateCodeFromCompileUnit( - codeCompileUnit, - stringWriter, - new CodeGeneratorOptions()); - return stringWriter.ToString(); - } - - private const string namespacePrefix = "Microsoft.PowerShell.Cmdletization.GeneratedTypes"; - - private static CodeCompileUnit CreateCodeCompileUnit(EnumMetadataEnum enumMetadata) - { - var codeDomProvider = CodeDomProvider.CreateProvider("C#"); - - string subnamespaceText = string.Empty; - string enumNameText; - int indexOfLastDot = enumMetadata.EnumName.LastIndexOf('.'); - if (indexOfLastDot < 0) - { - enumNameText = enumMetadata.EnumName; - } - else - { - subnamespaceText = "." + enumMetadata.EnumName.Substring(0, indexOfLastDot); - enumNameText = enumMetadata.EnumName.Substring( - indexOfLastDot + 1, enumMetadata.EnumName.Length - indexOfLastDot - 1); - } - - // defense in depth (in case xsd is allowing some invalid identifiers) - // + xsd allows reserved keywords (i.e. "namespace" passes the regex test, but is not a valid identifier) - if (!codeDomProvider.IsValidIdentifier(enumNameText)) - { - var errorMessage = string.Format( - CultureInfo.InvariantCulture, - ActivityResources.EnumWriter_InvalidEnumName, - enumMetadata.EnumName); - throw new XmlException(errorMessage); - } - var newEnum = new CodeTypeDeclaration(codeDomProvider.CreateValidIdentifier(enumNameText)) { IsEnum = true, Attributes = MemberAttributes.Public }; - - if (enumMetadata.BitwiseFlagsSpecified && enumMetadata.BitwiseFlags) - { - newEnum.CustomAttributes.Add( - new CodeAttributeDeclaration(new CodeTypeReference(typeof(FlagsAttribute)))); - } - - Type underlyingType = null; - if (enumMetadata.UnderlyingType != null) - { - underlyingType = Type.GetType(enumMetadata.UnderlyingType, false, true); - - if (underlyingType != null) - { - newEnum.BaseTypes.Add(underlyingType); - } - else - { - underlyingType = typeof(Int32); - } - } - else - { - underlyingType = typeof(Int32); - } - - foreach (var value in enumMetadata.Value) - { - // defense in depth (in case xsd is allowing some invalid identifiers) - // + xsd allows reserved keywords (i.e. "namespace" passes the regex test, but is not a valid identifier) - if (!codeDomProvider.IsValidIdentifier(value.Name)) // defense in depth (in case xsd is allowing some invalid identifiers) - { - var errorMessage = string.Format( - CultureInfo.InvariantCulture, - ActivityResources.EnumWriter_InvalidValueName, - value.Name); - throw new XmlException(errorMessage); - } - - var nameValuePair = new CodeMemberField(underlyingType, codeDomProvider.CreateValidIdentifier(value.Name)); - - object integerValue = LanguagePrimitives.ConvertTo( - value.Value, underlyingType, CultureInfo.InvariantCulture); - nameValuePair.InitExpression = new CodePrimitiveExpression(integerValue); - - newEnum.Members.Add(nameValuePair); - } - - var topLevelNamespace = new CodeNamespace(namespacePrefix + subnamespaceText); - topLevelNamespace.Types.Add(newEnum); - - var codeCompileUnit = new CodeCompileUnit(); - codeCompileUnit.Namespaces.Add(topLevelNamespace); - codeCompileUnit.ReferencedAssemblies.Add("System.dll"); - - return codeCompileUnit; - } - - /// - /// - /// - /// - /// - /// - /// - /// - /// - public static Assembly GenerateAssemblyFromModuleInfo( - PSModuleInfo moduleToProcess, - string activityNamespace, - string outputAssemblyPath, - string[] referenceAssemblies, - out string errors - ) - { - string[] src = GenerateFromModuleInfo(moduleToProcess, activityNamespace); - - bool toAssembly = ! string.IsNullOrEmpty(outputAssemblyPath); - - return CompileStrings(src, referenceAssemblies, toAssembly, outputAssemblyPath, out errors); - } - - private static Assembly CompileStrings( - string[] src, - string[] referenceAssemblies, - bool toAssembly, - string outputAssemblyPath, - out string errors - ) - { - var cpar = new System.CodeDom.Compiler.CompilerParameters() - { - GenerateInMemory = ! toAssembly, - OutputAssembly = outputAssemblyPath, - }; - - // Add default references... - cpar.ReferencedAssemblies.Add(typeof(System.Activities.Activity).Assembly.Location); - cpar.ReferencedAssemblies.Add(typeof(System.CodeDom.Compiler.CodeCompiler).Assembly.Location); - cpar.ReferencedAssemblies.Add(typeof(PSObject).Assembly.Location); - cpar.ReferencedAssemblies.Add(typeof(Microsoft.PowerShell.Activities.PSActivity).Assembly.Location); - cpar.ReferencedAssemblies.Add(ResolveReferencedAssembly("Microsoft.Management.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")); - cpar.ReferencedAssemblies.Add(ResolveReferencedAssembly("Microsoft.PowerShell.Commands.Management, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")); - - // Add user supplied references... - if (referenceAssemblies != null) - { - foreach (string asm in referenceAssemblies) - { - cpar.ReferencedAssemblies.Add(ResolveReferencedAssembly(asm)); - } - } - - var compiler = new Microsoft.CSharp.CSharpCodeProvider(); - var cr = compiler.CompileAssemblyFromSource(cpar, src); - if (cr.Errors == null || cr.Errors.Count == 0) - { - errors = string.Empty; - } - else - { - StringBuilder errorBuilder = new StringBuilder(); - foreach (var err in cr.Errors) - { - errorBuilder.Append(err.ToString()); - errorBuilder.Append('\n'); - } - - errors = errorBuilder.ToString(); - } - - if (errors.Length > 0) - { - return null; - } - - // If the assembly was written to disk, return null - // since we don't want to load the assembly we've just created. - if (toAssembly) - { - return null; - } - else - { - return cr.CompiledAssembly; - } - } - - [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadWithPartialName")] - [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")] - private static string ResolveReferencedAssembly(string assembly) - { - Assembly asm = null; - - if (assembly == null) - { - throw new ArgumentNullException("assembly"); - } - - if (System.IO.Path.IsPathRooted(assembly)) - { - return assembly; - } - - if (assembly.Contains(',')) - { - try - { - asm = Assembly.Load(assembly); - return asm.Location; - } - catch (Exception) - { - ; - } - } - - - if (asm == null) - { - try - { -#pragma warning disable 0618 - asm = Assembly.LoadWithPartialName(assembly); - return asm.Location; - } - catch (Exception) - { - ; - } - } - - if (asm == null) - { - throw new InvalidOperationException(assembly); - } - return null; - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/GetCimAssociatedInstanceActivity.cs b/src/Microsoft.PowerShell.Activities/Activities/GetCimAssociatedInstanceActivity.cs deleted file mode 100644 index 046fdb79f..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/GetCimAssociatedInstanceActivity.cs +++ /dev/null @@ -1,135 +0,0 @@ - -using Microsoft.PowerShell.Activities; -using System.Activities; -using System.Collections.Generic; -using System.ComponentModel; - - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Activity to invoke the CimCmdlets\Get-CimAssociatedInstance command in a Workflow. - /// - [System.CodeDom.Compiler.GeneratedCode("Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromName", "3.0")] - public sealed class GetCimAssociatedInstance : GenericCimCmdletActivity - { - /// - /// Gets the display name of the command invoked by this activity. - /// - public GetCimAssociatedInstance() - { - this.DisplayName = "Get-CimAssociatedInstance"; - } - - /// - /// Gets the fully qualified name of the command invoked by this activity. - /// - public override string PSCommandName { get { return "CimCmdlets\\Get-CimAssociatedInstance"; } } - - /// - /// The .NET type implementing the cmdlet to invoke. - /// - public override System.Type TypeImplementingCmdlet { get { return typeof(Microsoft.Management.Infrastructure.CimCmdlets.GetCimAssociatedInstanceCommand); } } - - // Arguments - - /// - /// Provides access to the Association parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Association { get; set; } - - /// - /// Provides access to the ResultClassName parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument ResultClassName { get; set; } - - /// - /// Provides access to the InputObject parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument InputObject { get; set; } - - /// - /// Provides access to the Namespace parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Namespace { get; set; } - - /// - /// Provides access to the OperationTimeoutSec parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument OperationTimeoutSec { get; set; } - - /// - /// Provides access to the KeyOnly parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument KeyOnly { get; set; } - - /// - /// No module needed for this activity - /// - protected override string PSDefiningModule { get { return null; } } - - /// - /// Returns a configured instance of System.Management.Automation.PowerShell, pre-populated with the command to run. - /// - /// The NativeActivityContext for the currently running activity. - /// A populated instance of System.Management.Automation.PowerShell - /// The infrastructure takes responsibility for closing and disposing the PowerShell instance returned. - protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) - { - System.Management.Automation.PowerShell invoker = global::System.Management.Automation.PowerShell.Create(); - System.Management.Automation.PowerShell targetCommand = invoker.AddCommand(PSCommandName); - - // Initialize the arguments - - if(Association.Expression != null) - { - targetCommand.AddParameter("Association", Association.Get(context)); - } - - if (ResultClassName.Expression != null) - { - targetCommand.AddParameter("ResultClassName", ResultClassName.Get(context)); - } - - if (InputObject.Expression != null) - { - targetCommand.AddParameter("InputObject", InputObject.Get(context)); - } - - if(Namespace.Expression != null) - { - targetCommand.AddParameter("Namespace", Namespace.Get(context)); - } - - if(OperationTimeoutSec.Expression != null) - { - targetCommand.AddParameter("OperationTimeoutSec", OperationTimeoutSec.Get(context)); - } - - if(KeyOnly.Expression != null) - { - targetCommand.AddParameter("KeyOnly", KeyOnly.Get(context)); - } - - if (ResourceUri != null) - { - targetCommand.AddParameter("ResourceUri", ResourceUri.Get(context)); - } - - - return new ActivityImplementationContext() { PowerShellInstance = invoker }; - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/GetCimClassActivity.cs b/src/Microsoft.PowerShell.Activities/Activities/GetCimClassActivity.cs deleted file mode 100644 index 04cf6c7bd..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/GetCimClassActivity.cs +++ /dev/null @@ -1,131 +0,0 @@ - -using Microsoft.PowerShell.Activities; -using System.Activities; -using System.Collections.Generic; -using System.ComponentModel; - - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Activity to invoke the CimCmdlets\Get-CimClass command in a Workflow. - /// - [System.CodeDom.Compiler.GeneratedCode("Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromName", "3.0")] - public sealed class GetCimClass : GenericCimCmdletActivity - { - /// - /// Gets the display name of the command invoked by this activity. - /// - public GetCimClass() - { - this.DisplayName = "Get-CimClass"; - } - - /// - /// Gets the fully qualified name of the command invoked by this activity. - /// - public override string PSCommandName { get { return "CimCmdlets\\Get-CimClass"; } } - - /// - /// The .NET type implementing the cmdlet to invoke. - /// - public override System.Type TypeImplementingCmdlet { get { return typeof(Microsoft.Management.Infrastructure.CimCmdlets.GetCimClassCommand); } } - - // Arguments - - /// - /// Provides access to the ClassName parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument ClassName { get; set; } - - /// - /// Provides access to the Namespace parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Namespace { get; set; } - - /// - /// Provides access to the OperationTimeoutSec parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument OperationTimeoutSec { get; set; } - - /// - /// Provides access to the MethodName parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument MethodName { get; set; } - - /// - /// Provides access to the PropertyName parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument PropertyName { get; set; } - - /// - /// Provides access to the QualifierName parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument QualifierName { get; set; } - - /// - /// No module needed for this activity - /// - protected override string PSDefiningModule { get { return null; } } - - /// - /// Returns a configured instance of System.Management.Automation.PowerShell, pre-populated with the command to run. - /// - /// The NativeActivityContext for the currently running activity. - /// A populated instance of System.Management.Automation.PowerShell - /// The infrastructure takes responsibility for closing and disposing the PowerShell instance returned. - protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) - { - System.Management.Automation.PowerShell invoker = global::System.Management.Automation.PowerShell.Create(); - System.Management.Automation.PowerShell targetCommand = invoker.AddCommand(PSCommandName); - - // Initialize the arguments - // Specified ClassName cannot be WhiteSpace or NULL - // - if (ClassName.Expression != null && !string.IsNullOrWhiteSpace(ClassName.Get(context))) - { - targetCommand.AddParameter("ClassName", ClassName.Get(context)); - } - - if(Namespace.Expression != null) - { - targetCommand.AddParameter("Namespace", Namespace.Get(context)); - } - - if(OperationTimeoutSec.Expression != null) - { - targetCommand.AddParameter("OperationTimeoutSec", OperationTimeoutSec.Get(context)); - } - - if(MethodName.Expression != null) - { - targetCommand.AddParameter("MethodName", MethodName.Get(context)); - } - - if(PropertyName.Expression != null) - { - targetCommand.AddParameter("PropertyName", PropertyName.Get(context)); - } - - if(QualifierName.Expression != null) - { - targetCommand.AddParameter("QualifierName", QualifierName.Get(context)); - } - - - return new ActivityImplementationContext() { PowerShellInstance = invoker }; - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/GetCimInstanceActivity.cs b/src/Microsoft.PowerShell.Activities/Activities/GetCimInstanceActivity.cs deleted file mode 100644 index 10bada788..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/GetCimInstanceActivity.cs +++ /dev/null @@ -1,177 +0,0 @@ - -using Microsoft.PowerShell.Activities; -using System.Activities; -using System.Collections.Generic; -using System.ComponentModel; - - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Activity to invoke the CimCmdlets\Get-CimInstance command in a Workflow. - /// - [System.CodeDom.Compiler.GeneratedCode("Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromName", "3.0")] - public sealed class GetCimInstance : GenericCimCmdletActivity - { - /// - /// Gets the display name of the command invoked by this activity. - /// - public GetCimInstance() - { - this.DisplayName = "Get-CimInstance"; - } - - /// - /// Gets the fully qualified name of the command invoked by this activity. - /// - public override string PSCommandName { get { return "CimCmdlets\\Get-CimInstance"; } } - - /// - /// The .NET type implementing the cmdlet to invoke. - /// - public override System.Type TypeImplementingCmdlet { get { return typeof(Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand); } } - - // Arguments - - /// - /// Provides access to the ClassName parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument ClassName { get; set; } - - /// - /// Provides access to the Filter parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Filter { get; set; } - - /// - /// Provides access to the KeyOnly parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument KeyOnly { get; set; } - - /// - /// Provides access to the Namespace parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Namespace { get; set; } - - /// - /// Provides access to the OperationTimeoutSec parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument OperationTimeoutSec { get; set; } - - /// - /// Provides access to the InputObject parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument InputObject { get; set; } - - /// - /// Provides access to the Query parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Query { get; set; } - - /// - /// Provides access to the QueryDialect parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument QueryDialect { get; set; } - - /// - /// Provides access to the Shallow parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Shallow { get; set; } - - /// - /// Provides access to the Property parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Property { get; set; } - - /// - /// Returns a configured instance of System.Management.Automation.PowerShell, pre-populated with the command to run. - /// - /// The NativeActivityContext for the currently running activity. - /// A populated instance of System.Management.Automation.PowerShell - /// The infrastructure takes responsibility for closing and disposing the PowerShell instance returned. - protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) - { - System.Management.Automation.PowerShell invoker = global::System.Management.Automation.PowerShell.Create(); - System.Management.Automation.PowerShell targetCommand = invoker.AddCommand(PSCommandName); - - // Initialize the arguments - - if(ClassName.Expression != null) - { - targetCommand.AddParameter("ClassName", ClassName.Get(context)); - } - - if (Filter.Expression != null) - { - targetCommand.AddParameter("Filter", Filter.Get(context)); - } - - if(KeyOnly.Expression != null) - { - targetCommand.AddParameter("KeyOnly", KeyOnly.Get(context)); - } - - if(Namespace.Expression != null) - { - targetCommand.AddParameter("Namespace", Namespace.Get(context)); - } - - if(OperationTimeoutSec.Expression != null) - { - targetCommand.AddParameter("OperationTimeoutSec", OperationTimeoutSec.Get(context)); - } - - if (InputObject.Expression != null) - { - targetCommand.AddParameter("InputObject", InputObject.Get(context)); - } - - if(Query.Expression != null) - { - targetCommand.AddParameter("Query", Query.Get(context)); - } - - if(QueryDialect.Expression != null) - { - targetCommand.AddParameter("QueryDialect", QueryDialect.Get(context)); - } - - if(Shallow.Expression != null) - { - targetCommand.AddParameter("Shallow", Shallow.Get(context)); - } - - if (Property.Expression != null) - { - targetCommand.AddParameter("Property", Property.Get(context)); - } - - if (ResourceUri != null) - { - targetCommand.AddParameter("ResourceUri", ResourceUri.Get(context)); - } - - return new ActivityImplementationContext() { PowerShellInstance = invoker }; - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/GetPSWorkflowData.cs b/src/Microsoft.PowerShell.Activities/Activities/GetPSWorkflowData.cs deleted file mode 100644 index 599480c68..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/GetPSWorkflowData.cs +++ /dev/null @@ -1,338 +0,0 @@ -using System; -using System.Activities; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Globalization; -using System.Diagnostics.CodeAnalysis; -using System.Management.Automation; -using System.Management.Automation.Tracing; -using System.ComponentModel; - -namespace Microsoft.PowerShell.Activities -{ - - /// - /// - /// - public enum PSWorkflowRuntimeVariable - { - // Command Parameters - /// - /// - /// - PSComputerName = 0, - /// - /// - /// - PSCredential = 1, - /// - /// - /// - PSPort = 2, - /// - /// - /// - PSUseSsl = 3, - /// - /// - /// - PSConfigurationName = 4, - /// - /// - /// - PSApplicationName = 5, - /// - /// - /// - PSConnectionUri = 6, - /// - /// - /// - PSAllowRedirection = 7, - /// - /// - /// - PSSessionOption = 8, - /// - /// - /// - PSAuthentication = 9, - /// - /// - /// - PSAuthenticationLevel = 10, - /// - /// - /// - PSCertificateThumbprint = 11, - /// - /// - /// - Input = 13, - /// - /// - /// - Verbose = 15, - - // Retry policy constants - /// - /// - /// - PSConnectionRetryCount = 19, - /// - /// - /// - PSConnectionRetryIntervalSec = 21, - - /// - /// - /// - PSPrivateMetadata = 24, - - // Timers - /// - /// - /// - PSRunningTimeoutSec = 27, - /// - /// - /// - PSElapsedTimeoutSec = 28, - - /// - /// - /// - PSWorkflowRoot = 31, - - /// - /// - /// - JobName = 32, - /// - /// - /// - JobInstanceId = 33, - /// - /// - /// - JobId = 34, - - /// - /// - /// - JobCommandName = 36, - - /// - /// - /// - ParentJobInstanceId = 40, - - /// - /// - /// - ParentJobName = 41, - - /// - /// - /// - ParentJobId = 42, - - /// - /// - /// - ParentCommandName = 43, - - /// - /// - /// - WorkflowInstanceId = 48, - - /// - /// - /// - PSSenderInfo = 49, - - /// - /// - /// - PSCulture = 50, - - /// - /// - /// - [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly")] - PSUICulture = 51, - - /// - /// - /// - PSVersionTable = 52, - - /// - /// PSPersist - /// - PSPersist = 53, - - /// - /// ErrorAction - /// - ErrorAction = 54, - - /// - /// WarningAction - /// - WarningAction = 55, - - /// - /// InformationAction - /// - InformationAction = 56, - - /// - /// Tell the activity to look for a custom string - /// - Other = 1000, - - /// - /// Return all values as a hashtable - /// - All = 1001, - } - - /// - /// Activity to retrieve the value of a workflow runtime variable. - /// - public sealed class GetPSWorkflowData : NativeActivity - { - /// - /// The variable to retrieve. - /// - [RequiredArgument] - public PSWorkflowRuntimeVariable VariableToRetrieve - { - get; - set; - } - - /// - /// The variable to retrieve, if not included in the PSWorkflowRuntimeVariable enum. - /// - [DefaultValue(null)] - public InArgument OtherVariableName - { - get; - set; - } - - /// - /// Execute the logic for this activity... - /// - /// - protected override void Execute(NativeActivityContext context) - { - // Retrieve our host overrides - HostParameterDefaults hostValues = context.GetExtension(); - - PropertyDescriptorCollection col = context.DataContext.GetProperties(); - string variableName = null; - - if (VariableToRetrieve != PSWorkflowRuntimeVariable.Other) - { - // Get the symbolic name for the enum - variableName = LanguagePrimitives.ConvertTo(VariableToRetrieve); - } - else - { - if (OtherVariableName.Expression != null) - { - string value = OtherVariableName.Get(context); - - if (!string.IsNullOrWhiteSpace(value)) - { - variableName = value; - } - } - } - - //BUGBUG need a better exception here, could also do this as a custom validator - // Make sure we have a variable here... - if (string.IsNullOrWhiteSpace(variableName)) - { - throw new InvalidOperationException("OtherVariable"); - } - - object valueToReturn = null; - PSDataCollection outputStream = null; - foreach (System.ComponentModel.PropertyDescriptor property in context.DataContext.GetProperties()) - { - if (string.Equals(property.Name, "ParameterDefaults", StringComparison.OrdinalIgnoreCase)) - { - foreach (var parameter in ((Microsoft.PowerShell.Activities.HostParameterDefaults)property.GetValue(context.DataContext)).Parameters) - { - if (parameter.Key.Equals(variableName, StringComparison.OrdinalIgnoreCase)) - { - valueToReturn = parameter.Value; - } - else if (parameter.Key.Equals("Result")) - { - outputStream = parameter.Value as PSDataCollection; - } - } - - // - // If the property to return was all, then just return the entire collection as a hashtable. - // (We still needed to loop to find the output stream to write into.) - // - if (VariableToRetrieve == PSWorkflowRuntimeVariable.All) - { - System.Collections.Hashtable workflowRuntimeVariables = new System.Collections.Hashtable(StringComparer.OrdinalIgnoreCase); - - string[] enumNames = VariableToRetrieve.GetType().GetEnumNames(); - - // Skipping last two enum names, Other and All, as they are not actual variable names - // - for (int i=0; i < (enumNames.Length - 2); i++) - { - workflowRuntimeVariables.Add(enumNames[i], null); - } - - Dictionary dictionaryParam = ((Microsoft.PowerShell.Activities.HostParameterDefaults)property.GetValue(context.DataContext)).Parameters; - - foreach(string varKey in dictionaryParam.Keys) - { - // We need to get the values of required runtime variables only, not everything from DataContext parameters - // - if (workflowRuntimeVariables.ContainsKey(varKey)) - { - Object value = null; - dictionaryParam.TryGetValue(varKey, out value); - workflowRuntimeVariables[varKey] = value; - } - } - - valueToReturn = workflowRuntimeVariables; - } - break; - } - } - - if (this.Result.Expression != null) - { - this.Result.Set(context, valueToReturn); - } - else if (outputStream != null) - { - if (valueToReturn != null) - { - outputStream.Add(PSObject.AsPSObject(valueToReturn)); - } - } - else - { - //BUGBUG need a better exception here... - throw new InvalidOperationException("Result"); - } - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/InlineScript.cs b/src/Microsoft.PowerShell.Activities/Activities/InlineScript.cs deleted file mode 100644 index 1601beb08..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/InlineScript.cs +++ /dev/null @@ -1,812 +0,0 @@ -// -// Copyright (C) Microsoft. All rights reserved. -// -using System; -using System.Activities; -using System.Collections.Generic; -using System.Globalization; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.ComponentModel; -using System.Text; -using System.Reflection; - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Activity to support the invocation of PowerShell script content in a Workflow. - /// -#if _NOTARMBUILD_ - [Designer(typeof(InlineScriptDesigner))] -#endif - public sealed class InlineScript : PSRemotingActivity - { - /// - /// The script text to invoke. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public string Command - { - get { return _command; } - set - { - _command = value; - _commandSpecified = true; - } - } - private string _command; - private bool _commandSpecified; - - /// - /// Name of the command to invoke - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument CommandName { get; set; } - - /// - /// Parameters to invoke the command with. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Parameters { get; set; } - - /// - /// Declares that this activity supports its own remoting. - /// - protected override bool SupportsCustomRemoting { get { return true; } } - - private ScriptBlock _compiledScriptForInProc; - private ScriptBlock _compiledScriptForOutProc; - private string _scriptWithoutUsing; - private HashSet _usingVariables; - // Remember the names of the variables/arguments that statically exist in the - // workflow context and potentially can be referenced by a using variable in - // an InlineScript. Those static variables/arguments include: - // 1. the default arguments of InlineScript and its parents - // 2. the workflow runtime variables - // - // This static set is used to decide whether to add the special prefix - // to a variable or not, when replacing a using variable. - private static readonly HashSet StaticPotentialUsingVariableSet = new HashSet(StringComparer.OrdinalIgnoreCase); - private const string VariablePrefix = "__PSUsingVariable_"; - - - static InlineScript() - { - PopulatePotentialUsingVariableStaticSet(); - } - - private static void PopulatePotentialUsingVariableStaticSet() - { - var namesToExclude = new HashSet(StringComparer.OrdinalIgnoreCase) - { - // from inlinescript common arguments - "Result", "PSError", "PSWarning", "PSVerbose", "PSDebug", "PSProgress", "PSInformation", - - // from workflow runtime variables - "Other", "All", - - // some workflow variables/arguments conflict with the built-in powershell variables, including: - // Input, PSSessionOption, PSCulture, PSUICulture, PSVersionTable - // - // per discussion with Hemant and Rahim, we want to: - // 1. treat $using:input, $using:PSSessionOption, $using:PSCulture, and $using:PSUICulture as workflow - // variable; add the special prefix when replacing 'using'. - // 2. treat PSVersionTable as powershell variable, so never add special prefix to it. - "PSVersionTable" - }; - - // Handle InlineScript activity common arguments - foreach (string argumentName in GetInlineScriptActivityArguments()) - { - if (namesToExclude.Contains(argumentName)) { continue; } - if (!StaticPotentialUsingVariableSet.Contains(argumentName)) - { - StaticPotentialUsingVariableSet.Add(argumentName); - } - } - - // Handle workflow runtime variables - var wfRuntimeVariables = typeof(PSWorkflowRuntimeVariable).GetEnumNames(); - foreach (string variableName in wfRuntimeVariables) - { - if (namesToExclude.Contains(variableName)) { continue; } - if (!StaticPotentialUsingVariableSet.Contains(variableName)) - { - StaticPotentialUsingVariableSet.Add(variableName); - } - } - } - - // Use the same logic as the PSActivity.GetActivityArguments to retrieve the names of all default - // arguments from the InlineScript and its parents - internal static IEnumerable GetInlineScriptActivityArguments() - { - Type activityType = typeof(InlineScript); - - while (activityType != null) - { - // We don't want to support parameter defaults for arguments on - // concrete types (as they almost guaranteed to collide with other types), - // but base classes make sense. - if (activityType.IsAbstract) - { - // Populate any parameter defaults. We only look at fields that are defined on this - // specific type (as opposed to derived types) so that we don't make assumptions about - // other activities and their defaults. - foreach (PropertyInfo field in activityType.GetProperties()) - { - // See if it's an argument - if (typeof(Argument).IsAssignableFrom(field.PropertyType)) - { - // Get the argument name - yield return field.Name; - } - } - } - - // Go to our base type, but stop when we go above PSActivity - activityType = activityType.BaseType; - if (!typeof(PSActivity).IsAssignableFrom(activityType)) - activityType = null; - } - } - - /// - /// Validates the contents of the script block for this command. - /// - /// Metadata for this activity - protected override void CacheMetadata(NativeActivityMetadata metadata) - { - base.CacheMetadata(metadata); - - if (! string.IsNullOrWhiteSpace(Command)) - { - Token[] tokens; - ParseError[] errors; - Parser.ParseInput(Command, out tokens, out errors); - if (errors != null && errors.Length > 0) - { - string compositeErrorString = ""; - foreach (var e in errors) - { - // Format and add each error message... - compositeErrorString += string.Format(CultureInfo.InvariantCulture, - "[{0}, {1}]: {2}\n", e.Extent.StartLineNumber, e.Extent.StartColumnNumber, e.Message); - } - metadata.AddValidationError(compositeErrorString); - } - } - } - - /// - /// Indicates if preference variables need to be updated - /// - protected override bool UpdatePreferenceVariable - { - get { return false; } - } - - /// - /// Returns a configured instance of System.Management.Automation.PowerShell, pre-populated with the script to run. - /// - /// The NativeActivityContext for the currently running activity. - /// A populated instance of System.Management.Automation.PowerShell - /// The infrastructure takes responsibility for closing and disposing the PowerShell instance returned. - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Microsoft.Reliability", - "CA2000:Dispose objects before losing scope", - Justification = "Disposed by the infrastructure.")] - protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) - { - ValidateParameters(); - System.Management.Automation.PowerShell invoker = null; - HashSet allWorkflowVarNames = new HashSet(StaticPotentialUsingVariableSet, StringComparer.OrdinalIgnoreCase); - Dictionary defaults = this.ParameterDefaults.Get(context); - Dictionary activityVariables = new Dictionary(StringComparer.OrdinalIgnoreCase); - Dictionary activityUsingVariables = new Dictionary(StringComparer.OrdinalIgnoreCase); - - string[] streams = - { - "Result", "PSError", "PSWarning", "PSVerbose", "PSDebug", "PSProgress", "PSInformation" - }; - - // First, set the variables from the user's variables - foreach (System.ComponentModel.PropertyDescriptor property in context.DataContext.GetProperties()) - { - if (String.Equals(property.Name, "ParameterDefaults", StringComparison.OrdinalIgnoreCase)) - continue; - - // Add all user-defined variables/parameters in the same scope of the InlineScript activity - if (!allWorkflowVarNames.Contains(property.Name)) - { - allWorkflowVarNames.Add(property.Name); - } - - Object value = property.GetValue(context.DataContext); - if (value != null) - { - object tempValue = value; - - PSDataCollection collectionObject = value as PSDataCollection; - - if (collectionObject != null && collectionObject.Count == 1) - { - tempValue = collectionObject[0]; - } - - activityVariables[property.Name] = tempValue; - } - } - - // Then, set anything we received from parameters - foreach (PSActivityArgumentInfo currentArgument in GetActivityArguments()) - { - string @default = currentArgument.Name; - if (streams.Any(item => string.Equals(item, @default, StringComparison.OrdinalIgnoreCase))) - continue; - - object argumentValue = currentArgument.Value.Get(context); - if (argumentValue != null && !activityVariables.ContainsKey(currentArgument.Name)) - { - activityVariables[currentArgument.Name] = argumentValue; - } - } - - // Then, set the variables from the host defaults - if (defaults != null) - { - foreach (string hostDefault in defaults.Keys) - { - string @default = hostDefault; - if (streams.Any(item => string.Equals(item, @default, StringComparison.OrdinalIgnoreCase))) - continue; - - object propertyValue = defaults[hostDefault]; - if (propertyValue != null && !activityVariables.ContainsKey(hostDefault)) - { - activityVariables[hostDefault] = propertyValue; - } - } - } - - if (_commandSpecified) - { - string script = string.IsNullOrEmpty(Command) ? string.Empty : Command; - Tracer.WriteMessage(String.Format(CultureInfo.InvariantCulture, "PowerShell activity ID={0}: Inline Script: '{1}'.", context.ActivityInstanceId, script)); - - if (IsBlocked(script)) - { - throw new PSInvalidOperationException(String.Format(CultureInfo.InvariantCulture, ActivityResources.CannotLaunchFormat, script)); - } - - string[] targetNodes = null; - if (this.PSComputerName.Expression != null) - { - targetNodes = this.PSComputerName.Get(context); - } - else - { - if (defaults != null && defaults.ContainsKey("PSComputerName")) - { - targetNodes = this.ParameterDefaults.Get(context)["PSComputerName"] as string[]; - } - } - - // See if this command will be run in process. - if ((targetNodes == null || targetNodes.Length == 0) && GetRunInProc(context)) - { - if (_compiledScriptForInProc == null || _ci == null) - { - lock (Syncroot) - { - if (_compiledScriptForInProc == null) - { - if (_scriptWithoutUsing == null) - { - _scriptWithoutUsing = RemoveUsingPrefix(script, allWorkflowVarNames, out _usingVariables); - } - _compiledScriptForInProc = ScriptBlock.Create(_scriptWithoutUsing); - } - - // Invoke using the CommandInfo for Invoke-Command directly, rather than going through - // the command discovery since this is much faster. - if (_ci == null) - { - _ci = new CmdletInfo("Invoke-Command", typeof(Microsoft.PowerShell.Commands.InvokeCommandCommand)); - } - } - } - - SetAvailableUsingVariables(activityVariables, activityUsingVariables); - Tracer.WriteMessage("PowerShell activity: executing InlineScript locally with ScriptBlock."); - invoker = System.Management.Automation.PowerShell.Create(); - invoker.AddCommand(_ci).AddParameter("NoNewScope").AddParameter("ScriptBlock", _compiledScriptForInProc); - } - else - { - // Try to convert the ScriptBlock to a powershell instance - if (_compiledScriptForOutProc == null) - { - lock (Syncroot) - { - if (_compiledScriptForOutProc == null) - { - _compiledScriptForOutProc = ScriptBlock.Create(script); - } - } - } - - try - { - // we trust the code inside inlinescript, set isTrusted as True. - invoker = _compiledScriptForOutProc.GetPowerShell(activityVariables, out activityUsingVariables, true); - Tracer.WriteMessage("PowerShell activity: executing InlineScript with ScriptBlock to powershell conversion."); - } - catch (Exception) - { - invoker = null; - } - - if (invoker == null) - { - // Since scriptblocks aren't serialized with fidelity in the remote case, we need to - // use AddScript instead. - if (_scriptWithoutUsing == null) - { - lock (Syncroot) - { - if (_scriptWithoutUsing == null) - { - _scriptWithoutUsing = RemoveUsingPrefix(script, allWorkflowVarNames, out _usingVariables); - } - } - } - - SetAvailableUsingVariables(activityVariables, activityUsingVariables); - Tracer.WriteMessage("PowerShell activity: executing InlineScript by using AddScript."); - invoker = System.Management.Automation.PowerShell.Create(); - invoker.AddScript(_scriptWithoutUsing); - } - } - } - else - { - string commandName = CommandName.Get(context); - if (String.IsNullOrEmpty(commandName)) - { - throw new ArgumentException(ActivityResources.CommandNameRequired); - } - - Tracer.WriteMessage(String.Format(CultureInfo.InvariantCulture, "PowerShell activity ID={0}: Invoking command '{1}'.", context.ActivityInstanceId, commandName)); - invoker = System.Management.Automation.PowerShell.Create(); - invoker.AddCommand(commandName); - - System.Collections.Hashtable parameters = Parameters.Get(context); - - if (parameters != null && parameters.Count > 0) - { - foreach (var key in parameters.Keys) - { - Tracer.WriteMessage(String.Format(CultureInfo.InvariantCulture, "PowerShell activity: Adding parameter '-{0} {1}'.", - key, parameters[key])); - } - invoker.AddParameters(parameters); - } - } - - var implementationContext = new ActivityImplementationContext - { - PowerShellInstance = invoker, - WorkflowContext = activityUsingVariables - }; - - return implementationContext; - } - - private void SetAvailableUsingVariables(Dictionary allActivityVariables, Dictionary activityUsingVariables) - { - if (_usingVariables == null) { return; } - - foreach (string varName in _usingVariables) - { - object value; - string varNameToUse = VariablePrefix + varName; - if (allActivityVariables.TryGetValue(varName, out value) && !activityUsingVariables.ContainsKey(varNameToUse)) - { - activityUsingVariables.Add(varNameToUse, value); - } - } - } - - private void ValidateParameters() - { - if (_commandSpecified) - { - if (CommandName.Expression != null || Parameters.Expression != null) - { - throw new ArgumentException(ActivityResources.CannotSpecifyBothCommandAndCommandName); - } - } - else - { - if (CommandName.Expression == null) - { - throw new ArgumentException(ActivityResources.CannotSpecifyBothCommandAndCommandName); - } - } - } - - /// - /// Checks if the script is blocked - /// - /// - private bool IsBlocked(string script) - { - string[] psUnsupportedConsoleApplications = new string[] - { - "cmd", - "cmd.exe", - "diskpart", - "diskpart.exe", - "edit.com", - "netsh", - "netsh.exe", - "nslookup", - "nslookup.exe", - "powershell", - "powershell.exe", - }; - - foreach (string app in psUnsupportedConsoleApplications) - { - if (script.Equals(app, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return false; - } - - #region "Using variable utility" - - /// - /// Remove the "Using" prefix for all UsingExpressionAsts that appear in the given script - /// - /// script text - /// all workflow variables/arguments that potentially can be referred by a using variable - /// names of the variables in the script that have the "Using" prefix - /// - /// Return script if the script text is empty string or null - /// Return script if there are errors when parsing the script text - /// Return script if there is no UsingExpressionAst in the given script - /// Return a new script text that has all the "Using" prefixes removed - /// - private static string RemoveUsingPrefix(string script, HashSet allWorkflowVariables, out HashSet usingVariables) - { - usingVariables = new HashSet(StringComparer.OrdinalIgnoreCase); - var usingAsts = GetUsingExpressionAsts(script); - if (usingAsts == null || !usingAsts.Any()) { return script; } - - StringBuilder newScript = null; - int startOffset = 0; - foreach (Ast ast in usingAsts) - { - var usingAst = ast as UsingExpressionAst; - if (usingAst == null) { continue; } - - VariableExpressionAst variableAst = UsingExpressionAst.ExtractUsingVariable(usingAst); - if (variableAst == null) { continue; } - - if (newScript == null) - { - newScript = new StringBuilder(); - } - - string varName = variableAst.VariablePath.UserPath; - string varSign = variableAst.Splatted ? "@" : "$"; - bool needPrefix = allWorkflowVariables.Contains(varName); - string newVar = needPrefix ? (varSign + VariablePrefix + varName) : (varSign + varName); - - // Add those variable names that potentially refer to workflow variables/arguments - if (needPrefix && !usingVariables.Contains(varName)) - { - usingVariables.Add(varName); - } - - newScript.Append(script.Substring(startOffset, variableAst.Extent.StartOffset - startOffset)); - newScript.Append(newVar); - startOffset = variableAst.Extent.EndOffset; - } - - if (newScript != null) - { - newScript.Append(script.Substring(startOffset)); - return newScript.ToString(); - } - - return script; - } - - /// - /// Get the UsingExpressionAsts out of a script - /// - /// - /// a list of UsingExpressionAsts ordered by the StartOffset - private static IEnumerable GetUsingExpressionAsts(string script) - { - if (String.IsNullOrEmpty(script)) - { - return null; - } - - ParseError[] errors; - Token[] tokens; - ScriptBlockAst scriptAst = Parser.ParseInput(script, out tokens, out errors); - if (errors.Length != 0) - { - return null; - } - - var list = scriptAst.FindAll(ast => ast is UsingExpressionAst, searchNestedScriptBlocks: true).ToList(); - if (list.Count > 1) - { - return list.OrderBy(a => a.Extent.StartOffset); - } - return list; - } - - #endregion "Using variable utility" - - /// - /// Adds the PSActivity variable to the active runspace, which is of type InlineScriptContext. - /// - /// The ActivityImplementationContext returned by the call to GetCommand. - protected override void PrepareSession(ActivityImplementationContext implementationContext) - { - if (implementationContext.PSActivityEnvironment == null) - { - implementationContext.PSActivityEnvironment = new PSActivityEnvironment(); - } - - // Update the preference variables - UpdatePreferenceVariables(implementationContext); - System.Management.Automation.PowerShell session = implementationContext.PowerShellInstance; - - implementationContext.PSActivityEnvironment.Variables["UserName"] = System.Environment.UserName; - - string computerName = null; - if (implementationContext.ConnectionInfo != null) - { - computerName = implementationContext.ConnectionInfo.ComputerName; - } - if (string.IsNullOrEmpty(computerName)) - { - computerName = "localhost"; - } - - implementationContext.PSActivityEnvironment.Variables["ComputerName"] = computerName; - implementationContext.PSActivityEnvironment.Variables["PSComputerName"] = computerName; - - string workflowCommandName = null; - - Dictionary activityVariables = (Dictionary)implementationContext.WorkflowContext; - if (activityVariables != null && activityVariables.ContainsKey("ParameterDefaults")) - { - HostParameterDefaults defaults = activityVariables["ParameterDefaults"] as HostParameterDefaults; - if (defaults != null) - { - workflowCommandName = defaults.Parameters["WorkflowCommandName"] as string; - } - } - - if (string.IsNullOrEmpty(workflowCommandName)) - { - workflowCommandName = "unknown"; - } - - implementationContext.PSActivityEnvironment.Variables["CommandName"] = workflowCommandName; - - // Populate the default variables - InlineScriptContext inlineScriptContext = new InlineScriptContext(this); - - // Populate the activity variables - foreach (KeyValuePair entry in activityVariables) - { - if (String.Equals(entry.Key, "ParameterDefaults", StringComparison.OrdinalIgnoreCase)) - { - System.Diagnostics.Debug.Assert(entry.Value is HostParameterDefaults, "ParameterDefaults does not contain a HostParameterDefaults object"); - inlineScriptContext.Variables[entry.Key] = ((HostParameterDefaults)entry.Value).Parameters; - continue; - } - inlineScriptContext.Variables[entry.Key] = entry.Value; - } - - // Set the PowerShell session variables... - foreach (KeyValuePair entry in activityVariables) - { - var value = entry.Value; - - if (String.Equals(entry.Key, "ParameterDefaults", StringComparison.OrdinalIgnoreCase)) - continue; - implementationContext.PSActivityEnvironment.Variables[entry.Key] = value; - } - } - - // InlineScript needs to handle these specially, since it might go through the PowerShell AddScript() API. - // If the parameter "CommandName" is in use, we add the preference configuration to the command parameters, - // otherwise, we add the preference configuration to the preference variable. - // All other activities have this set automatically by the infrastructure via parameters. - private void UpdatePreferenceVariables(ActivityImplementationContext implementationContext) - { - System.Management.Automation.PowerShell session = implementationContext.PowerShellInstance; - System.Management.Automation.Runspaces.Command command = null; - - if (!_commandSpecified) - { - // "CommandName" and "Parameters" are in use - command = session.Commands.Commands[0]; - } - - if (implementationContext.Verbose != null) - { - if (command != null) - { - command.Parameters.Add("Verbose", implementationContext.Verbose); - } - else - { - // Map the boolean / switch to an actual action preference - ActionPreference preference = ActionPreference.SilentlyContinue; - - if (implementationContext.Verbose.Value) - preference = ActionPreference.Continue; - - implementationContext.PSActivityEnvironment.Variables["VerbosePreference"] = preference; - } - } - - if (implementationContext.Debug != null) - { - if (command != null) - { - command.Parameters.Add("Debug", implementationContext.Debug); - } - else - { - // Map the boolean / switch to an actual action preference - ActionPreference preference = ActionPreference.SilentlyContinue; - - if (implementationContext.Debug.Value) - preference = ActionPreference.Continue; - - implementationContext.PSActivityEnvironment.Variables["DebugPreference"] = preference; - } - } - - if (implementationContext.WhatIf != null && command != null) - { - command.Parameters.Add("WhatIf", implementationContext.WhatIf); - } - - if (implementationContext.ErrorAction != null) - { - if (command != null) - { - command.Parameters.Add("ErrorAction", implementationContext.ErrorAction); - } - else - { - implementationContext.PSActivityEnvironment.Variables["ErrorActionPreference"] = implementationContext.ErrorAction; - } - } - - if (implementationContext.WarningAction != null) - { - if (command != null) - { - command.Parameters.Add("WarningAction", implementationContext.WarningAction); - } - else - { - implementationContext.PSActivityEnvironment.Variables["WarningPreference"] = implementationContext.WarningAction; - } - } - - if (implementationContext.InformationAction != null) - { - if (command != null) - { - command.Parameters.Add("InformationAction", implementationContext.InformationAction); - } - else - { - implementationContext.PSActivityEnvironment.Variables["InformationPreference"] = implementationContext.InformationAction; - } - } - - } - - static CommandInfo _ci; - static readonly object Syncroot = new object(); - } - - /// - /// Defines the context information available to scripts running within the - /// InlineScript activity. These are exposed through the $PSActivity automatic - /// variable. - /// - public class InlineScriptContext - { - /// - /// Creates a new InlineScriptContext - /// - /// The InlineScript activity being invoked - public InlineScriptContext(InlineScript current) - { - this.current = current; - this.variables = new Dictionary(StringComparer.OrdinalIgnoreCase); - this.current = null; - } - - /// - /// Gets the current InlineScript activity being invoked. - /// - //public InlineScript Current - //{ - // get { return current; } - //} - private InlineScript current; - - /// - /// Gets the current variables and arguments that are in-scope for - /// the current activity within its context in the workflow. - /// - public Dictionary Variables - { - get { return variables; } - } - private Dictionary variables; - } - - /// - /// Suspends the current workflow. - /// - public class Suspend : NativeActivity - { - /// - /// Optional field used for resuming the workflow for a specific label. - /// - public string Label { get; set; } - - /// - /// Returns true if the activity can induce an idle. - /// - protected override bool CanInduceIdle { get { return true; } } - - /// - /// Invokes the activity - /// - /// The activity context. - /// True if the given argument is set. - protected override void Execute(NativeActivityContext context) - { - string bookmarkname = string.IsNullOrEmpty(this.Label) ? - PSActivity.PSSuspendBookmarkPrefix : - PSActivity.PSSuspendBookmarkPrefix + this.Label + "_"; - - bookmarkname += Guid.NewGuid().ToString().Replace("-", "_"); - - context.CreateBookmark(bookmarkname, BookmarkResumed); - } - - private void BookmarkResumed(NativeActivityContext context, Bookmark bookmark, object value) - { - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/InlineScriptDesigner.xaml.cs b/src/Microsoft.PowerShell.Activities/Activities/InlineScriptDesigner.xaml.cs deleted file mode 100644 index a8580782e..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/InlineScriptDesigner.xaml.cs +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (C) Microsoft. All rights reserved. -// -#if _NOTARMBUILD_ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Interaction logic for InlineScriptDesigner.xaml - /// - public partial class InlineScriptDesigner - { - /// - /// Create the designer instance - /// - public InlineScriptDesigner() - { - InitializeComponent(); - } - } -} -#endif \ No newline at end of file diff --git a/src/Microsoft.PowerShell.Activities/Activities/InvokeCimMethodActivity.cs b/src/Microsoft.PowerShell.Activities/Activities/InvokeCimMethodActivity.cs deleted file mode 100644 index 5dda7530c..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/InvokeCimMethodActivity.cs +++ /dev/null @@ -1,170 +0,0 @@ - -using Microsoft.PowerShell.Activities; -using System.Activities; -using System.Collections.Generic; -using System.ComponentModel; - - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Activity to invoke the CimCmdlets\Invoke-CimMethod command in a Workflow. - /// - [System.CodeDom.Compiler.GeneratedCode("Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromName", "3.0")] - public sealed class InvokeCimMethod : GenericCimCmdletActivity - { - /// - /// Gets the display name of the command invoked by this activity. - /// - public InvokeCimMethod() - { - this.DisplayName = "Invoke-CimMethod"; - } - - /// - /// Gets the fully qualified name of the command invoked by this activity. - /// - public override string PSCommandName { get { return "CimCmdlets\\Invoke-CimMethod"; } } - - /// - /// The .NET type implementing the cmdlet to invoke. - /// - public override System.Type TypeImplementingCmdlet { get { return typeof(Microsoft.Management.Infrastructure.CimCmdlets.InvokeCimMethodCommand); } } - - // Arguments - - /// - /// Provides access to the ClassName parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument ClassName { get; set; } - - /// - /// Provides access to the CimClass parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument CimClass { get; set; } - - /// - /// Provides access to the Query parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Query { get; set; } - - /// - /// Provides access to the QueryDialect parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument QueryDialect { get; set; } - - /// - /// Provides access to the InputObject parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument InputObject { get; set; } - - /// - /// Provides access to the Arguments parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Arguments { get; set; } - - /// - /// Provides access to the MethodName parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument MethodName { get; set; } - - /// - /// Provides access to the Namespace parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Namespace { get; set; } - - /// - /// Provides access to the OperationTimeoutSec parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument OperationTimeoutSec { get; set; } - - /// - /// Script module contents for this activity - /// - protected override string PSDefiningModule { get { return null; } } - - /// - /// Returns a configured instance of System.Management.Automation.PowerShell, pre-populated with the command to run. - /// - /// The NativeActivityContext for the currently running activity. - /// A populated instance of System.Management.Automation.PowerShell - /// The infrastructure takes responsibility for closing and disposing the PowerShell instance returned. - protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) - { - System.Management.Automation.PowerShell invoker = global::System.Management.Automation.PowerShell.Create(); - System.Management.Automation.PowerShell targetCommand = invoker.AddCommand(PSCommandName); - - // Initialize the arguments - - if(ClassName.Expression != null) - { - targetCommand.AddParameter("ClassName", ClassName.Get(context)); - } - - if(CimClass.Expression != null) - { - targetCommand.AddParameter("CimClass", CimClass.Get(context)); - } - - if(Query.Expression != null) - { - targetCommand.AddParameter("Query", Query.Get(context)); - } - - if(QueryDialect.Expression != null) - { - targetCommand.AddParameter("QueryDialect", QueryDialect.Get(context)); - } - - if (InputObject.Expression != null) - { - targetCommand.AddParameter("InputObject", InputObject.Get(context)); - } - - if(Arguments.Expression != null) - { - targetCommand.AddParameter("Arguments", Arguments.Get(context)); - } - - if(MethodName.Expression != null) - { - targetCommand.AddParameter("MethodName", MethodName.Get(context)); - } - - if(Namespace.Expression != null) - { - targetCommand.AddParameter("Namespace", Namespace.Get(context)); - } - - if(OperationTimeoutSec.Expression != null) - { - targetCommand.AddParameter("OperationTimeoutSec", OperationTimeoutSec.Get(context)); - } - - if (ResourceUri != null) - { - targetCommand.AddParameter("ResourceUri", ResourceUri.Get(context)); - } - - return new ActivityImplementationContext() { PowerShellInstance = invoker }; - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/IsArgumentSet.cs b/src/Microsoft.PowerShell.Activities/Activities/IsArgumentSet.cs deleted file mode 100644 index f1e136558..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/IsArgumentSet.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (C) Microsoft. All rights reserved. -// -using System; -using System.Activities; -using System.Collections.Generic; -using System.Globalization; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.ComponentModel; -using System.Text; -using System.Reflection; - -namespace Microsoft.PowerShell.Activities.Internal -{ - /// - /// Determines whether an argument to a PSActivity activity - /// has been set. - /// - [SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes", Justification = "Needed Internal use only")] - public class IsArgumentSet : CodeActivity - { - /// - /// The argument to investigate. - /// - [DefaultValue(null)] - public Argument Argument { get; set; } - - /// - /// Invokes the activity - /// - /// The activity context. - /// True if the given argument is set. - protected override bool Execute(CodeActivityContext context) - { - return Argument != null && Argument.Expression != null; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.PowerShell.Activities/Activities/NewCimInstanceActivity.cs b/src/Microsoft.PowerShell.Activities/Activities/NewCimInstanceActivity.cs deleted file mode 100644 index 7d503cb4e..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/NewCimInstanceActivity.cs +++ /dev/null @@ -1,163 +0,0 @@ - -using Microsoft.PowerShell.Activities; -using System.Activities; -using System.Collections.Generic; -using System.ComponentModel; - - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Activity to invoke the CimCmdlets\New-CimInstance command in a Workflow. - /// - [System.CodeDom.Compiler.GeneratedCode("Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromName", "3.0")] - public sealed class NewCimInstance : GenericCimCmdletActivity - { - /// - /// Gets the display name of the command invoked by this activity. - /// - public NewCimInstance() - { - this.DisplayName = "New-CimInstance"; - } - - /// - /// Gets the fully qualified name of the command invoked by this activity. - /// - public override string PSCommandName { get { return "CimCmdlets\\New-CimInstance"; } } - - /// - /// The .NET type implementing the cmdlet to invoke. - /// - public override System.Type TypeImplementingCmdlet { get { return typeof(Microsoft.Management.Infrastructure.CimCmdlets.NewCimInstanceCommand); } } - - // Arguments - - /// - /// Provides access to the ClassName parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument ClassName { get; set; } - - /// - /// Provides access to the Key parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Key { get; set; } - - /// - /// Provides access to the CimClass parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument CimClass { get; set; } - - /// - /// Provides access to the Property parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Property { get; set; } - - /// - /// Provides access to the Namespace parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Namespace { get; set; } - - /// - /// Provides access to the OperationTimeoutSec parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument OperationTimeoutSec { get; set; } - - - /// - /// Provides access to the ClientOnly parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument ClientOnly { get; set; } - - /// - /// Script module contents for this activity`n/// - protected override string PSDefiningModule { get { return null; } } - - /// - /// Returns a configured instance of System.Management.Automation.PowerShell, pre-populated with the command to run. - /// - /// The NativeActivityContext for the currently running activity. - /// A populated instance of System.Management.Automation.PowerShell - /// The infrastructure takes responsibility for closing and disposing the PowerShell instance returned. - protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) - { - System.Management.Automation.PowerShell invoker = global::System.Management.Automation.PowerShell.Create(); - System.Management.Automation.PowerShell targetCommand = invoker.AddCommand(PSCommandName); - - // Initialize the arguments - - if(ClassName.Expression != null) - { - targetCommand.AddParameter("ClassName", ClassName.Get(context)); - } - - if(Key.Expression != null) - { - targetCommand.AddParameter("Key", Key.Get(context)); - } - - if(CimClass.Expression != null) - { - targetCommand.AddParameter("CimClass", CimClass.Get(context)); - } - - if(Property.Expression != null) - { - targetCommand.AddParameter("Property", Property.Get(context)); - } - - if(Namespace.Expression != null) - { - targetCommand.AddParameter("Namespace", Namespace.Get(context)); - } - - if(OperationTimeoutSec.Expression != null) - { - targetCommand.AddParameter("OperationTimeoutSec", OperationTimeoutSec.Get(context)); - } - - if (ResourceUri != null) - { - targetCommand.AddParameter("ResourceUri", ResourceUri.Get(context)); - } - - if (ClientOnly.Expression != null) - { - // Retrieve our host overrides - var hostValues = context.GetExtension(); - string[] computerName = null; - - if (hostValues != null) - { - Dictionary incomingArguments = hostValues.Parameters; - if (incomingArguments.ContainsKey("PSComputerName")) - { - computerName = incomingArguments["PSComputerName"] as string[]; - } - } - - if (computerName == null) - { - targetCommand.AddParameter("ClientOnly", ClientOnly.Get(context)); - } - } - - - return new ActivityImplementationContext() { PowerShellInstance = invoker }; - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/NewCimSessionActivity.cs b/src/Microsoft.PowerShell.Activities/Activities/NewCimSessionActivity.cs deleted file mode 100644 index 291c9ef5a..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/NewCimSessionActivity.cs +++ /dev/null @@ -1,148 +0,0 @@ - -using Microsoft.PowerShell.Activities; -using System.Activities; -using System.Collections.Generic; -using System.ComponentModel; - - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Activity to invoke the CimCmdlets\New-CimSession command in a Workflow. - /// - [System.CodeDom.Compiler.GeneratedCode("Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromName", "3.0")] - public sealed class NewCimSession : GenericCimCmdletActivity - { - /// - /// Gets the display name of the command invoked by this activity. - /// - public NewCimSession() - { - this.DisplayName = "New-CimSession"; - } - - /// - /// Gets the fully qualified name of the command invoked by this activity. - /// - public override string PSCommandName { get { return "CimCmdlets\\New-CimSession"; } } - - /// - /// The .NET type implementing the cmdlet to invoke. - /// - public override System.Type TypeImplementingCmdlet { get { return typeof(Microsoft.Management.Infrastructure.CimCmdlets.NewCimSessionCommand); } } - - // Arguments - - /// - /// Provides access to the Authentication parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Authentication { get; set; } - - /// - /// Provides access to the Credential parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Credential { get; set; } - - /// - /// Provides access to the CertificateThumbprint parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument CertificateThumbprint { get; set; } - - /// - /// Provides access to the Name parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Name { get; set; } - - /// - /// Provides access to the OperationTimeoutSec parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument OperationTimeoutSec { get; set; } - - /// - /// Provides access to the Port parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Port { get; set; } - - /// - /// Provides access to the SessionOption parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument SessionOption { get; set; } - - - - /// - /// Script module contents for this activity`n/// - protected override string PSDefiningModule { get { return "CimCmdlets"; } } - - /// - /// Returns a configured instance of System.Management.Automation.PowerShell, pre-populated with the command to run. - /// - /// The NativeActivityContext for the currently running activity. - /// A populated instance of System.Management.Automation.PowerShell - /// The infrastructure takes responsibility for closing and disposing the PowerShell instance returned. - protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) - { - System.Management.Automation.PowerShell invoker = global::System.Management.Automation.PowerShell.Create(); - System.Management.Automation.PowerShell targetCommand = invoker.AddCommand(PSCommandName); - - // Initialize the arguments - - if (GetIsComputerNameSpecified(context)) - { - targetCommand.AddParameter("ComputerName", PSComputerName.Get(context)); - } - - if(Authentication.Expression != null) - { - targetCommand.AddParameter("Authentication", Authentication.Get(context)); - } - - if(Credential.Expression != null) - { - targetCommand.AddParameter("Credential", Credential.Get(context)); - } - - if(CertificateThumbprint.Expression != null) - { - targetCommand.AddParameter("CertificateThumbprint", CertificateThumbprint.Get(context)); - } - - if(Name.Expression != null) - { - targetCommand.AddParameter("Name", Name.Get(context)); - } - - if(OperationTimeoutSec.Expression != null) - { - targetCommand.AddParameter("OperationTimeoutSec", OperationTimeoutSec.Get(context)); - } - - if(Port.Expression != null) - { - targetCommand.AddParameter("Port", Port.Get(context)); - } - - if(SessionOption.Expression != null) - { - targetCommand.AddParameter("SessionOption", SessionOption.Get(context)); - } - - - return new ActivityImplementationContext() { PowerShellInstance = invoker }; - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/NewCimSessionOptionActivity.cs b/src/Microsoft.PowerShell.Activities/Activities/NewCimSessionOptionActivity.cs deleted file mode 100644 index 695072fff..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/NewCimSessionOptionActivity.cs +++ /dev/null @@ -1,286 +0,0 @@ - -using Microsoft.PowerShell.Activities; -using System.Activities; -using System.Collections.Generic; -using System.ComponentModel; - - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Activity to invoke the CimCmdlets\New-CimSessionOption command in a Workflow. - /// - [System.CodeDom.Compiler.GeneratedCode("Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromName", "3.0")] - public sealed class NewCimSessionOption : GenericCimCmdletActivity - { - /// - /// Gets the display name of the command invoked by this activity. - /// - public NewCimSessionOption() - { - this.DisplayName = "New-CimSessionOption"; - } - - /// - /// Gets the fully qualified name of the command invoked by this activity. - /// - public override string PSCommandName { get { return "CimCmdlets\\New-CimSessionOption"; } } - - /// - /// The .NET type implementing the cmdlet to invoke. - /// - public override System.Type TypeImplementingCmdlet { get { return typeof(Microsoft.Management.Infrastructure.CimCmdlets.NewCimSessionOptionCommand); } } - - // Arguments - - /// - /// Provides access to the NoEncryption parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument NoEncryption { get; set; } - - /// - /// Provides access to the CertificateCACheck parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument CertificateCACheck { get; set; } - - /// - /// Provides access to the CertificateCNCheck parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument CertificateCNCheck { get; set; } - - /// - /// Provides access to the CertRevocationCheck parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument CertRevocationCheck { get; set; } - - /// - /// Provides access to the EncodePortInServicePrincipalName parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument EncodePortInServicePrincipalName { get; set; } - - /// - /// Provides access to the Encoding parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Encoding { get; set; } - - /// - /// Provides access to the HttpPrefix parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument HttpPrefix { get; set; } - - /// - /// Provides access to the MaxEnvelopeSizeKB parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument MaxEnvelopeSizeKB { get; set; } - - /// - /// Provides access to the ProxyAuthentication parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument ProxyAuthentication { get; set; } - - /// - /// Provides access to the ProxyCertificateThumbprint parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument ProxyCertificateThumbprint { get; set; } - - /// - /// Provides access to the ProxyCredential parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument ProxyCredential { get; set; } - - /// - /// Provides access to the ProxyType parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument ProxyType { get; set; } - - /// - /// Provides access to the UseSsl parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument UseSsl { get; set; } - - /// - /// Provides access to the Impersonation parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Impersonation { get; set; } - - /// - /// Provides access to the PacketIntegrity parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument PacketIntegrity { get; set; } - - /// - /// Provides access to the PacketPrivacy parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument PacketPrivacy { get; set; } - - /// - /// Provides access to the Protocol parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Protocol { get; set; } - - /// - /// Provides access to the UICulture parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument UICulture { get; set; } - - /// - /// Provides access to the Culture parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Culture { get; set; } - - - /// - /// Script module contents for this activity`n/// - protected override string PSDefiningModule { get { return null; } } - - /// - /// Returns a configured instance of System.Management.Automation.PowerShell, pre-populated with the command to run. - /// - /// The NativeActivityContext for the currently running activity. - /// A populated instance of System.Management.Automation.PowerShell - /// The infrastructure takes responsibility for closing and disposing the PowerShell instance returned. - protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) - { - System.Management.Automation.PowerShell invoker = global::System.Management.Automation.PowerShell.Create(); - System.Management.Automation.PowerShell targetCommand = invoker.AddCommand(PSCommandName); - - // Initialize the arguments - - if(NoEncryption.Expression != null) - { - targetCommand.AddParameter("NoEncryption", NoEncryption.Get(context)); - } - - if(CertificateCACheck.Expression != null) - { - targetCommand.AddParameter("CertificateCACheck", CertificateCACheck.Get(context)); - } - - if(CertificateCNCheck.Expression != null) - { - targetCommand.AddParameter("CertificateCNCheck", CertificateCNCheck.Get(context)); - } - - if(CertRevocationCheck.Expression != null) - { - targetCommand.AddParameter("CertRevocationCheck", CertRevocationCheck.Get(context)); - } - - if(EncodePortInServicePrincipalName.Expression != null) - { - targetCommand.AddParameter("EncodePortInServicePrincipalName", EncodePortInServicePrincipalName.Get(context)); - } - - if(Encoding.Expression != null) - { - targetCommand.AddParameter("Encoding", Encoding.Get(context)); - } - - if(HttpPrefix.Expression != null) - { - targetCommand.AddParameter("HttpPrefix", HttpPrefix.Get(context)); - } - - if(MaxEnvelopeSizeKB.Expression != null) - { - targetCommand.AddParameter("MaxEnvelopeSizeKB", MaxEnvelopeSizeKB.Get(context)); - } - - if(ProxyAuthentication.Expression != null) - { - targetCommand.AddParameter("ProxyAuthentication", ProxyAuthentication.Get(context)); - } - - if(ProxyCertificateThumbprint.Expression != null) - { - targetCommand.AddParameter("ProxyCertificateThumbprint", ProxyCertificateThumbprint.Get(context)); - } - - if(ProxyCredential.Expression != null) - { - targetCommand.AddParameter("ProxyCredential", ProxyCredential.Get(context)); - } - - if(ProxyType.Expression != null) - { - targetCommand.AddParameter("ProxyType", ProxyType.Get(context)); - } - - if(UseSsl.Expression != null) - { - targetCommand.AddParameter("UseSsl", UseSsl.Get(context)); - } - - if(Impersonation.Expression != null) - { - targetCommand.AddParameter("Impersonation", Impersonation.Get(context)); - } - - if(PacketIntegrity.Expression != null) - { - targetCommand.AddParameter("PacketIntegrity", PacketIntegrity.Get(context)); - } - - if(PacketPrivacy.Expression != null) - { - targetCommand.AddParameter("PacketPrivacy", PacketPrivacy.Get(context)); - } - - if(Protocol.Expression != null) - { - targetCommand.AddParameter("Protocol", Protocol.Get(context)); - } - - if(UICulture.Expression != null) - { - targetCommand.AddParameter("UICulture", UICulture.Get(context)); - } - - if(Culture.Expression != null) - { - targetCommand.AddParameter("Culture", Culture.Get(context)); - } - - - return new ActivityImplementationContext() { PowerShellInstance = invoker }; - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/PSPersist.cs b/src/Microsoft.PowerShell.Activities/Activities/PSPersist.cs deleted file mode 100644 index 266c5056d..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/PSPersist.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (C) Microsoft. All rights reserved. -// -using System; -using System.Activities; -using System.Collections.Generic; -using System.Globalization; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.ComponentModel; -using System.Text; -using System.Reflection; - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Persist the current workflow. Also defines the persistence point where suspend-job is getting suspended. - /// - public class PSPersist : NativeActivity - { - /// - /// Returns true if the activity can induce an idle. - /// - protected override bool CanInduceIdle { get { return true; } } - - /// - /// Invokes the activity - /// - /// The activity context. - protected override void Execute(NativeActivityContext context) - { - string bookmarkname = PSActivity.PSPersistBookmarkPrefix + Guid.NewGuid().ToString().Replace("-", "_"); - context.CreateBookmark(bookmarkname, BookmarkResumed); - - } - - private void BookmarkResumed(NativeActivityContext context, Bookmark bookmark, object value) - { - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/Pipeline.cs b/src/Microsoft.PowerShell.Activities/Activities/Pipeline.cs deleted file mode 100644 index fba27cc72..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/Pipeline.cs +++ /dev/null @@ -1,296 +0,0 @@ -// -// Copyright (C) Microsoft. All rights reserved. -// -using System; -using System.Activities; -using System.Activities.Validation; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Runtime; -using System.Activities.Statements; -using System.Management.Automation; -using System.ComponentModel; - -namespace Microsoft.PowerShell.Activities -{ - /// - /// The implementation of pipeline activity. - /// This similar concept which we have in PowerShell today like Get-Process | Stop-Process. - /// Pipeline activity will make sure the piped execution of its child activities. - /// -#if _NOTARMBUILD_ - [Designer (typeof (PipelineDesigner))] -#endif - public sealed class Pipeline : PipelineEnabledActivity - { - /// - /// Tracks the number of current child activity in the collection. - /// - private Variable lastIndexHint; - - private bool inputValidationFailed; - private bool resultValidationFailed; - - /// - /// Maintain intermediate outflow of data from child activity. - /// - private Variable> OutputStream; - - /// - /// Maintain intermediate inflow of data into child activity. - /// - private Variable> InputStream; - - /// - /// Get activities. - /// - [RequiredArgument] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", - "CA2227:CollectionPropertiesShouldBeReadOnly", - Justification = "This is needs to support assignment via workflow.")] - public Collection Activities { get; set; } - - /// - /// Default constructor - /// - public Pipeline() - : base() - { - this.lastIndexHint = new Variable(); - this.Activities = new Collection(); - - this.inputValidationFailed = false; - this.resultValidationFailed = false; - } - - /// - /// Validate the required number of activities of pipeline activity. - /// Setup the cachemetadata with variables and activities. - /// - /// - protected override void CacheMetadata(NativeActivityMetadata metadata) - { - int count = 0; - - if (this.Activities != null) - { - count = this.Activities.Count; - } - - if (count == 0) - { - metadata.AddValidationError(new ValidationError(ActivityResources.NoChildPipeline, true)); - return; - } - - //BUGBUG: As written, the following checks cause error in scenarios where they should not. - // They are left in for the time being but disabled until we verify that there are no - // scenarios where we need to check for two variables being assigned. -#if false - if (Input != null && Input.Expression != null && this.Activities[0].Input != null && this.Activities[0].Input.Expression != null) - { - metadata.AddValidationError(new ValidationError(ActivityResources.DuplicateInputDefinedInPipeline, true)); - this.inputValidationFailed = true; - return; - } - - if (Result != null && Result.Expression != null && this.Activities[count - 1].Result != null && this.Activities[count - 1].Result.Expression != null) - { - metadata.AddValidationError(new ValidationError(ActivityResources.DuplicateResultDefinedInPipeline, true)); - this.resultValidationFailed = true; - return; - } -#endif - // Adding variables into the CacheMetadata of pipeline activity. - metadata.AddImplementationVariable(this.lastIndexHint); - - // We use a GUID here to make this name hard to guess. It's not a security issue, - // it just prevents code from accidentally taking a dependency on it. - this.OutputStream = new Variable>(Guid.NewGuid().ToString().Replace("-","_")); - this.InputStream = new Variable>(Guid.NewGuid().ToString().Replace("-","_")); - - metadata.AddVariable(this.OutputStream); - metadata.AddVariable(this.InputStream); - - bool appendOutput = false; - if ((this.AppendOutput != null) && (this.AppendOutput.Value)) - { - appendOutput = true; - } - - // Adding activities into the CacheMetadata of pipeline activity. - if (count == 1) - { - - if (Input != null && Input.Expression != null) - { - this.Activities[0].Input = this.Input; - } - - if (Result != null && Result.Expression != null) - { - this.Activities[0].Result = this.Result; - } - - if (appendOutput) - { - this.Activities[0].AppendOutput = true; - } - - metadata.AddChild(this.Activities[0]); - } - else - { - - if (Input != null && Input.Expression != null) - { - this.Activities[0].Input = this.Input; - } - - // Connecting child activities with temporary input and out streams. - this.Activities[0].Result = this.OutputStream; - metadata.AddChild(this.Activities[0]); - - for (int i = 1; i < (count - 1); i++) - { - this.Activities[i].Input = this.InputStream; - this.Activities[i].Result = this.OutputStream; - - metadata.AddChild(this.Activities[i]); - } - - if (Result != null && Result.Expression != null) - { - this.Activities[count - 1].Result = this.Result; - } - - if (appendOutput) - { - this.Activities[count - 1].AppendOutput = true; - } - - this.Activities[count - 1].Input = this.InputStream; - metadata.AddChild(this.Activities[count - 1]); - } - } - - /// - /// Executes the first child activity - /// - /// The execution context of pipeline activity. - protected override void Execute(NativeActivityContext executionContext) - { - int count = 0; - - if (this.Activities != null) - { - count = this.Activities.Count; - } - - if (count == 0) - { - throw new ArgumentException(ActivityResources.NoChildPipeline); - } - - if (this.inputValidationFailed && Input != null && Input.Expression != null && this.Activities[0].Input != null && this.Activities[0].Input.Expression != null) - { - throw new ArgumentException(ActivityResources.DuplicateInputDefinedInPipeline); - } - - if (this.resultValidationFailed && Result != null && Result.Expression != null && this.Activities[count - 1].Result != null && this.Activities[count - 1].Result.Expression != null) - { - throw new ArgumentException(ActivityResources.DuplicateResultDefinedInPipeline); - } - - //Executing the first child activity. - PipelineEnabledActivity firstChild = this.Activities[0]; - executionContext.ScheduleActivity(firstChild, new CompletionCallback(InternalExecute)); - } - - /// - /// Get results from previous activity and schedule the execution of next activity. - /// - /// The execution context of pipeline activity. - /// The activity instance of completed child activity. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - private void InternalExecute(NativeActivityContext executionContext, ActivityInstance completedInstance) - { - int completedInstanceIndex; - - // Reading the value of pipeline activity variables from the context. - completedInstanceIndex = this.lastIndexHint.Get(executionContext); - - PSDataCollection outValue = this.GetData(executionContext, this.OutputStream); - PSDataCollection inValue = this.GetData(executionContext, this.InputStream); - - // Re-checking the index of the the child activity, which has just completed its execution. - if (completedInstanceIndex >= this.Activities.Count || this.Activities[completedInstanceIndex] != completedInstance.Activity) - { - completedInstanceIndex = this.Activities.IndexOf((PSActivity) completedInstance.Activity); - } - - // Calculating next child activity. - int nextChildIndex = completedInstanceIndex + 1; - - // Checking for pipeline activity completion. - if (nextChildIndex == this.Activities.Count) - { - if (inValue != null) inValue.Dispose(); - if (outValue != null) outValue.Dispose(); - return; - } - - // Setting up the environment for next child activity to run. - if (outValue != null) outValue.Complete(); - if (inValue != null) inValue.Dispose(); - - inValue = outValue; - outValue = new PSDataCollection(); - - // The pipeline is complete if there is no input - // PS > function foo { $input | Write-Output "Hello" } - // PS > foo - // PS > - if ((inValue == null) || (inValue.Count == 0)) - { - if (outValue != null) outValue.Dispose(); - return; - } - - this.SetData(executionContext, this.OutputStream, outValue); - this.SetData(executionContext, this.InputStream, inValue); - - // Executing the next child activity. - PipelineEnabledActivity nextChild = this.Activities[nextChildIndex]; - - executionContext.ScheduleActivity(nextChild, new CompletionCallback(InternalExecute)); - - this.lastIndexHint.Set(executionContext, nextChildIndex); - } - - /// - /// Get the data from the pipeline variable. - /// - /// The activity context. - /// The variable which value to get. - /// Returns the value of the variable. - private PSDataCollection GetData(ActivityContext context, Variable> variable) - { - PropertyDescriptor prop = context.DataContext.GetProperties()[variable.Name]; - return (PSDataCollection)prop.GetValue(context.DataContext); - } - - /// - /// Set the data to the pipeline variable. - /// - /// The activity context. - /// The variable which needs to set. - /// The value for the variable. - private void SetData(ActivityContext context, Variable> variable, PSDataCollection value) - { - PropertyDescriptor prop = context.DataContext.GetProperties()[variable.Name]; - prop.SetValue(context.DataContext, value); - } - - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/PipelineDesigner.xaml.cs b/src/Microsoft.PowerShell.Activities/Activities/PipelineDesigner.xaml.cs deleted file mode 100644 index 713ef39e8..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/PipelineDesigner.xaml.cs +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright (C) Microsoft. All rights reserved. -// - -#if _NOTARMBUILD_ -namespace Microsoft.PowerShell.Activities -{ - /// - /// Interaction logic for PipelineDesigner.xaml - /// - public partial class PipelineDesigner - { - /// - /// Default Constructor. - /// - public PipelineDesigner() - { - InitializeComponent(); - } - - } -} -#endif \ No newline at end of file diff --git a/src/Microsoft.PowerShell.Activities/Activities/PowerShellValue.cs b/src/Microsoft.PowerShell.Activities/Activities/PowerShellValue.cs deleted file mode 100644 index 9c1e7cf46..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/PowerShellValue.cs +++ /dev/null @@ -1,564 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Collections.Concurrent; -using System.ComponentModel; -using System.Globalization; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Activities; -using System.Diagnostics; -using System.Management.Automation; -using System.Management.Automation.Language; -using System.Management.Automation.Runspaces; - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Evaluate the Powershell expression and return the value of type T. - /// - public sealed class PowerShellValue : NativeActivity - { - /// - /// The PowerShell expression, which will be evaluated and retuned a type of T value. - /// - [RequiredArgument] - public string Expression { get; set; } - - /// - /// Determines whether to connect the input stream for this activity. - /// - [DefaultValue(false)] - public bool UseDefaultInput - { - get; - set; - } - - /// - /// Validates the syntax of the script text for this activity. - /// - /// Activity metadata for this activity - protected override void CacheMetadata(NativeActivityMetadata metadata) - { - base.CacheMetadata(metadata); - - if (!string.IsNullOrWhiteSpace(Expression)) - { - var errors = new Collection(); - PSParser.Tokenize(Expression, out errors); - if (errors != null && errors.Count > 0) - { - string compositeErrorString = ""; - foreach (var e in errors) - { - // Format and add each error message... - compositeErrorString += string.Format(CultureInfo.InvariantCulture, - "[{0}, {1}]: {2}\n", e.Token.StartLine, e.Token.StartColumn, e.Message); - } - metadata.AddValidationError(compositeErrorString); - } - } - } - - /// - /// Get the scriptblock for this activity, caching it once it's compiled. - /// - private ScriptBlock ExpressionScriptBlock - { - get - { - if (_expressionScriptBlock == null) - { - lock (syncroot) - { - if (_expressionScriptBlock == null) - { - // The guard check for a null expression string is done in Execute() instead - // of in this property. It's also done in the validation check for CacheMetadata - string updatedExpression = Expression; - - // Hack to make sure the $input *does* get unrolled... - if (string.Equals("$input", Expression.Trim(), StringComparison.OrdinalIgnoreCase)) - { - updatedExpression = "$(" + updatedExpression + "\n)"; - } - else - { - Token[] tokens; - ParseError[] errors; - ScriptBlockAst exprAst = Parser.ParseInput(updatedExpression, out tokens, out errors); - if (errors.Length > 0) - { - throw new ParseException(errors); - } - - if (exprAst.BeginBlock == null && exprAst.ProcessBlock == null && exprAst.EndBlock != null) - { - var statements = exprAst.EndBlock.Statements; - if (statements != null && statements.Count == 1) - { - PipelineAst pipeline = statements[0] as PipelineAst; - if (pipeline != null && pipeline.GetPureExpression() != null) - { - // It is very difficult to get equivalent expression semantics in workflow because the engine - // APIs get in the way necessitating a lot of fiddling with the actual expression as well as post-processing - // the result of the expression. - // We wrap a pure expression in an array so that PowerShell's loop unrolling doesn't impact our - // ability to return collections. We also add a trap/break so that terminating errors in expressions - // are turned into exceptions for the PowerShell object. The trap and closing ')' go on their own line - // for the XAML designer case where the expression might have a trailing '#' making the rest of the - // line into a comment. - updatedExpression = ",(" + updatedExpression + "\n); trap { break }"; - } - } - } - } - - _expressionScriptBlock = ScriptBlock.Create(updatedExpression); - } - } - } - return _expressionScriptBlock; - } - } - ScriptBlock _expressionScriptBlock; - - /// - /// Check to see if the expression only uses elements of the restricted language - /// as well as only using the allowed commands and variables. - /// - /// - /// List of command names to allow in the expression - /// - /// - /// List of variable names to allow in the expression. If the collection contains a single - /// element "*", all variables will be allowed including environment variables - /// functions, etc. - /// - /// - /// If true, environment variables are allowed even if the allowedVariables list is empty. - /// - public void ValidateExpressionConstraints(IEnumerable allowedCommands, IEnumerable allowedVariables, bool allowEnvironmentVariables) - { - ExpressionScriptBlock.CheckRestrictedLanguage(allowedCommands, allowedVariables, allowEnvironmentVariables); - } - - /// - /// Execution of PowerShell value activity. - /// PowerShell expression will be evaluated using PowerShell runspace and the value of Type T will be returned. - /// - /// - 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 collectionObject = value as PSDataCollection; - 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 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(); - - // 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 collectionObject = value as PSDataCollection; - - 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 inputStream = null; - if (UseDefaultInput) - { - // Retrieve our host overrides - hostValues = context.GetExtension(); - - if (hostValues != null) - { - Dictionary incomingArguments = hostValues.Parameters; - if (incomingArguments.ContainsKey("Input")) - { - inputStream = incomingArguments["Input"] as PSDataCollection; - } - } - } - - // 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 errorStream = null; - - // Retrieve our host overrides - hostValues = context.GetExtension(); - - if (hostValues != null) - { - Dictionary incomingArguments = hostValues.Parameters; - if (incomingArguments.ContainsKey("PSError")) - { - errorStream = incomingArguments["PSError"] as PSDataCollection; - } - } - - 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( result ); - } - } - else - { - valueToReturn = LanguagePrimitives.ConvertTo(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 - if (typeof(T) == typeof(PSDataCollection)) - { - Object tempValueToReturn = new PSDataCollection( - new List { LanguagePrimitives.ConvertTo(returnedvalue[0]) }); - valueToReturn = (T)tempValueToReturn; - } - else - { - throw; - } - } - - Result.Set(context, valueToReturn); - } - } - } - - private static void HandleErrorDataAdding(object sender, DataAddingEventArgs e) - { - HostSettingCommandMetadata commandMetadata; - CommandMetadataTable.TryGetValue(e.PowerShellInstanceId, out commandMetadata); - - if (commandMetadata != null) - { - PowerShellInvocation_ErrorAdding(sender, e, commandMetadata); - } - } - - private static readonly ConcurrentDictionary CommandMetadataTable = - new ConcurrentDictionary(); - - private static void PowerShellInvocation_ErrorAdding(object sender, DataAddingEventArgs e, HostSettingCommandMetadata commandMetadata) - { - ErrorRecord errorRecord = e.ItemAdded as ErrorRecord; - - if (errorRecord != null) - { - if (commandMetadata != null) - { - ScriptPosition scriptStart = new ScriptPosition( - commandMetadata.CommandName, - commandMetadata.StartLineNumber, - commandMetadata.StartColumnNumber, - null); - ScriptPosition scriptEnd = new ScriptPosition( - commandMetadata.CommandName, - commandMetadata.EndLineNumber, - commandMetadata.EndColumnNumber, - null); - ScriptExtent extent = new ScriptExtent(scriptStart, scriptEnd); - - if (errorRecord.InvocationInfo != null) - { - errorRecord.InvocationInfo.DisplayScriptPosition = extent; - } - } - } - } - - static CommandInfo _ci; - static object syncroot = new object(); - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/RemoveCimInstanceActivity.cs b/src/Microsoft.PowerShell.Activities/Activities/RemoveCimInstanceActivity.cs deleted file mode 100644 index 44e6fc169..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/RemoveCimInstanceActivity.cs +++ /dev/null @@ -1,120 +0,0 @@ - -using Microsoft.PowerShell.Activities; -using System.Activities; -using System.Collections.Generic; -using System.ComponentModel; - - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Activity to invoke the CimCmdlets\Remove-CimInstance command in a Workflow. - /// - [System.CodeDom.Compiler.GeneratedCode("Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromName", "3.0")] - public sealed class RemoveCimInstance : GenericCimCmdletActivity - { - /// - /// Gets the display name of the command invoked by this activity. - /// - public RemoveCimInstance() - { - this.DisplayName = "Remove-CimInstance"; - } - - /// - /// Gets the fully qualified name of the command invoked by this activity. - /// - public override string PSCommandName { get { return "CimCmdlets\\Remove-CimInstance"; } } - - /// - /// The .NET type implementing the cmdlet to invoke. - /// - public override System.Type TypeImplementingCmdlet { get { return typeof(Microsoft.Management.Infrastructure.CimCmdlets.RemoveCimInstanceCommand); } } - - /// - /// Provides access to the Namespace parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Namespace { get; set; } - - /// - /// Provides access to the OperationTimeoutSec parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument OperationTimeoutSec { get; set; } - - /// - /// Provides access to the InputObject parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument InputObject { get; set; } - - /// - /// Provides access to the Query parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Query { get; set; } - - /// - /// Provides access to the QueryDialect parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument QueryDialect { get; set; } - - - /// - /// Script module contents for this activity`n/// - protected override string PSDefiningModule { get { return null; } } - - /// - /// Returns a configured instance of System.Management.Automation.PowerShell, pre-populated with the command to run. - /// - /// The NativeActivityContext for the currently running activity. - /// A populated instance of System.Management.Automation.PowerShell - /// The infrastructure takes responsibility for closing and disposing the PowerShell instance returned. - protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) - { - System.Management.Automation.PowerShell invoker = global::System.Management.Automation.PowerShell.Create(); - System.Management.Automation.PowerShell targetCommand = invoker.AddCommand(PSCommandName); - - // Initialize the arguments - - if(Namespace.Expression != null) - { - targetCommand.AddParameter("Namespace", Namespace.Get(context)); - } - - if(OperationTimeoutSec.Expression != null) - { - targetCommand.AddParameter("OperationTimeoutSec", OperationTimeoutSec.Get(context)); - } - - if (InputObject.Expression != null) - { - targetCommand.AddParameter("InputObject", InputObject.Get(context)); - } - - if(Query.Expression != null) - { - targetCommand.AddParameter("Query", Query.Get(context)); - } - - if(QueryDialect.Expression != null) - { - targetCommand.AddParameter("QueryDialect", QueryDialect.Get(context)); - } - - if (ResourceUri != null) - { - targetCommand.AddParameter("ResourceUri", ResourceUri.Get(context)); - } - - return new ActivityImplementationContext() { PowerShellInstance = invoker }; - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/SetCimInstanceActivity.cs b/src/Microsoft.PowerShell.Activities/Activities/SetCimInstanceActivity.cs deleted file mode 100644 index 2e90f2ae2..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/SetCimInstanceActivity.cs +++ /dev/null @@ -1,148 +0,0 @@ - -using Microsoft.PowerShell.Activities; -using System.Activities; -using System.Collections.Generic; -using System.ComponentModel; - - -namespace cimcmdlets.Activities -{ - /// - /// Activity to invoke the CimCmdlets\Set-CimInstance command in a Workflow. - /// - [System.CodeDom.Compiler.GeneratedCode("Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromName", "3.0")] - public sealed class SetCimInstance : GenericCimCmdletActivity - { - /// - /// Gets the display name of the command invoked by this activity. - /// - public SetCimInstance() - { - this.DisplayName = "Set-CimInstance"; - } - - /// - /// Gets the fully qualified name of the command invoked by this activity. - /// - public override string PSCommandName { get { return "CimCmdlets\\Set-CimInstance"; } } - - /// - /// The .NET type implementing the cmdlet to invoke. - /// - public override System.Type TypeImplementingCmdlet { get { return typeof(Microsoft.Management.Infrastructure.CimCmdlets.SetCimInstanceCommand); } } - - /// - /// Provides access to the Namespace parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Namespace { get; set; } - - /// - /// Provides access to the OperationTimeoutSec parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument OperationTimeoutSec { get; set; } - - /// - /// Provides access to the InputObject parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument InputObject { get; set; } - - /// - /// Provides access to the Query parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Query { get; set; } - - /// - /// Provides access to the QueryDialect parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument QueryDialect { get; set; } - - /// - /// Provides access to the Property parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument Property { get; set; } - - /// - /// Provides access to the PassThru parameter. - /// - [ParameterSpecificCategory] - [DefaultValue(null)] - public InArgument PassThru { get; set; } - - /// - /// Module defining this command - /// Script module contents for this activity - /// - protected override string PSDefiningModule { get { return "CimCmdlets"; } } - - // Additional custom code for this activity - - - /// - /// Returns a configured instance of System.Management.Automation.PowerShell, pre-populated with the command to run. - /// - /// The NativeActivityContext for the currently running activity. - /// A populated instance of System.Management.Automation.PowerShell - /// The infrastructure takes responsibility for closing and disposing the PowerShell instance returned. - protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) - { - System.Management.Automation.PowerShell invoker = global::System.Management.Automation.PowerShell.Create(); - System.Management.Automation.PowerShell targetCommand = invoker.AddCommand(PSCommandName); - - // Initialize the arguments - - if(Namespace.Expression != null) - { - targetCommand.AddParameter("Namespace", Namespace.Get(context)); - } - - if(OperationTimeoutSec.Expression != null) - { - targetCommand.AddParameter("OperationTimeoutSec", OperationTimeoutSec.Get(context)); - } - - if (InputObject.Expression != null) - { - targetCommand.AddParameter("InputObject", InputObject.Get(context)); - } - - if(Query.Expression != null) - { - targetCommand.AddParameter("Query", Query.Get(context)); - } - - if(QueryDialect.Expression != null) - { - targetCommand.AddParameter("QueryDialect", QueryDialect.Get(context)); - } - - if(Property.Expression != null) - { - targetCommand.AddParameter("Property", Property.Get(context)); - } - - if(PassThru.Expression != null) - { - targetCommand.AddParameter("PassThru", PassThru.Get(context)); - } - - if (ResourceUri != null) - { - targetCommand.AddParameter("ResourceUri", ResourceUri.Get(context)); - } - - return new ActivityImplementationContext() { PowerShellInstance = invoker }; - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/SetHostValue.cs b/src/Microsoft.PowerShell.Activities/Activities/SetHostValue.cs deleted file mode 100644 index 42b26f9c6..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/SetHostValue.cs +++ /dev/null @@ -1,602 +0,0 @@ -using System; -using System.Reflection; -using System.Activities; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Globalization; -using System.Diagnostics.CodeAnalysis; -using System.Management.Automation; -using System.Management.Automation.Remoting; -using System.Management.Automation.Runspaces; -using System.Management.Automation.Tracing; -using System.ComponentModel; - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Activity to set a host value in a Workflow. - /// - public sealed class SetPSWorkflowData : NativeActivity - { - /// - /// The variable to set, if not included in the PSWorkflowRuntimeVariable enum. - /// - [DefaultValue(null)] - public InArgument OtherVariableName - { - get; - set; - } - - /// - /// - /// - [DefaultValue(null)] - public InArgument Value - { - get; - set; - } - - /// - /// Defines the remoting behavior to use when invoking this activity. - /// - [ConnectivityCategory] - [DefaultValue(RemotingBehavior.PowerShell)] - public InArgument PSRemotingBehavior { get; set; } - - /// - /// Defines the number of retries that the activity will make to connect to a remote - /// machine when it encounters an error. The default is to not retry. - /// - [BehaviorCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument PSConnectionRetryCount - { - get; - set; - } - - /// - /// Defines the delay, in seconds, between connection retry attempts. - /// The default is one second. - /// - [BehaviorCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument PSConnectionRetryIntervalSec - { - get; - set; - } - - /// - /// The Input stream for the activity. - /// - [InputAndOutputCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument> Input - { - get; - set; - } - - /// - /// Determines whether to connect the input stream for this activity. - /// - [InputAndOutputCategory] - [DefaultValue(false)] - public bool UseDefaultInput - { - get; - set; - } - - /// - /// The output stream from the activity - /// - [InputAndOutputCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InOutArgument> Result - { - get; - set; - } - - /// - /// Determines whether to append output to Result. - /// - [BehaviorCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public bool? AppendOutput - { - get; - set; - } - - /// - /// The Error stream / collection for the activity. - /// - [InputAndOutputCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InOutArgument> PSError - { - get; - set; - } - - /// - /// The Progress stream / collection for the activity. - /// - [InputAndOutputCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InOutArgument> PSProgress - { - get; - set; - } - - /// - /// The Verbose stream / collection for the activity. - /// - [InputAndOutputCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InOutArgument> PSVerbose - { - get; - set; - } - - /// - /// The Debug stream / collection for the activity. - /// - [InputAndOutputCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InOutArgument> PSDebug - { - get; - set; - } - - /// - /// The Warning stream / collection for the activity. - /// - [InputAndOutputCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InOutArgument> PSWarning - { - get; - set; - } - - /// - /// The Information stream / collection for the activity. - /// - [InputAndOutputCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InOutArgument> PSInformation - { - get; - set; - } - - /// - /// The computer name to invoke this activity on. - /// - [ConnectivityCategory] - [DefaultValue(null)] - public InArgument PSComputerName - { - get; - set; - } - - /// - /// Defines the credential to use in the remote connection. - /// - [ConnectivityCategory] - [DefaultValue(null)] - public InArgument PSCredential - { - get; - set; - } - - /// - /// Forces the activity to return non-serialized objects. Resulting objects - /// have functional methods and properties (as opposed to serialized versions - /// of them), but will not survive persistence when the Workflow crashes or is - /// persisted. - /// - [BehaviorCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument PSDisableSerialization - { - get; - set; - } - - /// - /// Forces the activity to not call the persist functionality, which will be responsible for - /// persisting the workflow state onto the disk. - /// - [BehaviorCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument PSPersist - { - get; - set; - } - - /// - /// Determines whether to merge error data to the output stream - /// - [BehaviorCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument MergeErrorToOutput - { - get; - set; - } - - /// - /// Defines the maximum amount of time, in seconds, that this activity may run. - /// The default is unlimited. - /// - [BehaviorCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument PSActionRunningTimeoutSec - { - get; - set; - } - - /// - /// Defines the maximum amount of time that the workflow engine should wait for a bookmark - /// to be resumed. - /// The default is unlimited. - /// - [BehaviorCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument PSBookmarkTimeoutSec - { - get; - set; - } - - /// - /// This the list of module names (or paths) that are required to run this Activity successfully. - /// The default is null. - /// - [BehaviorCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument PSRequiredModules - { - get; - set; - } - - /// - /// Defines the number of retries that the activity will make when it encounters - /// an error during execution of its action. The default is to not retry. - /// - [BehaviorCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument PSActionRetryCount - { - get; - set; - } - - /// - /// Defines the delay, in seconds, between action retry attempts. - /// The default is one second. - /// - [BehaviorCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument PSActionRetryIntervalSec - { - get; - set; - } - - /// - /// The port to use in a remote connection attempt. The default is: - /// HTTP: 5985, HTTPS: 5986. - /// - [ConnectivityCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument PSPort { get; set; } - - /// - /// Determines whether to use SSL in the connection attempt. The default is false. - /// - [ConnectivityCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument PSUseSsl { get; set; } - - /// - /// Determines whether to allow redirection by the remote computer. The default is false. - /// - [ConnectivityCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument PSAllowRedirection { get; set; } - - /// - /// Defines the remote application name to connect to. The default is "wsman". - /// - [ConnectivityCategory] - [DefaultValue(null)] - public InArgument PSApplicationName { get; set; } - - /// - /// Defines the remote configuration name to connect to. The default is "Microsoft.PowerShell". - /// - [ConnectivityCategory] - [DefaultValue(null)] - public InArgument PSConfigurationName { get; set; } - - /// - /// Defines the fully-qualified remote URI to connect to. When specified, the PSComputerName, - /// PSApplicationName, PSConfigurationName, and PSPort are not used. - /// - [ConnectivityCategory] - [DefaultValue(null)] - public InArgument PSConnectionUri { get; set; } - - /// - /// Defines the authentication type to be used in the remote connection. - /// - [ConnectivityCategory] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument PSAuthentication { get; set; } - - /// - /// Defines the certificate thumbprint to be used in the remote connection. - /// - [ConnectivityCategory] - [DefaultValue(null)] - public InArgument PSCertificateThumbprint { get; set; } - - /// - /// Defines any session options to be used in the remote connection. - /// - [ConnectivityCategory] - [DefaultValue(null)] - public InArgument PSSessionOption { get; set; } - - - /// - /// Execute the logic for this activity... - /// - /// - protected override void Execute(NativeActivityContext context) - { - // Retrieve our host overrides - HostParameterDefaults hostValues = context.GetExtension(); - SetHostValuesByVariableName(context, hostValues); - SetHostValuesByProperty(context, hostValues); - } - - private void SetHostValuesByProperty(NativeActivityContext context, HostParameterDefaults hostValues) - { - Type currentType = this.GetType(); - - // Populate any of our parameters into the host defaults. - foreach (PropertyInfo field in currentType.GetProperties()) - { - // See if it's an argument - if (typeof(Argument).IsAssignableFrom(field.PropertyType)) - { - // Skip the ones that are specific to this activity - if (String.Equals("VariableToSet", field.Name, StringComparison.OrdinalIgnoreCase) || - String.Equals("OtherVariableName", field.Name, StringComparison.OrdinalIgnoreCase) || - String.Equals("Value", field.Name, StringComparison.OrdinalIgnoreCase)) - { - continue; - } - - // Handle Bookmark timeouts, but don't set them as a host default. - if (String.Equals("PSBookmarkTimeoutSec", field.Name, StringComparison.OrdinalIgnoreCase)) - { - // See if this is trying to change the bookmark timeout - if (PSBookmarkTimeoutSec.Get(context).HasValue) - { - SafelySetResumeBookmarkTimeout(TimeSpan.FromSeconds(PSBookmarkTimeoutSec.Get(context).Value)); - } - else - { - SafelySetResumeBookmarkTimeout(TimeSpan.FromSeconds(0)); - } - - continue; - } - - // Get the argument - Argument currentArgument = (Argument)field.GetValue(this, null); - if (currentArgument.Expression != null) - { - if (currentArgument.Get(context) == null) - { - hostValues.Parameters.Remove(field.Name); - } - else - { - hostValues.Parameters[field.Name] = currentArgument.Get(context); - } - } - } - } - } - - private void SetHostValuesByVariableName(NativeActivityContext context, HostParameterDefaults hostValues) - { - // Set the Command / host metadata - string variableName = null; - - if (OtherVariableName.Get(context) != null) - { - if (OtherVariableName.Expression != null) - { - string value = OtherVariableName.Get(context); - - if (!string.IsNullOrWhiteSpace(value)) - { - variableName = value; - } - } - - if (String.Equals(variableName, "Position", StringComparison.OrdinalIgnoreCase)) - { - HostSettingCommandMetadata metadata = hostValues.HostCommandMetadata; - - // The position should come in as line:column:command - string positionMessage = (string)Value.Get(context); - string[] positionElements = positionMessage.Split(new char[] { ':' }, 3); - - string line = positionElements[0].Trim(); - string column = positionElements[1].Trim(); - string commandName = positionElements[2].Trim(); - - if (!String.IsNullOrEmpty(line)) - { - metadata.StartLineNumber = Int32.Parse(line, CultureInfo.InvariantCulture); - } - - if (!String.IsNullOrEmpty(column)) - { - metadata.StartColumnNumber = Int32.Parse(line, CultureInfo.InvariantCulture); - } - - if (!String.IsNullOrEmpty(commandName)) - { - metadata.CommandName = commandName; - } - } - else - { - if (Value.Get(context) == null) - { - hostValues.Parameters.Remove(variableName); - } - else - { - hostValues.Parameters[variableName] = Value.Get(context); - } - } - } - } - - /// - /// Internal reflection call to set the ResumeBookmarkTimeout property, which - /// controls how much time Workflow allows an activity to run while a bookmark is - /// being resumed. The workflow default is 30 seconds, which can be exceeded - /// on heavily loaded systems especially on parallel workflows. - /// There is not a public property for this value, so the implementation below is - /// the one recommended by the workflow team. - /// - /// How long to wait. - private static void SafelySetResumeBookmarkTimeout(TimeSpan timeout) - { - Type activityDefaults = Type.GetType("System.Activities.ActivityDefaults, System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"); - if (activityDefaults != null) - { - FieldInfo resumeBookmarkTimeout = activityDefaults.GetField("ResumeBookmarkTimeout"); - if (resumeBookmarkTimeout != null) - { - // This is an attempt to reset the workflow default. - if (timeout.TotalSeconds == 0) - { - // First see if it's been explicitly set. If so, don't reset it. - TimeSpan currentTimeout = (TimeSpan)resumeBookmarkTimeout.GetValue(null); - if (currentTimeout.TotalSeconds == 30) - { - resumeBookmarkTimeout.SetValue(null, TimeSpan.MaxValue); - } - } - else - { - // They've specified a value. Use it. - resumeBookmarkTimeout.SetValue(null, timeout); - } - } - else - { - System.Diagnostics.Debug.Fail("Could not find ResumeBookmarkTimeout property"); - } - } - else - { - System.Diagnostics.Debug.Fail("Could not find ResumeBookmarkTimeout type"); - } - } - } -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/ThrottledParallelForeach.cs b/src/Microsoft.PowerShell.Activities/Activities/ThrottledParallelForeach.cs deleted file mode 100644 index a197ca0ca..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/ThrottledParallelForeach.cs +++ /dev/null @@ -1,130 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) Microsoft Corporation. All rights reserved. -//----------------------------------------------------------------------------- - -using System; -using System.Activities; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Windows.Markup; - -namespace Microsoft.PowerShell.Activities -{ - /// - /// Implements the equivalent of the ParallelForeach activity, but supports throttling - /// as well. Taken from the Workflow SDK: http://www.microsoft.com/en-us/download/details.aspx?id=21459 - /// - /// - [ContentProperty("Body")] - public sealed class ThrottledParallelForEach : NativeActivity - { - Variable hasCompleted; - Variable> valueEnumerator; - CompletionCallback onBodyComplete; - - /// - /// Creates a new instance of the ThrottledParallelForeach activity - /// - public ThrottledParallelForEach() - : base() - { - } - - /// - /// Gets or sets the actions to be invoked in parallel - /// - [Browsable(false)] - [DefaultValue(null)] - public ActivityAction Body { get; set; } - - /// - /// Gets or sets the number of activities that may be scheduled simultaneously - /// - public InArgument ThrottleLimit { get; set; } - - /// - /// Gets or sets the values to be iterated over - /// - [RequiredArgument] - [DefaultValue(null)] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument> Values { get; set; } - - /// - /// Store implementation variables - /// - /// - protected override void CacheMetadata(NativeActivityMetadata metadata) - { - // add the arguments to the argument collection - metadata.AddArgument(new RuntimeArgument("Values", typeof(IEnumerable), ArgumentDirection.In, true)); - metadata.AddArgument(new RuntimeArgument("ThrottleLimit", typeof(int), ArgumentDirection.In)); - - // initialize the hasCompleted and valueEnumerator and add it to the list of private variables - this.hasCompleted = new Variable(); - metadata.AddImplementationVariable(this.hasCompleted); - - this.valueEnumerator = new Variable>(); - metadata.AddImplementationVariable(this.valueEnumerator); - - // add the body to the delegates collection - metadata.AddDelegate(this.Body); - } - - /// - /// Invoke the activity's actions - /// - /// - protected override void Execute(NativeActivityContext context) - { - // get the list of value to iterate through - IEnumerable values = this.Values.Get(context); - if (values == null) - { - throw new ApplicationException("ParallelForEach requires a non null Values collection"); - } - - // get the enumerator - this.valueEnumerator.Set(context, values.GetEnumerator()); - - // initialize the values for creating the execution window (max and runningCount) - int max = this.ThrottleLimit.Get(context); - if (max < 1) max = int.MaxValue; - int runningCount = 0; - - // initialize the value of the completion variable - this.hasCompleted.Set(context, false); - - // cache the completion callback - onBodyComplete = new CompletionCallback(OnBodyComplete); - - // iterate while there are items available and we didn't exceed the throttle factor - while (runningCount < max && valueEnumerator.Get(context).MoveNext()) - { - // increase the running instances counter - runningCount++; - - if (this.Body != null) - { - context.ScheduleAction(this.Body, valueEnumerator.Get(context).Current, onBodyComplete); - } - } - } - - void OnBodyComplete(NativeActivityContext context, ActivityInstance completedInstance) - { - if (!this.hasCompleted.Get(context)) - { - // get the next child and schedule it! - IEnumerator enumerator = this.valueEnumerator.Get(context); - if (this.valueEnumerator.Get(context).MoveNext()) - { - context.ScheduleAction(this.Body, this.valueEnumerator.Get(context).Current, onBodyComplete); - } - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.PowerShell.Activities/Activities/WmiActivities.cs b/src/Microsoft.PowerShell.Activities/Activities/WmiActivities.cs deleted file mode 100644 index bb11f0978..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/WmiActivities.cs +++ /dev/null @@ -1,242 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ -#pragma warning disable 1634, 1691 - -using System; -using System.ComponentModel; -using System.ComponentModel.Design; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Activities; -using System.Management; -using System.Management.Automation; -using System.Management.Automation.Host; -using System.Management.Automation.Runspaces; -using System.Management.Automation.Tracing; -using System.IO; -using System.Diagnostics.CodeAnalysis; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading; -using System.Globalization; - -namespace Microsoft.PowerShell.Activities -{ - - /// - /// Workflow activity wrapping the Get-Wmiobject cmdlet - /// - public sealed class GetWmiObject : WmiActivity - { - /// - /// Sets the default display name of the activity - /// - public GetWmiObject() - { - this.DisplayName = "Get-WmiObject"; - } - - /// - /// Specifies the name of a WMI class. When this parameter is used, the cmdlet - /// retrieves instances of the WMI class. - /// summary> - [BehaviorCategory] - [DefaultValue(null)] - [OverloadGroup("Class")] - public InArgument Class { get; set; } - - /// - /// Specifies the WMI class property or set of properties to retrieve. - /// - [BehaviorCategory] - [DefaultValue(null)] - public InArgument Property { get; set; } - - /// - /// Specifies a Where clause to use as a filter. Uses the syntax of the WMI Query Language (WQL). - /// - [BehaviorCategory] - [DefaultValue(null)] - [OverloadGroup("Class")] - public InArgument Filter { get; set; } - - /// - /// Specifies a WMI Query Language (WQL) statement to run. Event queries are not supported by this parameter. - /// - [BehaviorCategory] - [DefaultValue(null)] - [OverloadGroup("Query")] - public InArgument Query { get; set; } - - /// - /// Indicates whether the objects that are returned from WMI should contain amended - /// information. Typically, amended information is localizable information, such as object - /// and property descriptions, that is attached to the WMI object. - /// - [BehaviorCategory] - [DefaultValue(null)] - public bool Amended { get; set; } - - /// - /// Specifies whether direct access to the WMI provider is requested for the specified - /// class without any regard to its base class or to its derived classes. - /// - [BehaviorCategory] - [DefaultValue(null)] - public bool DirectRead { get; set; } - - /// - /// Execute the logic for the activity - /// - /// The native activity context to use in this activity - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) - { - System.Management.Automation.PowerShell command; - command = GetWmiCommandCore(context, "Get-WmiObject"); - if (Class.Get(context) != null) - { - command.AddParameter("Class", Class.Get(context)); - Tracer.WriteMessage(String.Format(CultureInfo.InvariantCulture, "PowerShell activity ID={0}: Setting parameter {1} to {2}.", - context.ActivityInstanceId, "Class", Class.Get(context))); - } - - if (Property.Get(context) != null) - { - command.AddParameter("Property", Property.Get(context)); - Tracer.WriteMessage(String.Format(CultureInfo.InvariantCulture, "PowerShell activity ID={0}: Setting parameter {1} to {2}.", - context.ActivityInstanceId, "Property", Property.Get(context))); - - } - if (Filter.Get(context) != null) - { - command.AddParameter("Filter", Filter.Get(context)); - Tracer.WriteMessage(String.Format(CultureInfo.InvariantCulture, "PowerShell activity ID={0}: Setting parameter {1} to {2}.", - context.ActivityInstanceId, "Filter", Filter.Get(context))); - - } - if (Amended) - { - command.AddParameter("Amended", Amended); - Tracer.WriteMessage(String.Format(CultureInfo.InvariantCulture, "PowerShell activity ID={0}: Setting parameter {1} to {2}.", - context.ActivityInstanceId, "Amended", Amended)); - - } - if (DirectRead) - { - command.AddParameter("DirectRead", DirectRead); - Tracer.WriteMessage(String.Format(CultureInfo.InvariantCulture, "PowerShell activity ID={0}: Setting parameter {1} to {2}.", - context.ActivityInstanceId, "DirectRead", DirectRead)); - - } - if (Query.Get(context) != null) - { - command.AddParameter("Query", Query.Get(context)); - Tracer.WriteMessage(String.Format(CultureInfo.InvariantCulture, "PowerShell activity ID={0}: Setting parameter {1} to {2}.", - context.ActivityInstanceId, "Query", Query.Get(context))); - } - - return new ActivityImplementationContext() { PowerShellInstance = command }; - } - } - - /// - /// Wraps the Invoke-WmiMethod cmdlet - /// - public sealed class InvokeWmiMethod : WmiActivity - { - /// - /// Sets the default display name of the activity - /// - public InvokeWmiMethod() - { - this.DisplayName = "Invoke-WmiMethod"; - } - - /// - /// A WMI path specification which should be of the form "Win32_Printer.DeviceID='TestPrinter'" - /// this will select instances of objects on which to call the method. - /// - [BehaviorCategory] - [DefaultValue(null)] - [OverloadGroup("path")] - public InArgument Path { get; set; } - - /// - /// The name of the WMI class to use for when static methods. - /// - [BehaviorCategory] - [DefaultValue(null)] - [OverloadGroup("class")] - public InArgument Class { get; set; } - - /// - /// THe name of the instance or static method to call - /// - [BehaviorCategory] - [DefaultValue(null)] - public InArgument Name { get; set; } - - /// - /// The collection of arguments to use when calling the method - /// - [BehaviorCategory] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", - "CA1006:DoNotNestGenericTypesInMemberSignatures", - Justification = "This is forced by the interaction of PowerShell and Workflow.")] - public InArgument> ArgumentList { get; set; } - - /// - /// Implements the logic of this activity - /// - /// The activity context to refer to - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context) - { - System.Management.Automation.PowerShell command; - command = GetWmiCommandCore(context, "Invoke-WmiMethod"); - - if (!String.IsNullOrEmpty(Path.Get(context))) - { - command.AddParameter("Path", Path.Get(context)); - Tracer.WriteMessage(String.Format(CultureInfo.InvariantCulture, "PowerShell activity ID={0}: Setting parameter {1} to {2}.", - context.ActivityInstanceId, "Path", Path.Get(context))); - - } - - if (!String.IsNullOrEmpty(Class.Get(context))) - { - command.AddParameter("Class", Class.Get(context)); - Tracer.WriteMessage(String.Format(CultureInfo.InvariantCulture, "PowerShell activity ID={0}: Setting parameter {1} to {2}.", - context.ActivityInstanceId, "Class", Class.Get(context))); - - } - - if (!String.IsNullOrEmpty(Name.Get(context))) - { - command.AddParameter("Name", Name.Get(context)); - Tracer.WriteMessage(String.Format(CultureInfo.InvariantCulture, - "PowerShell activity ID={0}: Setting parameter {1} to {2}.", - context.ActivityInstanceId, "Name", Name.Get(context))); - } - - if (ArgumentList.Get(context) != null) - { - Collection argCollection = ArgumentList.Get(context).ReadAll(); - if (argCollection.Count > 0) - { - command.AddParameter("ArgumentList", argCollection); - Tracer.WriteMessage(String.Format(CultureInfo.InvariantCulture, - "PowerShell activity ID={0}: Setting parameter {1} to '{2}'.", - context.ActivityInstanceId, "ArgumentList", string.Join("','", argCollection))); - } - } - - return new ActivityImplementationContext() { PowerShellInstance = command }; - } - } - -} diff --git a/src/Microsoft.PowerShell.Activities/Activities/WorkflowJobConverter.cs b/src/Microsoft.PowerShell.Activities/Activities/WorkflowJobConverter.cs deleted file mode 100644 index 72b81219d..000000000 --- a/src/Microsoft.PowerShell.Activities/Activities/WorkflowJobConverter.cs +++ /dev/null @@ -1,8151 +0,0 @@ -/********************************************************************++ -Copyright (c) Microsoft Corporation. All rights reserved. ---********************************************************************/ - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Management.Automation.Runspaces; -using System.Reflection; -using System.Activities; -using System.Activities.Expressions; -using Microsoft.PowerShell.Activities; -using Microsoft.PowerShell.Activities.Internal; -using System.Activities.Statements; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Management.Automation; -using System.Collections.ObjectModel; -using System.Management.Automation.Internal; -using System.Management.Automation.Language; -using CoreRunspaces = System.Management.Automation.Runspaces; -using System.Management.Automation.Tracing; -using System.Text; -using System.Text.RegularExpressions; -using System.Linq; -using System.Xaml; -using System.Xml; -using System.Activities.XamlIntegration; -using Microsoft.PowerShell.Commands; -using Pipeline = Microsoft.PowerShell.Activities.Pipeline; -using System.Runtime.Serialization; -using System.Runtime.CompilerServices; - -namespace Microsoft.PowerShell.Workflow -{ - /// - /// Exception thrown to return from workflow similar to a function return. - /// - [SerializableAttribute] - public class WorkflowReturnException : WorkflowTerminatedException - { - /// - /// Generic constructor - /// - public WorkflowReturnException() : base() - { } - - /// - /// Initializes a new WorkflowReturnException instance with a given message string. - /// - /// Exception message - public WorkflowReturnException(string message) - : base(message) - { } - - /// - /// Initializes a new WorkflowReturnException instance with a message and inner exception. - /// - /// Exception message - /// Inner Exception - public WorkflowReturnException(string message, Exception innerException) : - base(message, innerException) - { } - - /// - /// Initializes a new WorkflowReturnException with serialization info and streaming context - /// - /// Serialization Info - /// Streaming context - protected WorkflowReturnException(SerializationInfo info, StreamingContext context) : - base(info, context) - { } - } - - internal class WorkflowInfoComparer : System.Collections.Generic.IEqualityComparer - { - #region IEqualityComparer Members - - public bool Equals(WorkflowInfo x, WorkflowInfo y) - { - return string.Equals(x.XamlDefinition, y.XamlDefinition, StringComparison.OrdinalIgnoreCase); - } - - public int GetHashCode(WorkflowInfo obj) - { - return obj.XamlDefinition.GetHashCode(); - } - - #endregion - } - - /// - /// Converts a PowerShell AST into a function that invokes the corresponding - /// script as a workflow job. - /// - public sealed class AstToWorkflowConverter : IAstToWorkflowConverter - { - private static readonly PowerShellTraceSource Tracer = PowerShellTraceSourceFactory.GetTraceSource(); - - /// - /// Provides the opportunity for job converters to validate the semantics of - /// the AST before compilation. This stage should be light-weight and as efficient - /// as possible. - /// - /// The PowerShell AST corresponding to the job's definition. - /// A collection of PSParseErrors corresponding to any semantic issues in the AST. - public List ValidateAst(FunctionDefinitionAst ast) - { - return AstToXamlConverter.Validate(ast); - } - - /// - /// Converts a PowerShell AST into a script block that represents - /// the workflow to run. - /// - /// The PowerShell AST corresponding to the job's definition. - /// The module that is defining this command (if any) - /// - /// A PowerShell script block that invokes an underlying job, - /// based on the definition provided by this script block. - /// - public List CompileWorkflows(ScriptBlockAst ast, PSModuleInfo definingModule) - { - ParseException parsingException = null; - - var result = CompileWorkflows(ast, definingModule, null, out parsingException, null); - - if (parsingException.Errors != null) - { - throw parsingException; - } - - return result; - } - - - /// - /// Converts a PowerShell AST into a script block that represents - /// the workflow to run. - /// - /// The PowerShell AST corresponding to the job's definition. - /// The module that is defining this command (if any) - /// Only root Workflow will be compiled - /// - /// A PowerShell script block that invokes an underlying job, - /// based on the definition provided by this script block. - /// - public List CompileWorkflows(ScriptBlockAst ast, PSModuleInfo definingModule, string rootWorkflowName) - { - ParseException parsingException = null; - - var result = CompileWorkflows(ast, definingModule, null, out parsingException, rootWorkflowName); - - if (parsingException.Errors != null) - { - throw parsingException; - } - - return result; - } - - /// - /// Converts a PowerShell AST into a script block that represents - /// the workflow to run. - /// - /// The PowerShell AST corresponding to the job's definition. - /// The module that is defining this command (if any) - /// The initial session state of a runspace. - /// parsing errors - /// - /// A PowerShell script block that invokes an underlying job, - /// based on the definition provided by this script block. - /// - public List CompileWorkflows(ScriptBlockAst ast, PSModuleInfo definingModule, InitialSessionState initialSessionState, out ParseException parsingErrors) - { - - var result = CompileWorkflows(ast, definingModule, initialSessionState, out parsingErrors, null); - - if (parsingErrors.Errors != null) - { - throw parsingErrors; - } - - return result; - } - - /// - /// Converts a PowerShell AST into a script block that represents - /// the workflow to run. - /// - /// The PowerShell AST corresponding to the job's definition. - /// The module that is defining this command (if any) - /// The initial session state of a runspace. - /// parsing errors - /// Optional, once assigned, only root Workflow will be compiled - /// - /// A PowerShell script block that invokes an underlying job, - /// based on the definition provided by this script block. - /// - public List CompileWorkflows(ScriptBlockAst ast, PSModuleInfo definingModule, InitialSessionState initialSessionState, out ParseException parsingErrors, string rootWorkflowName) - { - return CompileWorkflowsImpl(ast, definingModule, initialSessionState, null, out parsingErrors, rootWorkflowName); - } - - /// - /// Converts a PowerShell AST into a script block that represents - /// the workflow to run. - /// - /// The PowerShell AST corresponding to the job's definition. - /// The module that is defining this command (if any). - /// The initial session state of a runspace. - /// Language mode of source that is creating the workflow. - /// Optional, once assigned, only root Workflow will be compiled. - /// - /// A PowerShell script block that invokes an underlying job, - /// based on the definition provided by this script block. - /// - public List CompileWorkflows(ScriptBlockAst ast, PSModuleInfo definingModule, InitialSessionState initialSessionState, PSLanguageMode? sourceLanguageMode, out ParseException parsingErrors) - { - return CompileWorkflowsImpl(ast, definingModule, initialSessionState, sourceLanguageMode, out parsingErrors, null); - } - - /// - /// Converts a PowerShell AST into a script block that represents - /// the workflow to run. - /// - /// The PowerShell AST corresponding to the job's definition. - /// The module that is defining this command (if any) - /// The initial session state of a runspace. - /// Language mode of source that is creating the workflow. - /// parsing errors - /// Optional, once assigned, only root Workflow will be compiled - /// - /// A PowerShell script block that invokes an underlying job, - /// based on the definition provided by this script block. - /// - private List CompileWorkflowsImpl(ScriptBlockAst ast, PSModuleInfo definingModule, InitialSessionState initialSessionState, PSLanguageMode? sourceLanguageMode, out ParseException parsingErrors, string rootWorkflowName) - { - List errorList = new List(); - - if (ast == null) - { - throw new PSArgumentNullException("ast"); - } - - // if user specifies rootWorkflowName, we will check if it exists in the given ast. - if (rootWorkflowName != null) - { - var methods = ast.FindAll(a => a is FunctionDefinitionAst, true); - bool isWFNameMatch = false; - foreach (FunctionDefinitionAst method in methods) - { - if (method.Name == rootWorkflowName) - { - isWFNameMatch = true; - break; - } - } - - if (!isWFNameMatch) - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.InvalidRootWorkflowName, rootWorkflowName); - throw new PSArgumentException(error); - } - } - - var dependencies = new Dictionary(); - var scope = BuildSymbolTable(ast, null, dependencies); - foreach (var scopeEntry in scope.functionDefinitions.Values) - { - AnalyzeFunctionBody(scopeEntry, scope, dependencies); - } - - // Now do a topological sort. - var outputList = new List(); - var readyList = dependencies.Values.Where(n => n.outgoingCalls.Count == 0).Select(node => node.scopeEntry).ToList(); - - while (readyList.Count > 0) - { - var entry = readyList[0]; - outputList.Add(entry); - readyList.RemoveAt(0); - - var node = dependencies[entry.functionDefinition]; - foreach (var caller in node.incomingCallers) - { - var nodeCaller = dependencies[caller.functionDefinition]; - nodeCaller.outgoingCalls.Remove(entry); - if (nodeCaller.outgoingCalls.Count == 0) - readyList.Add(nodeCaller.scopeEntry); - } - } - - if (outputList.Count != dependencies.Count) - { - // There must be a cycle. Workflows can't be recursive, so generate an error. - var error = new ParseError(ast.Extent, "RecursiveWorkflowNotSupported", ActivityResources.RecursiveWorkflowNotSupported); - errorList.Add(error); - } - - Ast parentAst = ast; - while (parentAst.Parent != null) - { - parentAst = parentAst.Parent; - } - var requirements = ((ScriptBlockAst)parentAst).ScriptRequirements; - - System.Management.Automation.PowerShell invoker; - bool useCurrentRunspace = false; - - HashSet processedActivityLibraries; - Dictionary activityMap; - var requiredAssemblies = new Collection(); - - if (requirements != null) - { - foreach (var reqAssembly in requirements.RequiredAssemblies) - requiredAssemblies.Add(reqAssembly); - } - - if (initialSessionState != null) - { - invoker = System.Management.Automation.PowerShell.Create(initialSessionState); - var scopeFromIss = GetScopeFromIss(initialSessionState, invoker, out processedActivityLibraries, out activityMap); - - // Add functionDefinitions, if any, from scopeFromIss to parent scope, so that they will be available for all FunctionDefinitionAsts - foreach(var entry in scopeFromIss.functionDefinitions) - { - scope.functionDefinitions.Add(entry.Key, entry.Value); - } - - // Add assemblies from initialSessionState to requiredAssemblies - foreach (var ssae in initialSessionState.Assemblies) - { - if (!string.IsNullOrEmpty(ssae.FileName)) - { - requiredAssemblies.Add(ssae.FileName); - } - else if (!string.IsNullOrEmpty(ssae.Name)) - { - requiredAssemblies.Add(ssae.Name); - } - } - } - else - { - - useCurrentRunspace = Runspace.CanUseDefaultRunspace; - invoker = System.Management.Automation.PowerShell.Create(useCurrentRunspace - ? RunspaceMode.CurrentRunspace - : RunspaceMode.NewRunspace); - - activityMap = AstToXamlConverter.GetActivityMap(requiredAssemblies, out processedActivityLibraries); - } - - var result = new List(); - try - { - foreach (var entry in outputList) - { - var func = entry.functionDefinition; - if (!func.IsWorkflow) - continue; - - try - { - entry.workflowInfo = CompileSingleWorkflow(entry.scope, func, scriptBlockTokenCache, definingModule, requiredAssemblies, activityMap, processedActivityLibraries, invoker, sourceLanguageMode, rootWorkflowName); - result.Add(entry.workflowInfo); - } - catch (ParseException e) - { - errorList.AddRange(e.Errors); - } - } - } - finally - { - if (!useCurrentRunspace) - { - invoker.Dispose(); - } - } - - if (errorList.Count > 0) - { - parsingErrors = new ParseException(errorList.ToArray()); - } - else - { - parsingErrors = new ParseException(); - } - - return result; - } - Dictionary scriptBlockTokenCache = new Dictionary(); - - private static WorkflowInfo CompileSingleWorkflow(Scope scope, - FunctionDefinitionAst func, - Dictionary scriptBlockTokenCache, - PSModuleInfo definingModule, - IEnumerable assemblyList, - Dictionary activityMap, - HashSet processedActivityLibraries, - System.Management.Automation.PowerShell invoker, - PSLanguageMode? sourceLanguageMode = (PSLanguageMode?)null, - string rootWorkflowName = null) - { - Dictionary parameterValidation; - WorkflowInfo[] calledWorkflows; - Dictionary referencedAssemblies; - string workflowAttributes; - - var xaml = AstToXamlConverter.Convert(func, scope, definingModule, activityMap, processedActivityLibraries, - out parameterValidation, out calledWorkflows, out referencedAssemblies, out workflowAttributes, - assemblyList, invoker); - - // This step does two major things: - // - it takes all of the dependent workflows and compiles them into in-memory dlls. - // - it synthesizes the text for user-callable powershell function from the workflow XAML definition - string modulePath = null; - if (definingModule != null) - { - modulePath = definingModule.ModuleBase; - } - else if (!String.IsNullOrEmpty(func.Extent.File)) - { - modulePath = Path.GetDirectoryName(func.Extent.File); - } - - // Get the topmost parent AST for the workflow function. - Ast parentAst = func; - while (parentAst.Parent != null) - { - parentAst = parentAst.Parent; - } - - // Pass either the workflow script file path if available or the full source otherwise. - string scriptFile = parentAst.Extent.File; - string scriptSource = string.IsNullOrEmpty(scriptFile) ? parentAst.Extent.StartScriptPosition.GetFullScript() : null; - ReadOnlyCollection attributeAstCollection = (func.Body.ParamBlock != null) ? func.Body.ParamBlock.Attributes : null; - var functionDefinition = ImportWorkflowCommand.CreateFunctionFromXaml(func.Name, xaml, - referencedAssemblies, calledWorkflows.Select(wfi => wfi.NestedXamlDefinition).ToArray(), - null, parameterValidation, modulePath, true, workflowAttributes, - scriptFile, scriptSource, rootWorkflowName, sourceLanguageMode, attributeAstCollection); - - var helpContent = func.GetHelpContent(scriptBlockTokenCache); - if (helpContent != null) - { - functionDefinition = helpContent.GetCommentBlock() + functionDefinition; - } - - var sb = ScriptBlock.Create(functionDefinition); - sb.DebuggerHidden = true; - - var defnText = func.Body.Extent.Text; - defnText = defnText.Substring(1, defnText.Length - 2); - return new WorkflowInfo(func.Name, defnText, sb, xaml, calledWorkflows, definingModule); - } - - static internal IEnumerable GetRequiredAssembliesFromInitialSessionState( - InitialSessionState initialSessionState, - System.Management.Automation.PowerShell invoker) - { - var getModuleCommand = new CmdletInfo("Get-Module", typeof(GetModuleCommand)); - invoker.Commands.Clear(); - invoker.AddCommand(getModuleCommand) - .AddParameter("ErrorAction", ActionPreference.Ignore); - var modules = invoker.Invoke(); - - var modulesToProcess = new Stack(modules); - while (modulesToProcess.Count > 0) - { - var module = modulesToProcess.Pop(); - - foreach (var assem in module.RequiredAssemblies) - { - yield return assem; - } - - foreach (var nestedModule in module.NestedModules) - { - modulesToProcess.Push(nestedModule); - } - } - - // All required assemblies have been loaded now, so we can iterate through - // the app domain and match up assemblies from iss. - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - if (assembly.IsDynamic) - { - continue; - } - - foreach (var ssae in initialSessionState.Assemblies) - { - if (!string.IsNullOrEmpty(ssae.Name)) - { - // Compare against full name and partial name - if (assembly.FullName.Equals(ssae.Name, StringComparison.OrdinalIgnoreCase) - || assembly.GetName().Name.Equals(ssae.Name, StringComparison.OrdinalIgnoreCase)) - { - yield return assembly.FullName; - continue; - } - } - if (!string.IsNullOrEmpty(ssae.FileName)) - { - if (assembly.Location.Equals(ssae.FileName, StringComparison.OrdinalIgnoreCase)) - { - yield return ssae.FileName; - continue; - } - } - } - } - } - - internal static Scope GetScopeFromIss(InitialSessionState iss, - System.Management.Automation.PowerShell invoker, - out HashSet processedActivityLibraries, - out Dictionary activityMap) - { - var scope = new Scope - { - functionDefinitions = new Dictionary(StringComparer.OrdinalIgnoreCase) - }; - - activityMap = AstToXamlConverter.GetActivityMap(GetRequiredAssembliesFromInitialSessionState(iss, invoker), out processedActivityLibraries); - - foreach (var sswe in iss.Commands.OfType()) - { - var issFn = AstToXamlConverter.GetScriptAsFunction(sswe.Name, sswe.Definition, isWorkflow: true); - var entry = new Scope.Entry - { - functionDefinition = issFn, - scope = new Scope - { - functionDefinitions = new Dictionary(StringComparer.OrdinalIgnoreCase) - }, - workflowInfo = (new AstToWorkflowConverter()).CompileWorkflow(sswe.Name, sswe.Definition, scope, processedActivityLibraries, activityMap, invoker) - }; - scope.functionDefinitions.Add(sswe.Name, entry); - } - - return scope; - } - - /// - /// Compile a single workflow from it's definition as a string. - /// - /// - /// - /// - /// - public WorkflowInfo CompileWorkflow(string name, string definition, InitialSessionState initialSessionState) - { - if (name == null) - { - throw new PSArgumentNullException("name"); - } - - if (definition == null) - { - throw new PSArgumentNullException("definition"); - } - - if (initialSessionState == null) - { - throw new PSArgumentNullException("initialSessionState"); - } - - var fnDefn = AstToXamlConverter.GetScriptAsFunction(name, definition, isWorkflow: true); - - var invoker = System.Management.Automation.PowerShell.Create(initialSessionState); - try - { - HashSet processedActivityLibraries; - Dictionary activityMap; - - var scope = GetScopeFromIss(initialSessionState, invoker, out processedActivityLibraries, out activityMap); - return CompileSingleWorkflow(scope, fnDefn, scriptBlockTokenCache, null, null, activityMap, processedActivityLibraries, invoker); - } - finally - { - invoker.Dispose(); - } - } - - internal WorkflowInfo CompileWorkflow(string name, - string definition, - Scope scope, - HashSet processedActivityLibraries, - Dictionary activityMap, - System.Management.Automation.PowerShell invoker) - { - var fnDefn = AstToXamlConverter.GetScriptAsFunction(name, definition, isWorkflow: true); - return CompileSingleWorkflow(scope, fnDefn, scriptBlockTokenCache, null, null, activityMap, processedActivityLibraries, invoker); - } - - /// - /// Returns the parameters of the activity called by the . - /// - /// The ast representing the command called - /// The parameters with their corresponding types, or null if the parameters cannot be found. - public static Dictionary GetActivityParameters(CommandAst commandAst) - { - CommandInfo command; - - Ast workflowRootAst = commandAst; - while (!(workflowRootAst is FunctionDefinitionAst)) - { - workflowRootAst = workflowRootAst.Parent; - } - var scope = new Scope - { - functionDefinitions = new Dictionary(StringComparer.OrdinalIgnoreCase) - }; - - bool useCurrentRunspace = Runspace.CanUseDefaultRunspace; - var invoker = System.Management.Automation.PowerShell.Create(useCurrentRunspace - ? RunspaceMode.CurrentRunspace - : RunspaceMode.NewRunspace); - try - { - HashSet processedActivityLibraries; - var activityMap = AstToXamlConverter.GetActivityMap(null, out processedActivityLibraries); - var converter = new AstToXamlConverter(null, (FunctionDefinitionAst)workflowRootAst, null, activityMap, processedActivityLibraries, true, scope, invoker); - - string commandName = commandAst.GetCommandName(); - AstToXamlConverter.ActivityKind activityKind = converter.ResolveActivityKindBasedOnCommandName(commandName, commandAst, out command, true); - - switch (activityKind) - { - case AstToXamlConverter.ActivityKind.InlineScript: - return AstToXamlConverter.GetAvailableProperties(typeof(InlineScript), null); - - case AstToXamlConverter.ActivityKind.Persist: - // The checkpoint-workflow activity accepts no parameters - return null; - - case AstToXamlConverter.ActivityKind.Suspend: - // The suspend-workflow activity accepts only one optional parameter, the syntax is: - // Suspend-Workflow [-Label ] - return new Dictionary() {{ "Label", typeof(string) }}; - - case AstToXamlConverter.ActivityKind.InvokeExpression: - // The real Invoke-Expression activity has the common parameters but the Language parameter is - // not available in the real activity. To encourage the expected use of Invoke-Expression, - // we'll only return -Language and -Command. - return new Dictionary() {{"Language", typeof (string)}, {"Command", typeof (string)}}; - - case AstToXamlConverter.ActivityKind.Delay: - return new Dictionary {{"Seconds", typeof (int)}, {"Milliseconds", typeof (int)}}; - - case AstToXamlConverter.ActivityKind.NewObject: - return new Dictionary {{"TypeName", typeof (string)}}; - - case AstToXamlConverter.ActivityKind.RegularCommand: - // If the command resolved to a script, the command metadata has all of it's parameters, - if ((command != null) && (command.CommandType & (CommandTypes.ExternalScript | CommandTypes.Workflow | CommandTypes.Function | CommandTypes.Filter | CommandTypes.Configuration)) != 0) - { - return null; - } - - CommandInfo resolvedCommand; - Type[] genericTypes; - - // Find the activity for this name - Type activityType = converter.ResolveActivityType(commandName, commandAst, true, out resolvedCommand, out genericTypes); - - if (activityType == null || resolvedCommand == null) - { - return null; - } - - Dictionary availableProperties = AstToXamlConverter.GetAvailableProperties(activityType, null); - Dictionary virtualProperties = AstToXamlConverter.GetVirtualProperties(activityType, null); - if (virtualProperties != null) - { - foreach (KeyValuePair virtualProperty in virtualProperties) - { - availableProperties.Add(virtualProperty.Key, virtualProperty.Value); - } - } - - return availableProperties; - } - } - finally - { - if (!useCurrentRunspace) - { - invoker.Dispose(); - } - } - - return null; - } - - #region Dependency graph - - class DependencyGraphNode - { - internal Scope.Entry scopeEntry; - internal List outgoingCalls = new List(); - internal List incomingCallers = new List(); - } - - private static void AnalyzeFunctionBody(Scope.Entry defnEntry, Scope parentScope, Dictionary dependencies) - { - var functionDefinitionAst = defnEntry.functionDefinition; - var scriptBlockAst = functionDefinitionAst.Body; - var currentNode = dependencies[functionDefinitionAst]; - var innerScope = BuildSymbolTable(scriptBlockAst, parentScope, dependencies); - defnEntry.scope = innerScope; - foreach (var commandAst in scriptBlockAst.FindAll(ast => true, searchNestedScriptBlocks: false).OfType()) - { - var commandName = commandAst.GetCommandName(); - if (!string.IsNullOrEmpty(commandName)) - { - var scopeEntry = innerScope.LookupCommand(commandName); - if (scopeEntry != null && !currentNode.outgoingCalls.Contains(scopeEntry)) - { - currentNode.outgoingCalls.Add(scopeEntry); - dependencies[scopeEntry.functionDefinition].incomingCallers.Add(defnEntry); - } - } - } - - foreach (var scopeEntry in innerScope.functionDefinitions.Values) - { - AnalyzeFunctionBody(scopeEntry, innerScope, dependencies); - } - } - - static Scope BuildSymbolTable(ScriptBlockAst scriptBlockAst, Scope parentScope, Dictionary dependencies) - { - var table = new Dictionary(StringComparer.OrdinalIgnoreCase); - var scope = new Scope { parent = parentScope, functionDefinitions = table }; - - foreach (var defn in scriptBlockAst.FindAll(ast => true, searchNestedScriptBlocks: false).OfType()) - { - if (table.ContainsKey(defn.Name)) - { - var errorMsg = String.Format(CultureInfo.InvariantCulture, ActivityResources.FunctionRedefinitionNotAllowed, defn.Name); - var error = new ParseError(defn.Extent, "FunctionRedefinitionNotAllowed", errorMsg); - throw new ParseException(new [] {error}); - } - var entry = new Scope.Entry {functionDefinition = defn}; - table.Add(defn.Name, entry); - dependencies.Add(defn, new DependencyGraphNode {scopeEntry = entry}); - } - - return scope; - } - - #endregion Dependency graph - } - - internal class Scope - { - internal class Entry - { - internal WorkflowInfo workflowInfo; - internal FunctionDefinitionAst functionDefinition; - internal Scope scope; - } - - internal Scope parent; - internal Dictionary functionDefinitions; - - internal Entry LookupCommand(string name) - { - Scope currentScope = this; - - while (currentScope != null) - { - Entry result; - if (currentScope.functionDefinitions.TryGetValue(name, out result)) - { - return result; - } - currentScope = currentScope.parent; - } - - return null; - } - } - - /// - /// Converts a PowerShell AST into the workflow XAML that represents it. - /// - public class AstToXamlConverter : ICustomAstVisitor - { - /// - /// Creates a new PowerShellXaml converter - /// - /// The name of the command being converted - /// The AST that is the root of the PowerShell script to convert - /// The module that is defining this command (if any) - /// The dictionary mapping activities to their types. - /// A hashset of activity libraries that the workflow depends on - /// Only do validation. - /// Scope chain used to resolve commands lexically - /// - internal AstToXamlConverter(string name, - FunctionDefinitionAst workflowAstRoot, - PSModuleInfo definingModule, - Dictionary activityMap, - HashSet processedActivityLibraries, - bool validateOnly, - Scope scope, - System.Management.Automation.PowerShell invoker) - { - this.name = name; - this.scriptWorkflowAstRoot = workflowAstRoot; - this.activityMap = activityMap; - this.processedActivityLibraries = processedActivityLibraries; - this.validateOnly = validateOnly; - this.definingModule = definingModule; - this.scope = scope; - this.invoker = invoker; - } - - static AstToXamlConverter() - { - PopulateActivityStaticMap(); - - List supportedCommonParameters = new List() { "Verbose", "Debug", "ErrorAction", "WarningAction", "InformationAction" }; - ignoredParameters = new List(Cmdlet.CommonParameters.Concat(Cmdlet.OptionalCommonParameters)); - ignoredParameters.RemoveAll( item => supportedCommonParameters.Contains(item, StringComparer.OrdinalIgnoreCase) ); - } - - /// - /// Any parameter validation attributes associated with this script block. - /// - internal Dictionary ParameterValidation - { - get { return parameterValidation; } - } - private Dictionary parameterValidation = new Dictionary(StringComparer.OrdinalIgnoreCase); - - private bool disableSymbolGeneration = false; - private string name = null; - private PSModuleInfo definingModule = null; - private readonly Ast scriptWorkflowAstRoot; - private int _currentIndentLevel; - private Scope scope; - private System.Management.Automation.PowerShell invoker; - - // Remember the assemblies we've processed, as these should - // correspond to the module names of commands we're processing. - // If the user ever tries to call a command from a module that we've - // processed - but that command is not found - then we generate an - // error because that activity was probably intentionally excluded. - private HashSet processedActivityLibraries; - private Dictionary activityMap; - private static HashSet staticProcessedActivityLibraries = new HashSet(StringComparer.OrdinalIgnoreCase); - private static Dictionary staticActivityMap = new Dictionary(StringComparer.OrdinalIgnoreCase); - - // Bool to identify if the workflow uses return / exit. - // If so, we need to generate a try / catch statement to wrap this control flow. - bool hasControlFlowException = false; - - // Indicate whether to merge error stream for a specific CommandAst or CommandExpressionAst - private bool mergeErrorToOutput = false; - - // XAML elements - const string xamlHeader = @" -"; - private const string AppendOutputTemplate = @" AppendOutput = ""True"""; - private const string GenericTypesKey = @"Activity-GenericTypes"; - private const string MemberTemplate = @""; - private const string M3PKeyForThrowStatement = @"__Microsoft.PowerShell.Activities.Throw"; - - // PseudoCommands that only work in the script workflow - // Please keep in sync with the System.Management.Automation.CompletionCompleter.PseudoCommands - private const string CheckpointWorkflow = "Checkpoint-Workflow"; - private const string SuspendWorkflow = "Suspend-Workflow"; - - private int namespaceCount = 0; - private Dictionary namespaces = new Dictionary(StringComparer.OrdinalIgnoreCase); - private List namespaceDefinitions = new List(); - private List bodyElements = new List(); - private Stack scopes = new Stack(); - private Stack resultVariables = new Stack(); - private Dictionary members = new Dictionary(StringComparer.OrdinalIgnoreCase); - private Dictionary memberDefaults = new Dictionary(StringComparer.OrdinalIgnoreCase); - private bool isVisitingPipeline = false; - private bool isVisitingIterativePipeline = false; - - /// - /// Converts a PowerShell AST into the XAML that represents it, also returning the cmdlet attribute string - /// for the workflow. - /// - /// The PowerShell AST to convert - /// The module that is defining this command (if any) - /// The list of additional assemblies to search for workflow activities. - /// Any parameter validation applied to the parameters in the provided AST. - /// Any nested workflows required by this PowerShell AST. - /// All assemblies, including provided at API or provided in workflow definition, required by this PowerShell Workflow. - /// The attribute string for the workflow if these is one. - public static string Convert(FunctionDefinitionAst ast, - PSModuleInfo definingModule, - List referencedAssemblies, - out Dictionary parameterValidation, - out WorkflowInfo[] nestedWorkflows, - out Dictionary requiredAssemblies, - out string workflowAttributes) - { - var scope = new Scope - { - functionDefinitions = new Dictionary(StringComparer.OrdinalIgnoreCase) - }; - - HashSet processedActivityLibraries; - var activityMap = AstToXamlConverter.GetActivityMap(referencedAssemblies, out processedActivityLibraries); - - bool useCurrentRunspace = Runspace.CanUseDefaultRunspace; - var invoker = System.Management.Automation.PowerShell.Create(useCurrentRunspace - ? RunspaceMode.CurrentRunspace - : RunspaceMode.NewRunspace); - - try - { - return Convert(ast, scope, definingModule, activityMap, processedActivityLibraries, out parameterValidation, out nestedWorkflows, - out requiredAssemblies, out workflowAttributes, referencedAssemblies, invoker); - } - finally - { - if (!useCurrentRunspace) - { - invoker.Dispose(); - } - } - } - - internal static FunctionDefinitionAst GetScriptAsFunction(string name, string definition, bool isWorkflow) - { - Token[] tokens; - ParseError[] errors; - var block = Parser.ParseInput( - string.Format(CultureInfo.InvariantCulture, "{0} {1} {{ {2} }}", - isWorkflow ? "workflow" : "function", name, definition), - out tokens, out errors); - if (errors.Count() > 0) - { - throw new ParseException(errors); - } - return (FunctionDefinitionAst)block.EndBlock.Statements[0]; - } - - /// - /// - /// - /// - /// - /// - /// - public static string Convert(string name, string definition, InitialSessionState initialSessionState) - { - if (name == null) - { - throw new PSArgumentNullException("name"); - } - - if (definition == null) - { - throw new PSArgumentNullException("definition"); - } - - if (initialSessionState == null) - { - throw new PSArgumentNullException("initialSessionState"); - } - - var fnDefn = GetScriptAsFunction(name, definition, true); - - var invoker = System.Management.Automation.PowerShell.Create(initialSessionState); - - try - { - HashSet processedActivityLibraries; - Dictionary activityMap; - - var scope = AstToWorkflowConverter.GetScopeFromIss(initialSessionState, invoker, out processedActivityLibraries, out activityMap); - - Dictionary parameterValidation; - WorkflowInfo[] nestedWorkflows; - Dictionary requiredAssemblies; - string workflowAttributes; - return Convert(fnDefn, scope, null, activityMap, processedActivityLibraries, out parameterValidation, out nestedWorkflows, - out requiredAssemblies, out workflowAttributes, null, invoker); - } - finally - { - invoker.Dispose(); - } - } - - internal static string Convert(FunctionDefinitionAst ast, - Scope scope, - PSModuleInfo definingModule, - Dictionary activityMap, - HashSet processedActivityLibraries, - out Dictionary parameterValidation, - out WorkflowInfo[] nestedWorkflows, - out Dictionary requiredAssemblies, - out string workflowAttributes, - IEnumerable assemblyList, - System.Management.Automation.PowerShell invoker) - { - AstToXamlConverter converter = new AstToXamlConverter(ast.Name, ast, definingModule, activityMap, processedActivityLibraries, false, scope, invoker); - - ast.Visit(converter); - parameterValidation = converter.ParameterValidation; - nestedWorkflows = converter.NestedWorkflows.ToArray(); - - requiredAssemblies = new Dictionary(StringComparer.OrdinalIgnoreCase); - if (assemblyList != null) - { - - foreach (string filePath in assemblyList) - { - - if (!string.IsNullOrEmpty(filePath)) - { - string fileName; - - // To avoid situation like "System.Management.Automation -> System.Management" - if (string.Equals(Path.GetExtension(filePath),".dll",StringComparison.OrdinalIgnoreCase)) - { - fileName = Path.GetFileNameWithoutExtension(filePath); - } - else - { - fileName = filePath; - } - - requiredAssemblies.Add(fileName, filePath); - } - } - } - - // Pop the attribute off of the stack - workflowAttributes = converter.CmdletAttributeText; - - string result = converter.ToString().Trim(); - return result; - } - - /// - /// Validates a PowerShell AST as a valid workflow. - /// - /// The PowerShell AST to convert - public static List Validate(FunctionDefinitionAst ast) - { - var scope = new Scope - { - functionDefinitions = new Dictionary(StringComparer.OrdinalIgnoreCase) - }; - - bool useCurrentRunspace = Runspace.CanUseDefaultRunspace; - var invoker = System.Management.Automation.PowerShell.Create(useCurrentRunspace - ? RunspaceMode.CurrentRunspace - : RunspaceMode.NewRunspace); - - try - { - // Guard access to private static variables. IEnumerable use is not thread safe. - lock (staticProcessedActivityLibraries) - { - var converter = new AstToXamlConverter(null, ast, null, staticActivityMap, staticProcessedActivityLibraries, true, scope, invoker); - - try - { - ast.Visit(converter); - } - catch (Exception) - { - // If we are reporting a parse error, catch all exceptions during validation - // as we probably tried to continue past a parse error. True code issues will - // be caught during final compilation. - if (converter.ParseErrors.Count == 0) - { - throw; - } - } - - return converter.ParseErrors; - } - } - finally - { - if (!useCurrentRunspace) - { - invoker.Dispose(); - } - } - } - - /// - /// Returns the XAML result of the AST compilation - /// - /// The XAML result of the AST compilation - public override string ToString() - { - StringBuilder result = new StringBuilder(); - - // Add in the initial header - string actualActivityName = string.Format(CultureInfo.InvariantCulture, "Activity_{0}", Math.Abs(scriptWorkflowAstRoot.ToString().GetHashCode())); - string formattedXamlHeader = String.Format( - CultureInfo.InvariantCulture, - xamlHeader, - actualActivityName); - result.AppendLine(formattedXamlHeader); - - if (hasControlFlowException) - { - // Add exception namespace to list so we can use the friendly name - GetFriendlyName(null, typeof(Microsoft.PowerShell.Workflow.WorkflowReturnException)); - } - - // Add in the namespaces - foreach (string namespaceDeclaration in namespaceDefinitions) - { - result.AppendLine(namespaceDeclaration); - } - - // Add in the defaults - foreach (string memberName in memberDefaults.Keys) - { - result.AppendLine(String.Format( - CultureInfo.InvariantCulture, " local:{0}.{1} = \"{2}\"", - actualActivityName, - memberName, - memberDefaults[memberName])); - } - - // Close the Activity tag - result.AppendLine(" >"); - - IndentLevel(); - - // Add the members - if (members.Count > 0) - { - result.AppendLine(GetIndentedLine("")); - - IndentLevel(); - foreach (VariableDefinition member in members.Values) - { - result.AppendLine(GetIndentedLine(member.XamlDefinition)); - } - UnindentLevel(); - - result.AppendLine(GetIndentedLine("")); - } - - // Add the wrapping try / catch to support return and exit - if (hasControlFlowException) - { - result.AppendLine(GetIndentedLine("")); - IndentLevel(); - result.AppendLine(GetIndentedLine("")); - IndentLevel(); - } - - // Add the body elements: ... - foreach (string element in bodyElements) - { - result.AppendLine(GetIndentedLine(element)); - } - - // Close up the wrapping try / catch to support return and exit - if (hasControlFlowException) - { - string friendlyTypeName = GetConvertedTypeName(typeof(Microsoft.PowerShell.Workflow.WorkflowReturnException)); - UnindentLevel(); - result.AppendLine(GetIndentedLine("")); - result.AppendLine(GetIndentedLine("")); - IndentLevel(); - result.AppendLine(GetIndentedLine(@"")); - IndentLevel(); - result.AppendLine(GetIndentedLine(@"")); - IndentLevel(); - result.AppendLine(GetIndentedLine(@"")); - IndentLevel(); - result.AppendLine(GetIndentedLine(@"")); - UnindentLevel(); - result.AppendLine(GetIndentedLine(@"")); - UnindentLevel(); - result.AppendLine(GetIndentedLine(@"")); - UnindentLevel(); - result.AppendLine(GetIndentedLine(@"")); - - UnindentLevel(); - result.AppendLine(GetIndentedLine("")); - UnindentLevel(); - result.AppendLine(GetIndentedLine("")); - } - - UnindentLevel(); - result.AppendLine(GetIndentedLine(xamlFooter)); - - return result.ToString(); - } - - /// - /// Set to True if workflow conversion should be done in validation mode. - /// - internal bool ValidateOnly - { - get { return validateOnly; } - } - private bool validateOnly = false; - - /// - /// Returns the list of errors found during validation / compilation - /// - internal List ParseErrors - { - get { return _parseErrors; } - } - List _parseErrors = new List(); - - /// - /// Returns all nested workflows used by this command - /// - internal HashSet NestedWorkflows - { - get { return nestedWorkflows; } - } - private HashSet nestedWorkflows = new HashSet(new WorkflowInfoComparer()); - - private string GetIndentedLine(string line) - { - if (_currentIndentLevel > 0) - { - StringBuilder indentation = new StringBuilder(); - indentation.Append(' ', 4 * _currentIndentLevel); - indentation.Append(line); - - line = indentation.ToString(); - } - - return line; - } - - private void WriteLine(string line) - { - bodyElements.Add(GetIndentedLine(line)); - } - - // Convert a type name to something with namespaces shortened down to XML namespaces (i.e.: ns0:Dictionary) - // Also adds the XML namespaces to the list of namespaces in the activity itself. - private string GetConvertedTypeName(Type requiredType) - { - string convertedName = GetFriendlyName(null, requiredType); - - // Process generic arguments - if (requiredType.IsGenericType) - { - convertedName += "("; - - Type[] genericArguments = requiredType.GetGenericArguments(); - string[] convertedGenericArguments = new string[genericArguments.Length]; - - for (int counter = 0; counter < genericArguments.Length; counter++) - { - convertedGenericArguments[counter] = GetConvertedTypeName(genericArguments[counter]); - } - - convertedName += String.Join(", ", convertedGenericArguments); - - convertedName += ")"; - } - - return convertedName; - } - - private string GetFriendlyName(string invocationName, Type requiredType) - { - // Generate an error if they're trying to use a parameter type / etc - // from a dynamically-loaded assembly. - if (String.IsNullOrEmpty(requiredType.Assembly.Location)) - { - throw new NotSupportedException( - String.Format(CultureInfo.InvariantCulture, ActivityResources.TypeFromDynamicAssembly, requiredType.FullName)); - } - - string typeKey = requiredType.Namespace + "|" + requiredType.Assembly.FullName; - - // Add a namespace alias if required - if (!namespaces.ContainsKey(typeKey)) - { - string namespaceName = "ns" + namespaceCount; - namespaces[typeKey] = namespaceName; - - namespaceDefinitions.Add( - String.Format(CultureInfo.InvariantCulture, @" xmlns:ns{0}=""clr-namespace:{1};assembly={2}""", - namespaceCount, requiredType.Namespace, requiredType.Module.Name.Replace(".dll", ""))); - namespaceCount++; - } - - string namespaceMapping = namespaces[typeKey]; - - if (invocationName == null) - { - invocationName = requiredType.Name; - } - - string friendlyName = GetNonGenericName(invocationName); - - if (typeof(DynamicActivity).IsAssignableFrom(requiredType)) - { - friendlyName = friendlyName.Replace("Microsoft.PowerShell.DynamicActivities.", ""); - namespaceMapping = "local"; - } - - return String.Format(CultureInfo.InvariantCulture, "{0}:{1}", namespaceMapping, friendlyName); - } - - private string GetNonGenericName(string genericName) - { - int genericIndex = genericName.IndexOf('`'); - if (genericIndex >= 0) - { - genericName = genericName.Substring(0, genericIndex); - } - return genericName; - } - - private void IndentLevel() - { - ++_currentIndentLevel; - } - - private void UnindentLevel() - { - --_currentIndentLevel; - if (_currentIndentLevel < 0) - { - throw new InvalidOperationException(); - } - } - - object ICustomAstVisitor.VisitErrorStatement(ErrorStatementAst errorStatementAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitErrorExpression(ErrorExpressionAst errorExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitScriptBlock(ScriptBlockAst scriptBlockAst) - { - ValidateScriptBlock(scriptBlockAst); - - // We've already processed a sequence - if (bodyElements.Count != 0) - { - ReportError("CannotProcessMoreThanOneScriptBlock", ActivityResources.CannotProcessMoreThanOneScriptBlock, scriptBlockAst.Extent); - } - - WriteLine(""); - IndentLevel(); - EnterScope(); - - try - { - if (scriptBlockAst.ParamBlock != null) - { - scriptBlockAst.ParamBlock.Visit(this); - } - - // Initialize the 'result' reference parameter with empty collection, without this result parameter is generating - // wrong results if it is first used in a += operation in Powershell value activity. - if(members.ContainsKey("result") && typeof(PSDataCollection).IsAssignableFrom(members["result"].Type)) - { - GeneratePowerShellValue(typeof(PSDataCollection), "@()", false, "result"); - } - - if (scriptBlockAst.EndBlock != null) - { - scriptBlockAst.EndBlock.Visit(this); - } - } - finally - { - DumpVariables("Sequence"); - LeaveScope(); - - UnindentLevel(); - WriteLine(""); - } - - return null; - } - - private void ValidateScriptBlock(ScriptBlockAst scriptBlockAst) - { - if (scriptBlockAst.DynamicParamBlock != null) - { - ReportError("DynamicParametersNotSupported", ActivityResources.DynamicParametersNotSupported, scriptBlockAst.DynamicParamBlock.Extent); - } - if (scriptBlockAst.BeginBlock != null) - { - ReportError("BeginNotSupported", ActivityResources.BeginProcessNotSupported, scriptBlockAst.BeginBlock.Extent); - } - if (scriptBlockAst.ProcessBlock != null) - { - ReportError("ProcessNotSupported", ActivityResources.BeginProcessNotSupported, scriptBlockAst.ProcessBlock.Extent); - } - } - - object ICustomAstVisitor.VisitTypeConstraint(TypeConstraintAst typeConstraintAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitAttribute(AttributeAst attributeAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitParameter(ParameterAst parameterAst) - { - Type parameterType = parameterAst.StaticType; - string parameterName = parameterAst.Name.VariablePath.ToString(); - string actualParameterName; - if (!IsValidMemberName(parameterName, out actualParameterName, true)) - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.InvalidMemberName, parameterName); - ReportError("MemberNameNotValid", error, parameterAst.Extent); - } - - // If we've already seen the parameter, it's an error, but that error should have been reported by the parser. - if (members.ContainsKey(parameterName)) - { - return null; - } - - // Store any parameter validation - if ((parameterAst.Attributes.Count > 0) || - (parameterAst.DefaultValue != null)) - { - if(! parameterValidation.ContainsKey(parameterName)) - { - parameterValidation[parameterName] = parameterAst; - } - } - - // If the parameter is not typed and they've given a default - // value, then use the static type from the default. - if (parameterType == typeof(System.Object)) - { - if (parameterAst.DefaultValue != null) - { - bool constrainedToObject = false; - - // Check if it was constrained that way - if (parameterAst.Attributes.Count > 0) - { - foreach (AttributeBaseAst attribute in parameterAst.Attributes) - { - if (attribute is TypeConstraintAst) - { - constrainedToObject = true; - break; - } - } - } - - if (!constrainedToObject) - { - parameterType = parameterAst.DefaultValue.StaticType; - } - } - } - - string memberTemplate = @""; - - // If it's a reference type, we need to generate an OutArgument - if (parameterType == typeof(System.Management.Automation.PSReference)) - { - // Unfortunately, you can't type constrain these. Determine the - // type through flow analysis. (Good version TBD!) - parameterType = DetectType(parameterName, true, scriptWorkflowAstRoot); - memberTemplate = @""; - } - - // If they've specified a default value, save that so we can add it to the - // workflow. - if (parameterAst.DefaultValue != null) - { - bool areParameterAndDefaultCompatible = - (parameterAst.StaticType == typeof(object)) || - (parameterAst.StaticType == typeof(bool)) || - (parameterAst.StaticType == parameterAst.DefaultValue.StaticType); - - bool isSupportedDefaultType = - areParameterAndDefaultCompatible && - ( - parameterAst.DefaultValue.StaticType.IsPrimitive || - (parameterAst.DefaultValue.StaticType == typeof(string)) || - parameterAst.StaticType == typeof(bool) - ); - - if (!isSupportedDefaultType) - { - ReportError("OnlySimpleParameterDefaultsSupported", ActivityResources.OnlySimpleParameterDefaultsSupported, parameterAst.DefaultValue.Extent); - return null; - } - - ConstantExpressionAst parameterValue = parameterAst.DefaultValue as ConstantExpressionAst; - - if (parameterValue != null) - { - this.memberDefaults[parameterName] = EncodeStringArgument(parameterValue.Value.ToString(), false); - } - else - { - string valueText = parameterAst.DefaultValue.Extent.Text; - - // Do some hand tweaking for booleans, which actually come as variable expressions - valueText = GetEquivalentVBTextForLiteralValue(parameterAst.StaticType, valueText); - if (valueText == null) - { - ReportError("OnlySimpleParameterDefaultsSupported", ActivityResources.OnlySimpleParameterDefaultsSupported, parameterAst.DefaultValue.Extent); - return null; - } - - this.memberDefaults[parameterName] = EncodeStringArgument(valueText, false); - } - } - - string xamlDefinition = String.Format(CultureInfo.InvariantCulture, memberTemplate, parameterName, GetConvertedTypeName(parameterType)); - VariableDefinition member = new VariableDefinition() { Name = parameterName, Type = parameterType, XamlDefinition = xamlDefinition }; - members.Add(parameterName, member); - - return null; - } - - private string GetEquivalentVBTextForLiteralValue(Type argumentType, string valueText) - { - string result = null; - - if (argumentType == typeof(bool)) - { - if (String.Equals(valueText, "$true", StringComparison.OrdinalIgnoreCase) || - String.Equals(valueText, "$false", StringComparison.OrdinalIgnoreCase)) - { - result = valueText.Substring(1); - } - } - - return result; - } - - private bool IsValidMemberName(string name, out string actualVariableName, bool isParameter) - { - actualVariableName = name; - if (name == null) { return false; } - - if (!isParameter) - { - // Allow the "WORKFLOW:" scope qualifier in nested scopes - if (name.IndexOf(':') >= 0) - { - if ((name.StartsWith("WORKFLOW:", StringComparison.OrdinalIgnoreCase)) && - (scopes.Count > 1)) - { - name = name.Remove(0, "WORKFLOW:".Length); - actualVariableName = name; - } - else - { - return false; - } - } - } - - // Alphabetic to start, alphabetic plus numbers, dash, and underscore for the rest. - return Regex.IsMatch(name, "^[a-zA-Z][a-zA-Z0-9-_]*$"); - } - - private Type DetectType(string parameterName, bool isReference, Ast scriptRoot) - { - // Currently only does enough to detect simple derivation of [ref] types: - // $Variable.Value = Expression - Func assignmentSearcher = (ast) => - { - AssignmentStatementAst assignment = ast as AssignmentStatementAst; - UnaryExpressionAst unaryExpression = ast as UnaryExpressionAst; - - if ((assignment == null) && (unaryExpression == null)) - { - return false; - } - - // Check if this is a unary assignment - if (unaryExpression != null) - { - VariableExpressionAst referenceVariable = unaryExpression.Child as VariableExpressionAst; - if (referenceVariable != null && String.Equals(referenceVariable.VariablePath.UserPath, parameterName, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - // Check if this is a regular assignment - if (assignment == null) { return false; } - - if (isReference) - { - MemberExpressionAst member = assignment.Left as MemberExpressionAst; - if (member == null) { return false; } - - VariableExpressionAst variable = member.Expression as VariableExpressionAst; - if (variable == null) { return false; } - - // See if it's the variable we're looking for - // Variable.Value = - if ( - (String.Equals(variable.VariablePath.ToString(), parameterName, StringComparison.OrdinalIgnoreCase)) && - (String.Equals(member.Member.ToString(), "Value", StringComparison.OrdinalIgnoreCase)) - ) - { - CommandExpressionAst value = assignment.Right as CommandExpressionAst; - if (value == null) { return false; } - - return true; - } - } - else - { - // Capture $x = 10 - VariableExpressionAst variableExpression = assignment.Left as VariableExpressionAst; - string detectedVariableName = null; - - // Don't count PlusEquals for type detection, as we enforce that during assignment - // itself - if (assignment.Operator == TokenKind.PlusEquals) - { - return false; - } - - if (variableExpression == null) - { - // Capture [int] $x = 10 - ConvertExpressionAst convertExpression = assignment.Left as ConvertExpressionAst; - if (convertExpression != null) - { - variableExpression = convertExpression.Child as VariableExpressionAst; - } - } - - if (variableExpression != null) - { - detectedVariableName = variableExpression.VariablePath.UserPath; - } - else - { - return false; - } - - // See if it's the variable we're looking for - // Variable = - string workingVariableName = detectedVariableName; - - // Allow the "WORKFLOW:" scope qualifier in nested scopes - if (workingVariableName.StartsWith("WORKFLOW:", StringComparison.OrdinalIgnoreCase)) - { - workingVariableName = workingVariableName.Remove(0, "WORKFLOW:".Length); - } - - if (String.Equals(workingVariableName, parameterName, StringComparison.OrdinalIgnoreCase)) - { - // Ignore assignments to parallel script blocks (Variable = [parallel()] { ... }) - var value = assignment.Right as CommandExpressionAst; - if (value != null) - { - return true; - } - - // Ignore statements like foreach -parallel, parallel and sequence block - return !(assignment.Right is ForEachStatementAst) && !(assignment.Right is BlockStatementAst); - } - } - - return false; - }; - - List resultNodes = scriptRoot.FindAll(assignmentSearcher, searchNestedScriptBlocks: true).ToList(); - - // We couldn't detect the type. Assume PSDataCollection) - if (resultNodes.Count == 0) - { - return typeof(PSDataCollection); - } - - HashSet detectedTypes = new HashSet(); - foreach (Ast result in resultNodes) - { - AssignmentStatementAst assignmentStatement = result as AssignmentStatementAst; - if (assignmentStatement == null) - { - continue; - } - - ConvertExpressionAst convertExpression = assignmentStatement.Left as ConvertExpressionAst; - if (convertExpression != null) - { - Type detectedType = convertExpression.StaticType; - detectedTypes.Add(detectedType); - continue; - } - - PipelineAst invocationExpression = assignmentStatement.Right as PipelineAst; - if (invocationExpression != null) - { - if (invocationExpression.PipelineElements.Count == 1 && invocationExpression.PipelineElements[0] is CommandAst) - { - var commandAst = (CommandAst)invocationExpression.PipelineElements[0]; - string commandName = commandAst.GetCommandName(); - CommandInfo command; - - bool searchSessionState = !this.ValidateOnly; - ActivityKind activityKind = ResolveActivityKindBasedOnCommandName(commandName, commandAst, out command, searchSessionState); - - if (activityKind == ActivityKind.NewObject) - { - Dictionary parameters = GetAndResolveParameters(commandAst, true); - - if (parameters.ContainsKey("TypeName")) - { - string paramValue = parameters["TypeName"].OriginalValue.ToString(); - Type actualResultType = ResolveTypeFromParameterValue(commandAst, paramValue); - - if (actualResultType != null) - { - detectedTypes.Add(actualResultType); - } - continue; - } - } - else if ( - // For generic activities, the CommandInfo should be resolved to null - activityKind == ActivityKind.RegularCommand && command == null) - { - // Skip this expensive step if we are in parse mode - if (!this.ValidateOnly) - { - CommandInfo unusedCommandInfo; - Type[] genericTypes; - Type activityType = ResolveActivityType(commandName, commandAst, false, out unusedCommandInfo, out genericTypes); - - // By convention, the 'TResult' must be the last item in 'genericArgumentTypes' - Type[] genericArgumentTypes = null; - if (activityType != null && activityType.IsGenericType && genericTypes != null && - IsAssignableFromGenericType(typeof(Activity<>), activityType, out genericArgumentTypes)) - { - var genericTypeMap = GetGenericTypeMap(activityType, genericTypes); - var actualResultType = GetActualPropertyType(genericArgumentTypes[genericArgumentTypes.Length - 1], genericTypeMap, "Result", commandAst.Extent); - detectedTypes.Add(actualResultType); - continue; - } - } - } - } - - detectedTypes.Add(typeof(PSDataCollection)); - } - } - - // We detected an unambiguous type - if (detectedTypes.Count == 1) - { - return detectedTypes.ElementAt(0); - } - else if (detectedTypes.Contains(typeof(PSDataCollection))) - { - // When we see that a variable is storing the result of an activity call, - // we can't have the detected type be an Object, as Workflow doesn't allow that. - // So we just return PSDataCollection in that case. - return typeof(PSDataCollection); - } - else - { - // It was ambiguous, or of several types - return typeof(Object); - } - } - - internal ActivityKind ResolveActivityKindBasedOnCommandName(string commandName, CommandAst commandAst, out CommandInfo command, bool searchSessionState) - { - command = null; - - if (String.IsNullOrEmpty(commandName)) - { - return ActivityKind.RegularCommand; - } - - // Check if this is InlineScript activity - if (String.Equals(commandName, "InlineScript", StringComparison.OrdinalIgnoreCase)) - { - return ActivityKind.InlineScript; - } - // Check if this is a persist activity - else if ( - String.Equals(commandName, CheckpointWorkflow, StringComparison.OrdinalIgnoreCase) || - String.Equals(commandName, "persist", StringComparison.OrdinalIgnoreCase) - ) - { - return ActivityKind.Persist; - } - // Check if this is a suspend activity - else if (String.Equals(commandName, SuspendWorkflow, StringComparison.OrdinalIgnoreCase)) - { - return ActivityKind.Suspend; - } - // Check if this is inline XAML - else if ( - String.Equals(commandName, "Invoke-Expression", StringComparison.OrdinalIgnoreCase) || - String.Equals(commandName, "iex", StringComparison.OrdinalIgnoreCase) - ) - { - StaticBindingResult bindingResult = null; - if (commandAst != null) - { - bindingResult = StaticParameterBinder.BindCommand(commandAst, false, new string[] { "Language" }); - } - - // If they've specified the "-Language" parameter, invoke the - // built-in Invoke-Expression support for inline XAML - if ((bindingResult != null) && (bindingResult.BoundParameters.ContainsKey("Language"))) - { - return ActivityKind.InvokeExpression; - } - else - { - if (searchSessionState) - { - command = ResolveCommand(commandName); - } - - // Otherwise, use the Invoke-Expression activity - return ActivityKind.RegularCommand; - } - } - // Check if this is a delay activity - else if ( - String.Equals(commandName, "Start-Sleep", StringComparison.OrdinalIgnoreCase) || - String.Equals(commandName, "sleep", StringComparison.OrdinalIgnoreCase) - ) - { - return ActivityKind.Delay; - } - // Check if this is a New-Object activity - else if (String.Equals(commandName, "New-Object", StringComparison.OrdinalIgnoreCase)) - { - if (searchSessionState) - { - command = ResolveCommand(commandName); - } - - return ActivityKind.NewObject; - } - // This is another command name - else - { - var entry = scope.LookupCommand(commandName); - if (entry != null) - { - command = entry.workflowInfo; - } - - if (searchSessionState && command == null) - { - command = ResolveCommand(commandName); - } - - return ActivityKind.RegularCommand; - } - } - - /// - /// Block variable scope prefix like "$GLOBAL:" and "$SCRIPT:". In script workflow, - /// the only valid scope prefix is "$WORKFLOW:". When generating expression for the - /// PowerShellValue activity, we need to remove the $WORKFLOW part. Otherwise it will - /// generate error during execution, because the prefix "WORKFLOW" is not actually - /// supported in the PowerShell. - /// - /// - /// - private string GetPowerShellValueExpression(Ast expression) - { - Func variableSearcher = (ast) => - { - var variableExpr = ast as VariableExpressionAst; - if (variableExpr == null) - { - return false; - } - - string variableName = variableExpr.VariablePath.ToString(); - if (variableName.IndexOf(':') != -1 && !variableName.StartsWith("ENV:", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - return false; - }; - - List resultNodes = expression.FindAll(variableSearcher, searchNestedScriptBlocks: true).ToList(); - if (resultNodes.Count == 0) - { - return expression.Extent.Text; - } - - string valueExpression = expression.Extent.ToString(); - foreach (Ast node in resultNodes) - { - var variableNode = node as VariableExpressionAst; - if (variableNode == null) - { - continue; - } - - string variableName = variableNode.VariablePath.ToString(); - string variableSign = variableNode.Splatted ? "@" : "$"; - if (variableName.IndexOf(':') != -1) - { - if (!variableName.StartsWith("WORKFLOW:", StringComparison.OrdinalIgnoreCase)) - { - ReportError("InvalidScopePrefixInWorkflow", ActivityResources.InvalidScopePrefixInWorkflow, variableNode.Extent); - } - else - { - string actualVariableName = variableName.Remove(0, "WORKFLOW:".Length); - string oldValue = variableSign + variableName; - string newValue = variableSign + actualVariableName; - valueExpression = valueExpression.Replace(oldValue, newValue); - } - } - } - - return valueExpression; - } - - object ICustomAstVisitor.VisitTypeExpression(TypeExpressionAst typeExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst) - { - // Process top-level workflow to generate the callable function, nested functions must be handled by the caller. - if (functionDefinitionAst != scriptWorkflowAstRoot) return null; - - // Generate the parameters applied to the function itself - if (functionDefinitionAst.Parameters != null) - { - foreach (ParameterAst parameter in functionDefinitionAst.Parameters) - { - parameter.Visit(this); - } - } - - // Extract the cmdlet binding attribute and save it to add to the generated function text... - bool foundCmdletBinding = false; - if (functionDefinitionAst.Body.ParamBlock != null && functionDefinitionAst.Body.ParamBlock.Attributes != null) - { - foreach (var attribute in functionDefinitionAst.Body.ParamBlock.Attributes) - { - if (typeof(CmdletBindingAttribute) == attribute.TypeName.GetReflectionAttributeType()) - { - bool error = false; - - if (attribute.PositionalArguments.Count != 0) - { - ReportError("InvalidCmdletBindingAttribute", ActivityResources.InvalidCmdletBindingAttribute, functionDefinitionAst.Extent); - error = true; - } - else - { - foreach(NamedAttributeArgumentAst namedArg in attribute.NamedArguments) - { - if(!namedArg.ArgumentName.Equals("DefaultParameterSetName", StringComparison.OrdinalIgnoreCase) && - !namedArg.ArgumentName.Equals("ConfirmImpact", StringComparison.OrdinalIgnoreCase) && - !namedArg.ArgumentName.Equals("HelpUri", StringComparison.OrdinalIgnoreCase) && - !namedArg.ArgumentName.Equals("PositionalBinding", StringComparison.OrdinalIgnoreCase)) - { - ReportError("InvalidCmdletBindingAttribute", ActivityResources.InvalidCmdletBindingAttribute, functionDefinitionAst.Extent); - error = true; - } - } - } - - if (!error) - { - foundCmdletBinding = true; - - if (String.IsNullOrEmpty(this.CmdletAttributeText)) - { - this.CmdletAttributeText = attribute.ToString(); - } - else - { - this.CmdletAttributeText += "\r\n" + attribute.ToString(); - } - } - } - - if ((typeof(OutputTypeAttribute) == attribute.TypeName.GetReflectionAttributeType()) || - (typeof(AliasAttribute) == attribute.TypeName.GetReflectionAttributeType())) - { - if (String.IsNullOrEmpty(this.CmdletAttributeText)) - { - this.CmdletAttributeText = attribute.ToString(); - } - else - { - this.CmdletAttributeText += "\r\n" + attribute.ToString(); - } - } - } - } - - if (!foundCmdletBinding) - { - if (String.IsNullOrEmpty(this.CmdletAttributeText)) - { - this.CmdletAttributeText = "[CmdletBinding()]"; - } - else - { - this.CmdletAttributeText += "\r\n[CmdletBinding()]"; - } - } - - functionDefinitionAst.Body.Visit(this); - - return null; - } - - /// - /// Used to hold the CmdletBinding attribute string specified in the script workflow text. - /// This needs to be propagated to the synthesized driver function . - /// - internal string CmdletAttributeText { get; set; } - - object ICustomAstVisitor.VisitParamBlock(ParamBlockAst paramBlockAst) - { - foreach (ParameterAst parameter in paramBlockAst.Parameters) - { - parameter.Visit(this); - } - - return null; - } - - object ICustomAstVisitor.VisitNamedBlock(NamedBlockAst namedBlockAst) - { - if (namedBlockAst.BlockKind != TokenKind.End) - { - ReportError("BeginProcessNotSupported", ActivityResources.BeginProcessNotSupported, namedBlockAst.Extent); - } - - if (namedBlockAst.Traps != null) - { - foreach(TrapStatementAst ast in namedBlockAst.Traps) - { - ast.Visit(this); - } - } - - DefineVariable("WorkflowCommandName", typeof(string), namedBlockAst.Extent, this.name); - - if (namedBlockAst.Statements != null) - { - foreach (StatementAst ast in namedBlockAst.Statements) - { - ast.Visit(this); - } - } - - return null; - } - - object ICustomAstVisitor.VisitStatementBlock(StatementBlockAst statementBlockAst) - { - // If the statement block is the body of a parallel block statement, we enclose each - // statement in a Try/Catch block, so that: - // 1. the activities generated for each statement will be executed sequentially. - // 2. the terminating exception thrown from one statement will not terminate other statements that - // are running in parallel. - var blockStatement = statementBlockAst.Parent as BlockStatementAst; - bool needToEncloseStatementInTryCatchBlock = blockStatement != null - && blockStatement.Kind.Text.Equals(TokenKind.Parallel.Text(), StringComparison.OrdinalIgnoreCase); - - foreach (StatementAst statement in statementBlockAst.Statements) - { - try - { - if (needToEncloseStatementInTryCatchBlock) - { - // Start to add the Try/Catch block - AddTryCatchForParallelStart(); - - WriteLine(""); - IndentLevel(); - } - statement.Visit(this); - } - finally - { - if (needToEncloseStatementInTryCatchBlock) - { - UnindentLevel(); - WriteLine(""); - - // Finish the Try/Catch block - AddTryCatchForParallelEnd(); - } - } - } - - return null; - } - - object ICustomAstVisitor.VisitIfStatement(IfStatementAst ifStmtAst) - { - Collection> ifClauses = new Collection>(); - foreach (Tuple ifClause in ifStmtAst.Clauses) - { - ifClauses.Add(ifClause); - } - GenerateIf(ifClauses, ifStmtAst.ElseClause); - - return null; - } - - private void GenerateIf(Collection> ifClauses, StatementBlockAst elseClause) - { - Tuple ifClause = ifClauses[0]; - ifClauses.RemoveAt(0); - - // Generate a temporary variable for the if condition - string tempVarName = GenerateUniqueVariableName("IfCondition"); - Type conditionType = DetectType(tempVarName, false, ifClause.Item1); - DefineVariable(tempVarName, conditionType, ifClause.Item1.Extent, null); - - // Generate the assignment of the the clause to the temporary variable - string conditionExpression = GetPowerShellValueExpression(ifClause.Item1); - GenerateAssignment(tempVarName, ifClause.Item1.Extent, TokenKind.Equals, ifClause.Item1, conditionExpression); - - // Note that symbols are generated from the above GenerateAssignment call. - WriteLine(""); - IndentLevel(); - - // Generate the "If" - WriteLine(""); - IndentLevel(); - - // Convert the results of the condition to a boolean via PowerShellValue - string boolFriendlyName = GetConvertedTypeName(typeof(bool)); - WriteLine(@""); - IndentLevel(); - - GeneratePowerShellValue(typeof(bool), "$" + tempVarName, false, false); - - UnindentLevel(); - WriteLine(""); - - UnindentLevel(); - WriteLine(""); - - // Generate the "Then" - WriteLine(""); - IndentLevel(); - WriteLine(""); - IndentLevel(); - - ifClause.Item2.Visit(this); - - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(""); - - // Generate the "Else" - if ((ifClauses.Count > 0) || (elseClause != null)) - { - WriteLine(""); - IndentLevel(); - - WriteLine(""); - IndentLevel(); - - // If we had an "ElseIf", then it's an "If" statement nested in an Else statement - if (ifClauses.Count > 0) - { - GenerateIf(ifClauses, elseClause); - } - else - { - if (elseClause != null) - { - GenerateSymbolicInformation(elseClause.Extent); - elseClause.Visit(this); - } - } - - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(""); - } - - UnindentLevel(); - WriteLine(""); - } - - object ICustomAstVisitor.VisitTrap(TrapStatementAst trapStatementAst) - { - ReportError("TrapNotSupported", ActivityResources.TrapNotSupported, trapStatementAst.Extent); - return null; - } - - object ICustomAstVisitor.VisitAssignmentStatement(AssignmentStatementAst assignmentStatementAst) - { - StatementAst right = null; - string variableName = null; - VariableExpressionAst leftExpressionAst = null; - - AttributedExpressionAst leftAttributeAst = assignmentStatementAst.Left as AttributedExpressionAst; - if (leftAttributeAst != null) - { - leftExpressionAst = leftAttributeAst.Child as VariableExpressionAst; - } - else - { - leftExpressionAst = assignmentStatementAst.Left as VariableExpressionAst; - } - - // This was neither a variable assignment, nor a strongly-typed variable - if (leftExpressionAst == null) - { - ReportError("AssignmentNotSupported", ActivityResources.AssignmentNotSupported, assignmentStatementAst.Left.Extent); - return null; - } - - // check if the left-hand itself has any side effects - string nameOfUnSupportedVariableFound = null; - if (CheckIfExpressionHasUnsupportedVariableOrHasSideEffects(null, leftExpressionAst, out nameOfUnSupportedVariableFound)) - { - if (!string.IsNullOrEmpty(nameOfUnSupportedVariableFound)) - { - string error = String.Format(CultureInfo.InvariantCulture, - ActivityResources.VariableNotSupportedInWorkflow, - nameOfUnSupportedVariableFound); - ReportError("VariableNotSupportedInWorkflow", error, leftExpressionAst.Extent); - } - } - - variableName = leftExpressionAst.VariablePath.ToString(); - right = assignmentStatementAst.Right; - - string expression = GetPowerShellValueExpression(assignmentStatementAst); - GenerateAssignment(variableName, leftExpressionAst.Extent, assignmentStatementAst.Operator, right, expression); - - return null; - } - - private void GenerateAssignment(string variableName, IScriptExtent errorExtent, TokenKind assignmentOperator, Ast value, string expression) - { - // Give a good error message specifically for environment variable names - if (variableName.StartsWith("env:", StringComparison.OrdinalIgnoreCase)) - { - ReportError("EnvironmentVariableAssignmentNotSupported", ActivityResources.EnvironmentVariableAssignmentNotSupported, errorExtent); - } - - string actualVariableName; - if (!IsValidMemberName(variableName, out actualVariableName, false)) - { - // This was an error with variable scoping - if (variableName.IndexOf(':') > 0) - { - ReportError("WorkflowScopeOnlyValidInParallelOrSequenceBlock", ActivityResources.WorkflowScopeOnlyValidInParallelOrSequenceBlock, errorExtent); - } - else - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.InvalidMemberName, variableName); - ReportError("VariableNameNotValid", error, errorExtent); - } - } - - // Give a good error message if they've used a reserved variable name - if (IsReservedVariableName(actualVariableName)) - { - Dictionary propsCanBeSet = GetAvailableProperties(typeof(SetPSWorkflowData), null); - if (propsCanBeSet.ContainsKey(actualVariableName)) - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.VariableNameReserved, variableName); - ReportError("VariableNameReserved", error, errorExtent); - } - else - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.VariableNameReadOnly, variableName); - ReportError("VariableNameReadOnly", error, errorExtent); - } - } - - // Check if the value itself contains side-effects. If so, generate an error. - string nameOfUnSupportedVariableFound = null; - if (CheckIfExpressionHasUnsupportedVariableOrHasSideEffects(variableName, value, out nameOfUnSupportedVariableFound)) - { - if (string.IsNullOrEmpty(nameOfUnSupportedVariableFound)) - { - string errorTemplate = ActivityResources.CannotStoreResultsInUnsupportedElement; - ReportError("CannotStoreResultsInUnsupportedElement", - ActivityResources.CannotStoreResultsInUnsupportedElement, value.Extent); - return; - } - else - { - string error = String.Format(CultureInfo.InvariantCulture, - ActivityResources.VariableNotSupportedInWorkflow, - nameOfUnSupportedVariableFound); - ReportError("VariableNotSupportedInWorkflow", error, value.Extent); - } - } - - Type variableType = null; - if(members.ContainsKey(actualVariableName)) - { - variableType = members[actualVariableName].Type; - } - - if (variableType == null) - { - VariableDefinition variable = GetVariableDefinition(actualVariableName); - if (variable != null) - { - variableType = variable.Type; - } - } - - if (variableType == null) - { - variableType = DetectType(actualVariableName, false, scriptWorkflowAstRoot); - } - - // Create the variable if it hasn't been created - if ((!VariableDefinedInCurrentScope(variableName)) && - (!members.ContainsKey(actualVariableName))) - { - DefineVariable(variableName, variableType, errorExtent, null); - } - - // Create the variable assignment. If this is of type PSActivity, then we can - // set the variable as the result. - if (LocalVariableAlreadyExisting()) - { - string errorTemplate = ActivityResources.CannotStoreResultsInVariable; - string error = String.Format(CultureInfo.InvariantCulture, errorTemplate, variableName, resultVariables.Peek().VariableName); - - ReportError("CannotStoreResultsInVariable", error, errorExtent); - return; - } - - // Should not override a data collecting variable - if (IsDataAggregatingVariable(actualVariableName)) - { - string errorMessage = String.Format(CultureInfo.InvariantCulture, ActivityResources.CannotUseDataCollectingVariable, actualVariableName); - ReportError("CannotUseDataCollectingVariable", errorMessage, errorExtent); - } - - bool isAggregatingVariable = false; - if (assignmentOperator == TokenKind.PlusEquals) - { - isAggregatingVariable = true; - } - - // Generate debug symbol information for variable assignments. - GenerateSymbolicInformation(value.Extent); - - // Visit the right-hand side of the expression for activities - PipelineAst rightPipeline = value as PipelineAst; - if (rightPipeline != null) - { - try - { - EnterStorage(actualVariableName, isAggregatingVariable); - value.Visit(this); - } - finally - { - LeaveStorage(); - } - } - else if (value is BlockStatementAst || value is ForEachStatementAst) - { - try - { - EnterStorage(actualVariableName, true); - value.Visit(this); - } - finally - { - LeaveStorage(); - } - } - else - { - // Support simple assignment expressions, such as hashtables, ranges, etc. - // Specifically exclude subexpressions, as they are supported by InlineScript. - CommandExpressionAst rightExpression = value as CommandExpressionAst; - UnaryExpressionAst unaryExpression = value as UnaryExpressionAst; - - if (( - (rightExpression != null) && (!(rightExpression.Expression is SubExpressionAst)) && - ((rightExpression.Expression is ConvertExpressionAst) || !(rightExpression.Expression is AttributedExpressionAst)) - ) || - (unaryExpression != null) - ) - { - try - { - EnterStorage(actualVariableName, false); - - // We rewrite an assignment such as: "$x = $x + 1" to "$x = $x + 1; $x" so that - // PowerShell returns the new value after assignment. This is especially required - // for statements such as $x++, which normally have no output. - string assignmentExpression = null; - - if (assignmentOperator != TokenKind.Equals) - { - // We rewrite an assignment such as: "$x = $x + 1" to "$x = $x + 1; $x" so that - // PowerShell returns the new value after assignment. This is required - // for statements such as $x++, which normally have no output. - assignmentExpression = expression + "; ,($" + actualVariableName + ")"; - } - else - { - assignmentExpression = GetPowerShellValueExpression(rightExpression); - } - - GeneratePowerShellValue(variableType, assignmentExpression, false, true); - } - finally - { - LeaveStorage(); - } - } - else - { - ReportError("CannotStoreResultsInUnsupportedElement", ActivityResources.CannotStoreResultsInUnsupportedElement, value.Extent); - } - } - } - - private bool IsReservedVariableName(string variable) - { - PSWorkflowRuntimeVariable unused; - return Enum.TryParse(variable, true, out unused); - } - - private void DefineVariable(string name, Type variableType, IScriptExtent extent, string defaultValue) - { - VariableScope scopeToUse = scopes.Peek(); - if (name.StartsWith("WORKFLOW:", StringComparison.OrdinalIgnoreCase)) - { - scopeToUse = scopes.Last(); - name = name.Remove(0, "WORKFLOW:".Length); - } - - // Check that it's not already defined - foreach (VariableScope scope in scopes) - { - if (scope.Variables.ContainsKey(name)) - { - string errorMessage = String.Format(CultureInfo.InvariantCulture, ActivityResources.VariableAlreadyDefined, name); - ReportError("VariableAlreadyDefined", errorMessage, extent); - } - } - - string convertedTypeName = GetConvertedTypeName(variableType); - - string defaultValueTemplate = "Default = \"{0}\" "; - string defaultValueElement = String.Empty; - if (!String.IsNullOrEmpty(defaultValue)) - { - defaultValueElement = String.Format(CultureInfo.InvariantCulture, defaultValueTemplate, EncodeStringArgument(defaultValue, false)); - } - - string xamlDefinition = String.Format(CultureInfo.InvariantCulture, MemberTemplate, name, convertedTypeName, defaultValueElement); - VariableDefinition variable = new VariableDefinition() { Name = name, Type = variableType, XamlDefinition = xamlDefinition }; - - scopeToUse.Variables[name] = variable; - } - - private bool VariableDefined(string variableName) - { - if (variableName.StartsWith("WORKFLOW:", StringComparison.OrdinalIgnoreCase)) - { - variableName = variableName.Remove(0, "WORKFLOW:".Length); - } - - // Check that it's not already defined - foreach (VariableScope scope in scopes) - { - if (scope.Variables.ContainsKey(variableName)) - { - return true; - } - } - - return false; - } - - private bool VariableDefinedInCurrentScope(string variableName) - { - VariableScope scopeToCheck = scopes.Peek(); - - if (variableName.StartsWith("WORKFLOW:", StringComparison.OrdinalIgnoreCase)) - { - scopeToCheck = scopes.Last(); - variableName = variableName.Remove(0, "WORKFLOW:".Length); - } - - return scopeToCheck.Variables.ContainsKey(variableName); - } - - - private VariableDefinition GetVariableDefinition(string variableName) - { - return (from scope in scopes - where scope.Variables.ContainsKey(variableName) - select scope.Variables[variableName]).FirstOrDefault(); - } - - private void DumpVariables(string scopeType) - { - VariableScope currentScope = scopes.Peek(); - - if (currentScope.Variables.Count > 0) - { - WriteLine(String.Format(CultureInfo.InvariantCulture, "<{0}.Variables>", scopeType)); - IndentLevel(); - - foreach (VariableDefinition variable in currentScope.Variables.Values) - { - WriteLine(variable.XamlDefinition); - } - - UnindentLevel(); - WriteLine(String.Format(CultureInfo.InvariantCulture, "", scopeType)); - } - } - - private void EnterScope() - { - VariableScope newScope = new VariableScope(); - scopes.Push(newScope); - } - - private void LeaveScope() - { - scopes.Pop(); - } - - private void EnterStorage(string variable, bool isAggregatingVariable) - { - StorageVariable newStorage = new StorageVariable(variable, isAggregatingVariable); - resultVariables.Push(newStorage); - } - - private void LeaveStorage() - { - resultVariables.Pop(); - } - - - private StorageVariable GetVariableToUse() - { - if (resultVariables != null && resultVariables.Count > 0) - { - return resultVariables.Peek(); - } - - return null; - } - - private bool LocalVariableAlreadyExisting() - { - if (resultVariables != null && resultVariables.Count > 0) - { - return !resultVariables.Peek().IsAggregatingVariable; - } - return false; - } - - private bool IsDataAggregatingVariable(string actualVariableName) - { - // Check that it's not already defined - return resultVariables.Any(scope => scope.IsAggregatingVariable && scope.VariableName.Equals(actualVariableName, StringComparison.OrdinalIgnoreCase)); - } - - private string RemoveScriptBlockBraces(string expression) - { - string trimmedExpression = expression.Trim(); - - if (trimmedExpression.StartsWith("{", StringComparison.OrdinalIgnoreCase) && - trimmedExpression.EndsWith("}", StringComparison.OrdinalIgnoreCase)) - { - trimmedExpression = trimmedExpression.Remove(0, 1); - trimmedExpression = trimmedExpression.Remove(trimmedExpression.Length - 1, 1); - } - - return trimmedExpression; - } - - - private void GeneratePowerShellValue(Type outputType, string expression, bool isLiteral, string resultVariable) - { - if ((outputType == typeof(ScriptBlock)) || - (outputType == typeof(ScriptBlock[]))) - { - expression = RemoveScriptBlockBraces(expression); - } - - string convertedTypeName = GetConvertedTypeName(outputType); - string powerShellValueFriendlyName = GetFriendlyName(null, typeof(PowerShellValue)); - - bool useDefaultInput = System.Text.RegularExpressions.Regex.IsMatch(expression, "\\$input", RegexOptions.IgnoreCase); - - String valueLine = null; - - valueLine = String.Format(CultureInfo.InvariantCulture, - @"<" + powerShellValueFriendlyName + @" x:TypeArguments=""{0}"" Expression=""{1}""", - convertedTypeName, - EncodeStringNonArgument(expression, isLiteral) - ); - - if(! String.IsNullOrEmpty(resultVariable)) - { - valueLine += String.Format(CultureInfo.InvariantCulture, " Result=\"[{0}]\"", resultVariable); - } - - if (useDefaultInput) - { - valueLine += " UseDefaultInput=\"true\""; - } - - valueLine += " />"; - - WriteLine(valueLine); - } - - private void GeneratePowerShellValue(Type outputType, string expression, bool isLiteral, bool storeResults) - { - string resultVariable = null; - - if ((LocalVariableAlreadyExisting()) && (storeResults)) - { - resultVariable = resultVariables.Peek().VariableName; - } - - GeneratePowerShellValue(outputType, expression, isLiteral, resultVariable); - } - - - private bool CheckIfExpressionHasUnsupportedVariableOrHasSideEffects(string variableName, Ast root, out string nameOfUnSupportedVariableFound) - { - nameOfUnSupportedVariableFound = null; - if (root == null) { return false; } - - ExpressionHasUnsupportedVariableOrSideEffectsVisitor visitor = new ExpressionHasUnsupportedVariableOrSideEffectsVisitor(variableName); - root.Visit(visitor); - nameOfUnSupportedVariableFound = visitor.NameOfUnsupportedVariableFound; - - return visitor.ExpressionHasSideEffects; - } - - object ICustomAstVisitor.VisitPipeline(PipelineAst pipelineAst) - { - // If it's one command, generate the call alone - if (pipelineAst.PipelineElements.Count == 1) - { - pipelineAst.PipelineElements[0].Visit(this); - } - else - { - // It's a pipeline. Look for any elements that use -DisplayName or -PipelineVariable, as they become - // an inline foreach and simulate the -PipelineVariable concept in PowerShell. - // - // When used without Foreach -Sequence, - // - // A | B | C -PipelineVariable C2 | D -DisplayName D2 | E | F | G - // - // becomes - // - // foreach($C2 in A | B |C) - // { - // foreach($D2 in $C2 | D) - // { - // $D2 | E | F | G - // } - // } - // - // The pipeline variable becomes the foreach variable - // The commands up to (and including) the command with the pipeline variable - // become the foreach condition - // The commands after the command with the pipeline variable become the foreach - // body. - // - // When used with Foreach -Sequence, we create an iteration-style pipeline. - // This captures output state in hashtable elements, and restores the state during - // each iteration. - // - // A -PipelineVariable A2 | Foreach-Object -Sequence { Command1 } -PipelineVariable B1 | - // Foreach-Object -Sequence { Command2 } -PipelineVariable C1 - // - // becomes - // - // foreach($a2 in A) - // { - // $psPipelineResults = @( @{} ) - // - // $psPipelineResults = foreach($item in $psPipelineResults) - // { - // foreach($output in Command1) - // { - // $result = $item.Clone() - // $result["B1"] = $output - // $result["_"] = $output - // $result - // } - // } - // - // $psPipelineResults = foreach($item in $psPipelineResults) - // { - // foreach($output in Command2) - // { - // $B1 = $item["B1"] - // $PSItem = $item["_"] - // - // $result = $item.Clone() - // $result["C1"] = $output - // $result["_"] = $output - // $result - // } - // } - // - // foreach($item in $psPipelineResults) { $item["_"] } - // } - - List prePipelineElements = new List(); - List postPipelineElements = new List(); - List iterativePipelineElements = new List(); - - string currentPipelineVariable = null; - string nonIterativePipelineVariable = null; - List iterativePipelineVariables = new List(); - bool isIterativePipeline = false; - bool isIterativeCommand = false; - bool processedPipelineVariable = false; - - foreach (CommandBaseAst commandBase in pipelineAst.PipelineElements) - { - // If this defines a DisplayName or PipelineVariable, then we need to split this - // pipeline into two segments. - CommandAst command = commandBase as CommandAst; - isIterativeCommand = false; - - if (command != null) - { - StaticBindingResult bindingResult = StaticParameterBinder.BindCommand(command, false); - IScriptExtent errorExtent = null; - - // Get the argument for the PipelineVariable parameter - last one wins. - currentPipelineVariable = null; - string boundParameter = null; - string[] parametersToCheck = new string[] { "DisplayName", "PV", "PipelineVariable" }; - - foreach (string parameterName in parametersToCheck) - { - if (GetArgumentAndExtentForParameter(parameterName, ref currentPipelineVariable, bindingResult, ref errorExtent)) - { - // Ensure it wasn't treated like a switch statement - if (String.Equals(currentPipelineVariable, "-" + parameterName, StringComparison.OrdinalIgnoreCase)) - { - currentPipelineVariable = ""; - } - - boundParameter = parameterName; - - // DisplayName can also be used as a Activity.DisplayName in that case DisplayName param value is not treated as a PipelineVariable - if (String.Equals(parameterName, "DisplayName", StringComparison.OrdinalIgnoreCase) && - !Regex.IsMatch(currentPipelineVariable, "^[a-zA-Z][a-zA-Z0-9-_]*$")) - { - currentPipelineVariable = null; - } - } - } - - if (currentPipelineVariable != null) - { - if(String.IsNullOrEmpty(currentPipelineVariable)) - { - string errorMsg = String.Format(CultureInfo.InvariantCulture, ActivityResources.MissingValueForParameter, boundParameter); - ReportError("MissingValueForParameter", errorMsg, errorExtent); - return null; - } - - ValidateVariableName(currentPipelineVariable, errorExtent); - } - - ScriptBlockExpressionAst sequenceParameter = null; - ScriptBlockExpressionAst beginParameter = null; - ScriptBlockExpressionAst endParameter = null; - - // If this is Foreach-Object, check if it's using the "-Sequence" flag. If so, we have an iterative pipeline. - string commandName = command.GetCommandName(); - IterativeCommands iterativeCommandType = IterativeCommands.None; - if (string.Equals("Foreach-Object", commandName, StringComparison.OrdinalIgnoreCase) || - string.Equals("%", commandName, StringComparison.OrdinalIgnoreCase)) - { - if (bindingResult.BoundParameters.ContainsKey("Sequence")) - { - iterativeCommandType = IterativeCommands.ForEachSequence; - - // Detect foreach-object in the wrong pipeline position (where there are no - // pre-pipeline elements) - if (prePipelineElements.Count == 0) - { - ReportError("InvalidForeachSequencePipelinePosition", ActivityResources.InvalidForeachSequencePipelinePosition, command.Extent); - return null; - } - - isIterativeCommand = true; - isIterativePipeline = true; - - List supportedParameters = new List() { "PipelineVariable", "PV", "DisplayName", "Begin", "Sequence", "End" }; - foreach(string parameter in bindingResult.BoundParameters.Keys) - { - if(! supportedParameters.Contains(parameter, StringComparer.OrdinalIgnoreCase)) - { - ReportError("InvalidForeachSequenceParameter", ActivityResources.InvalidForeachSequenceParameter, command.Extent); - } - } - - // Get the argument for the Sequence parameter, if it exists. - sequenceParameter = bindingResult.BoundParameters["Sequence"].Value as ScriptBlockExpressionAst; - if ((sequenceParameter == null) || (sequenceParameter.ScriptBlock.EndBlock.Statements.Count == 0)) - { - string errorMsg = String.Format(CultureInfo.InvariantCulture, ActivityResources.MissingValueForParameter, "Sequence"); - ReportError("MissingValueForParameter", errorMsg, bindingResult.BoundParameters["Sequence"].Value.Extent); - return null; - } - - // Get the argument for the Begin parameter, if it exists. - if (bindingResult.BoundParameters.ContainsKey("Begin")) - { - beginParameter = bindingResult.BoundParameters["Begin"].Value as ScriptBlockExpressionAst; - if ((beginParameter == null) || (beginParameter.ScriptBlock.EndBlock.Statements.Count == 0)) - { - string errorMsg = String.Format(CultureInfo.InvariantCulture, ActivityResources.MissingValueForParameter, "Begin"); - ReportError("MissingValueForParameter", errorMsg, bindingResult.BoundParameters["Begin"].Value.Extent); - return null; - } - } - - // Get the argument for the End parameter, if it exists. - if (bindingResult.BoundParameters.ContainsKey("End")) - { - endParameter = bindingResult.BoundParameters["End"].Value as ScriptBlockExpressionAst; - if ((endParameter == null) || (endParameter.ScriptBlock.EndBlock.Statements.Count == 0)) - { - string errorMsg = String.Format(CultureInfo.InvariantCulture, ActivityResources.MissingValueForParameter, "End"); - ReportError("MissingValueForParameter", errorMsg, bindingResult.BoundParameters["End"].Value.Extent); - return null; - } - } - - // It's now an iterative pipeline, remember the nonIterativePipelineVariable as one - // that needs to be set - if ((!String.IsNullOrEmpty(nonIterativePipelineVariable)) && - (! iterativePipelineVariables.Contains(nonIterativePipelineVariable, StringComparer.OrdinalIgnoreCase))) - { - iterativePipelineVariables.Add(nonIterativePipelineVariable); - } - - } - } - else if ((string.Equals("Where-Object", commandName, StringComparison.OrdinalIgnoreCase) || - string.Equals("?", commandName, StringComparison.OrdinalIgnoreCase) || - string.Equals("where", commandName, StringComparison.OrdinalIgnoreCase)) && - (bindingResult.BoundParameters.ContainsKey("Sequence"))) - { - iterativeCommandType = IterativeCommands.WhereSequence; - - // Detect Where-Object with -Sequence in the wrong pipeline position (where there are no - // pre-pipeline elements) - if (prePipelineElements.Count == 0) - { - ReportError("InvalidWhereSequencePipelinePosition", ActivityResources.InvalidWhereSequencePipelinePosition, command.Extent); - return null; - } - - isIterativeCommand = true; - isIterativePipeline = true; - - // Check supported parameters - List supportedParameters = new List() { "PipelineVariable", "PV", "Sequence" }; - foreach (string parameter in bindingResult.BoundParameters.Keys) - { - if (!supportedParameters.Contains(parameter, StringComparer.OrdinalIgnoreCase)) - { - ReportError("InvalidWhereSequenceParameter", ActivityResources.InvalidWhereSequenceParameter, command.Extent); - } - } - - // Get Sequence parameter argument. - sequenceParameter = bindingResult.BoundParameters["Sequence"].Value as ScriptBlockExpressionAst; - if ((sequenceParameter == null) || (sequenceParameter.ScriptBlock.EndBlock.Statements.Count == 0)) - { - string errorMsg = String.Format(CultureInfo.InvariantCulture, ActivityResources.MissingValueForParameter, "Sequence"); - ReportError("MissingValueForParameter", errorMsg, bindingResult.BoundParameters["Sequence"].Value.Extent); - return null; - } - - // This is now an interactive pipeline, remember the nonIterativePipelineVariable as one that needs to be set. - if (!String.IsNullOrEmpty(nonIterativePipelineVariable) && - !iterativePipelineVariables.Contains(nonIterativePipelineVariable, StringComparer.OrdinalIgnoreCase)) - { - iterativePipelineVariables.Add(nonIterativePipelineVariable); - } - } - - // Verify that once they've started an interactive pipeline, all commands are - // Foreach-Object -Sequence or Where-Object -Sequence. - if (isIterativePipeline && (! isIterativeCommand)) - { - ReportError("EntirePipelineMustUseForeachSequence", ActivityResources.EntirePipelineMustUseForeachSequence, command.Extent); - return null; - } - - // If this is the first command with the pipelineVariable, - // it is now the pipeline variable for the first portion of - // the pipeline. - if ((currentPipelineVariable != null) && (! processedPipelineVariable)) - { - nonIterativePipelineVariable = currentPipelineVariable; - } - - // Generate the iterative pipeline element if we got one. - if (isIterativePipeline) - { - switch (iterativeCommandType) - { - case IterativeCommands.ForEachSequence: - GenerateIterativePipelineElementForForEach(iterativePipelineElements, currentPipelineVariable, iterativePipelineVariables, beginParameter, sequenceParameter, endParameter); - break; - - case IterativeCommands.WhereSequence: - GenerateIterativePipelineElementForWhere(iterativePipelineElements, currentPipelineVariable, iterativePipelineVariables, sequenceParameter); - break; - } - - if (! String.IsNullOrEmpty(currentPipelineVariable)) - { - iterativePipelineVariables.Add(currentPipelineVariable); - } - } - } - - // Otherwise, remember the non-iterative command. - // If we haven't processed the command with the pipeline variable yet, then it goes - // into the prePipeline. Otherwise, it goes into the post pipeline. - if(! isIterativePipeline) - { - if (! processedPipelineVariable) - { - prePipelineElements.Add((CommandBaseAst)commandBase.Copy()); - - if (nonIterativePipelineVariable != null) - { - processedPipelineVariable = true; - } - } - else - { - postPipelineElements.Add(commandBase); - } - } - } - - // Generate the outputter if we had an iterative pipeline - if (isIterativePipeline) - { - string outputter = "foreach($item in $PSPipelineVariableContext) { $item['_'] }"; - Token[] unusedTokens = null; - ParseError[] unusedParseErrors = null; - Ast pipelineElementAst = Parser.ParseInput(outputter, out unusedTokens, out unusedParseErrors); - - iterativePipelineElements.AddRange(((ScriptBlockAst)pipelineElementAst).EndBlock.Statements); - } - - // See if this is a generated pipeline segment used to support a pipeline variable. - // If it is, don't process any further. - bool isInGeneratedPipeline = - (pipelineAst.Parent) != null && - (pipelineAst.Parent is ForEachStatementAst) && - (pipelineAst.Parent.Parent == null); - - // If we got a pipeline variable, generate the appropriate style of pipeline. - if ((!isInGeneratedPipeline) && (isIterativePipeline || processedPipelineVariable)) - { - bool savedSymbolGeneration = this.disableSymbolGeneration; - - try - { - GenerateSymbolicInformation(pipelineAst.Extent); - this.disableSymbolGeneration = true; - - // This is an iterative pipeline - if (isIterativePipeline) - { - if (isVisitingIterativePipeline) - { - ReportError("CannotNestIterativePipeline", ActivityResources.CannotNestIterativePipeline, pipelineAst.Extent); - return null; - } - - try - { - this.isVisitingIterativePipeline = true; - GenerateIterativePipeline(prePipelineElements, iterativePipelineElements, nonIterativePipelineVariable); - } - finally - { - this.isVisitingIterativePipeline = false; - } - } - else - { - // This is a regular pipeline with a pipeline variable - GeneratePipelineVariablePipeline(pipelineAst, prePipelineElements, postPipelineElements, nonIterativePipelineVariable); - } - } - finally - { - this.disableSymbolGeneration = savedSymbolGeneration; - } - } - else - { - // We didn't get a pipeline variable at all. It's just a regular pipeline. - PipelineAst completePipeline = new PipelineAst(pipelineAst.Extent, prePipelineElements); - GeneratePipelineCall(completePipeline); - } - } - - return null; - } - - private void ValidateVariableName(string variableName, IScriptExtent errorExtent) - { - string actualVariableNameUnused; - if (!IsValidMemberName(variableName, out actualVariableNameUnused, false)) - { - // This was an error with variable scoping - if (variableName.IndexOf(':') > 0) - { - ReportError("WorkflowScopeOnlyValidInParallelOrSequenceBlock", ActivityResources.WorkflowScopeOnlyValidInParallelOrSequenceBlock, errorExtent); - } - else - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.InvalidMemberName, variableName); - ReportError("VariableNameNotValid", error, errorExtent); - } - } - } - - private void GenerateIterativePipelineElementForForEach(List iterativePipelineElements, string currentPipelineVariable, List iterativePipelineVariables, - ScriptBlockExpressionAst beginParameter, ScriptBlockExpressionAst sequenceParameter, ScriptBlockExpressionAst endParameter) - { - // Define the variable that will be used to hold the pipeline iteration count - if ((beginParameter != null) || (endParameter != null)) - { - VariableDefinition pipelineIteration = GetVariableDefinition("PSPipelineIteration"); - if (pipelineIteration == null) - { - DefineVariable("PSPipelineIteration", typeof(Int32), null, "0"); - } - - VariableDefinition pipelineCount = GetVariableDefinition("PSPipelineLength"); - if (pipelineIteration == null) - { - DefineVariable("PSPipelineLength", typeof(Int32), null, "0"); - } - } - - StringBuilder iterativePipelineElement = new StringBuilder(); - - // Set up start of foreach loop to go over all output collected so far - iterativePipelineElement.AppendLine("$PSPipelineIteration = 0"); - SetUpIterativePipelineLoop(iterativePipelineElement, iterativePipelineVariables); - - // If they specified "-Begin {}", then generate the script to invoke that code before repeated invocation of the -Sequence {} - if (beginParameter != null) - { - iterativePipelineElement.AppendLine(" if($PSPipelineIteration -eq 0)"); - iterativePipelineElement.AppendLine(" {"); - iterativePipelineElement.AppendLine(" [System.Management.Automation.PSDataCollection[PSObject]] $PSSequenceOutput = $null"); - iterativePipelineElement.AppendLine(" $PSSequenceOutput = sequence " + beginParameter.Extent.Text); - - // Handle PSSequenceOutput output - HandlePSSequenceOutput(iterativePipelineElement, currentPipelineVariable); - - iterativePipelineElement.AppendLine(" }"); - } - - // Now take all the output from invoking the -Sequence {} portion, and create new context frames to hold - // the output. These get stored in PSPipelineVariableContext by the foreach loop above. - iterativePipelineElement.AppendLine(" [System.Management.Automation.PSDataCollection[PSObject]] $PSSequenceOutput = $null"); - iterativePipelineElement.AppendLine(" $PSSequenceOutput = sequence " + sequenceParameter.Extent.Text); - - // Handle PSSequenceOutput output - HandlePSSequenceOutput(iterativePipelineElement, currentPipelineVariable); - - // If they specified "-End {}", then generate the script to invoke that code after repeated invocation of the -Sequence {} - if (endParameter != null) - { - iterativePipelineElement.AppendLine(" if($PSPipelineIteration -eq ($PSPipelineLength- 1))"); - iterativePipelineElement.AppendLine(" {"); - iterativePipelineElement.AppendLine(" [System.Management.Automation.PSDataCollection[PSObject]] $PSSequenceOutput = $null"); - iterativePipelineElement.AppendLine(" $PSSequenceOutput = sequence " + endParameter.Extent.Text); - - // Handle PSSequenceOutput output - HandlePSSequenceOutput(iterativePipelineElement, currentPipelineVariable); - - iterativePipelineElement.AppendLine(" }"); - } - - // Finish iterative pipeline loop. - FinishIterativePipelineLoop(iterativePipelineElement, iterativePipelineVariables, true); - - // Parse the iterative pipeline element and update the pipeline elements list. - ParseAndUpdatePipelineElements(iterativePipelineElement, iterativePipelineElements); - } - - private void GenerateIterativePipelineElementForWhere(List iterativePipelineElements, string currentPipelineVariable, List iterativePipelineVariables, - ScriptBlockExpressionAst sequenceParameter) - { - StringBuilder iterativePipelineElement = new StringBuilder(); - - // Set up start of foreach loop to go over all output collected so far - SetUpIterativePipelineLoop(iterativePipelineElement, iterativePipelineVariables); - - // Generate output with the Where-Object command and provided sequence script block. - iterativePipelineElement.AppendLine(" [System.Management.Automation.PSDataCollection[PSObject]] $PSSequenceOutput = $null"); - iterativePipelineElement.AppendLine(" $PSSequenceOutput = Where-Object -InputObject $PSItem -FilterScript " + sequenceParameter.Extent.Text); - - // Handle PSSequenceOutput output - HandlePSSequenceOutput(iterativePipelineElement, currentPipelineVariable); - - // Finish the iterative pipeline loop. - FinishIterativePipelineLoop(iterativePipelineElement, iterativePipelineVariables, false); - - // Parse the iterative pipeline element and update the pipeline elements list. - ParseAndUpdatePipelineElements(iterativePipelineElement, iterativePipelineElements); - } - - private void SetUpIterativePipelineLoop(StringBuilder iterativePipelineElement, List iterativePipelineVariables) - { - // Use a foreach loop to go over all output collected so far - iterativePipelineElement.AppendLine("$PSPipelineLength = @($PSPipelineVariableContext).Count"); - iterativePipelineElement.AppendLine("$PSPipelineVariableContext = foreach($PSPipelineItem in $PSPipelineVariableContext)"); - iterativePipelineElement.AppendLine("{"); - iterativePipelineElement.AppendLine(" $PSItem = $PSPipelineItem['_']"); - - // Create virtual variables that represent the variables used in the iterative pipeline, with - // their values taken from the context frame (PSPipelineItem). - foreach (string previousPipelineVariable in iterativePipelineVariables) - { - iterativePipelineElement.AppendLine(" $" + previousPipelineVariable + " = $PSPipelineItem['" + previousPipelineVariable + "']"); - } - } - - private void HandlePSSequenceOutput(StringBuilder iterativePipelineElement, string currentPipelineVariable) - { - // Take all the output from invoking -Sequence {} portion and create new context frames to hold - // the output. These are stored in PSPipelineVariableContext by the foreach loop above. - iterativePipelineElement.AppendLine(" foreach($output in $PSSequenceOutput)"); - iterativePipelineElement.AppendLine(" {"); - iterativePipelineElement.AppendLine(" PowerShellValue[Object] -Expression '"); - iterativePipelineElement.AppendLine(" $PSPipelineItem = $PSPipelineItem.Clone();"); - iterativePipelineElement.AppendLine(" $PSPipelineItem[\"_\"] = $output;"); - iterativePipelineElement.AppendLine(" $PSPipelineItem[\"" + currentPipelineVariable + "\"] = $output;"); - iterativePipelineElement.AppendLine(" $PSPipelineItem'"); - iterativePipelineElement.AppendLine(" }"); - } - - private void FinishIterativePipelineLoop(StringBuilder iterativePipelineElement, List iterativePipelineVariables, bool incrementIterationCount) - { - // Clean out the iterative pipeline variables so that they don't have values when the iteration - // completes - foreach (string previousPipelineVariable in iterativePipelineVariables) - { - iterativePipelineElement.AppendLine(" $" + previousPipelineVariable + " = $null"); - } - - // Finish script. - if (incrementIterationCount) - { - iterativePipelineElement.AppendLine(" $PSPipelineIteration = $PSPipelineIteration + 1"); - } - iterativePipelineElement.AppendLine("}"); - } - - private void ParseAndUpdatePipelineElements(StringBuilder iterativePipelineElement, List iterativePipelineElements) - { - // We can't use the parse errors, since the parser thinks we are using workflow constructs - // ("sequence") outside of a workflow context. We're only injecting validated pipeline variable names - // and already-parsed text, so that is OK. - Token[] unusedTokens = null; - ParseError[] unusedParseErrors = null; - Ast pipelineElementAst = Parser.ParseInput(iterativePipelineElement.ToString(), out unusedTokens, out unusedParseErrors); - - iterativePipelineElements.AddRange((((ScriptBlockAst)pipelineElementAst).EndBlock.Statements)); - } - - private static bool GetArgumentAndExtentForParameter(string key, ref string pipelineVariable, - StaticBindingResult parameters, ref IScriptExtent errorExtent) - { - if (parameters.BoundParameters.ContainsKey(key)) - { - ParameterBindingResult argument = parameters.BoundParameters[key]; - string stringConstantValue = argument.ConstantValue as string; - - if (stringConstantValue != null) - { - pipelineVariable = stringConstantValue; - } - else - { - pipelineVariable = argument.Value.Extent.Text; - } - - errorExtent = argument.Value.Extent; - return true; - } - - return false; - } - - private void GenerateIterativePipeline(List prePipelineElements, List bodyElements, string pipelineVariable) - { - // Define the context variable that will be used to hold context frames - VariableDefinition pipelineVariableContext = GetVariableDefinition("PSPipelineVariableContext"); - if (pipelineVariableContext == null) - { - DefineVariable("PSPipelineVariableContext", typeof(PSDataCollection), null, null); - } - - // Generate the pipeline initializer - string conditionExtent = ""; - foreach (var element in prePipelineElements) - { - if (!String.IsNullOrEmpty(conditionExtent)) - { - conditionExtent += " | "; - } - - conditionExtent += element.Extent.Text; - } - - StringBuilder iterativePipelineElement = new StringBuilder(); - iterativePipelineElement.AppendLine("[System.Management.Automation.PSDataCollection[PSObject]] $PSPipelineVariableContext = @( @{} )"); - - iterativePipelineElement.AppendLine("[System.Management.Automation.PSDataCollection[PSObject]] $PSSequenceOutput = $null"); - iterativePipelineElement.AppendLine("$PSSequenceOutput = " + conditionExtent); - iterativePipelineElement.AppendLine("$PSPipelineVariableContext = foreach($output in $PSSequenceOutput)"); - iterativePipelineElement.AppendLine("{"); - iterativePipelineElement.AppendLine(" PowerShellValue[Object] -Expression '"); - iterativePipelineElement.AppendLine(" $PSPipelineItem = @{};"); - iterativePipelineElement.AppendLine(" $PSPipelineItem[\"_\"] = $output;"); - iterativePipelineElement.AppendLine(" $PSPipelineItem[\"" + pipelineVariable + "\"] = $output;"); - iterativePipelineElement.AppendLine(" $PSPipelineItem'"); - iterativePipelineElement.AppendLine("}"); - - // We can't use the parse errors, since the parser thinks we are using workflow constructs - // ("sequence") outside of a workflow context. We're only injecting validated pipeline variable names - // and already-parsed text, so that is OK. - Token[] unusedTokens = null; - ParseError[] unusedParseErrors = null; - ScriptBlockAst pipelineElementAst = (ScriptBlockAst) Parser.ParseInput(iterativePipelineElement.ToString(), out unusedTokens, out unusedParseErrors); - - foreach (StatementAst statement in pipelineElementAst.EndBlock.Statements) - { - statement.Visit(this); - } - - foreach (Ast bodyElement in bodyElements) - { - bodyElement.Visit(this); - } - } - - private void GeneratePipelineVariablePipeline(PipelineAst pipelineAst, List prePipelineElements, List bodyElements, string pipelineVariable) - { - // If there's a storage variable, it now needs to become an aggregating variable - var storageVariable = GetVariableToUse(); - if (storageVariable != null) - { - storageVariable.IsAggregatingVariable = true; - } - - Token[] unusedTokens = null; - ParseError[] unusedParseErrors = null; - - // Generate the extent for the variable in the foreach - string extentText = "$" + pipelineVariable; - Ast newAst = Parser.ParseInput(extentText, out unusedTokens, out unusedParseErrors); - IScriptExtent variableExtent = newAst.Extent; - - newAst = Parser.ParseInput(extentText, out unusedTokens, out unusedParseErrors); - IScriptExtent foreachBodyExtent = newAst.Extent; - - List foreachBody = new List(); - foreach (StatementAst bodyElement in bodyElements) - { - foreachBody.Add((StatementAst) bodyElement.Copy()); - } - - // Generate the AST and extent for the foreach condition - string conditionExtent = ""; - foreach (var element in prePipelineElements) - { - if (!String.IsNullOrEmpty(conditionExtent)) - { - conditionExtent += " | "; - } - - conditionExtent += element.Extent.Text; - } - newAst = Parser.ParseInput(conditionExtent, out unusedTokens, out unusedParseErrors); - IScriptExtent foreachConditionExtent = newAst.Extent; - - // Generate the actual foreach AST, and visit it. - ForEachStatementAst foreachStatement = new ForEachStatementAst(pipelineAst.Extent, null, ForEachFlags.None, - new VariableExpressionAst(variableExtent, pipelineVariable, false), - new PipelineAst(foreachConditionExtent, prePipelineElements), - new StatementBlockAst(foreachBodyExtent, foreachBody, null)); - foreachStatement.Visit(this); - } - - private void GeneratePipelineVariablePipeline(PipelineAst pipelineAst, List prePipelineElements, List postPipelineElements, string pipelineVariable) - { - Token[] unusedTokens = null; - ParseError[] unusedParseErrors = null; - - // Generate the extent for the variable in the foreach - string extentText = "$" + pipelineVariable; - Ast newAst = Parser.ParseInput(extentText, out unusedTokens, out unusedParseErrors); - IScriptExtent variableExtent = newAst.Extent; - - // Generate the AST and extent for the foreach body - VariableExpressionAst expressionAst = new VariableExpressionAst(variableExtent, pipelineVariable, false); - CommandExpressionAst commandExpression = new CommandExpressionAst(variableExtent, expressionAst, null); - - foreach (var element in postPipelineElements) - { - extentText += " | " + element.Extent.Text; - } - - postPipelineElements.Insert(0, commandExpression); - - newAst = Parser.ParseInput(extentText, out unusedTokens, out unusedParseErrors); - IScriptExtent foreachBodyExtent = newAst.Extent; - - List bodyStatements = ((ScriptBlockAst)newAst).EndBlock.Statements.ToList(); - GeneratePipelineVariablePipeline(pipelineAst, prePipelineElements, bodyStatements, pipelineVariable); - } - - private void GeneratePipelineCall(PipelineAst pipelineAst) - { - GenerateSymbolicInformation(pipelineAst.Extent); - - // Create an assembly name reference - string friendlyName = GetFriendlyName(null, typeof(Pipeline)); - string typeArguments = GetConvertedTypeName(typeof(PSDataCollection)); - - // Generate the call to the activity - var currentVariable = GetVariableToUse(); - string variableToUse = null; - bool isAggregatingVariable = false; - if (currentVariable != null) - { - variableToUse = currentVariable.VariableName; - isAggregatingVariable = currentVariable.IsAggregatingVariable; - } - - if (string.IsNullOrEmpty(variableToUse)) - { - WriteLine("<" + friendlyName + ">"); - } - else - { - string appendOutput = isAggregatingVariable ? AppendOutputTemplate : string.Empty; - string pipelineCall = String.Format(CultureInfo.InvariantCulture, "<{0} Result=\"[{1}]\"{2}>", friendlyName, variableToUse, appendOutput); - WriteLine(pipelineCall); - } - - IndentLevel(); - WriteLine("<" + friendlyName + ".Activities>"); - IndentLevel(); - - bool savedSymbolGeneration = this.disableSymbolGeneration; - Stack savedStorage = this.resultVariables; - try - { - this.disableSymbolGeneration = true; - this.resultVariables = null; - this.isVisitingPipeline = true; - - foreach (CommandBaseAst pipelineElement in pipelineAst.PipelineElements) - { - pipelineElement.Visit(this); - } - } - finally - { - this.isVisitingPipeline = false; - this.disableSymbolGeneration = savedSymbolGeneration; - this.resultVariables = savedStorage; - } - - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(""); - } - - object ICustomAstVisitor.VisitFileRedirection(FileRedirectionAst fileRedirectionAst) - { - ReportError("OnlySupportErrorStreamRedirection", ActivityResources.OnlySupportErrorStreamRedirection, fileRedirectionAst.Extent); - return null; - } - - object ICustomAstVisitor.VisitMergingRedirection(MergingRedirectionAst mergingRedirectionAst) - { - if (mergingRedirectionAst.FromStream != RedirectionStream.Error || - mergingRedirectionAst.ToStream != RedirectionStream.Output) - { - ReportError("OnlySupportErrorStreamRedirection", ActivityResources.OnlySupportErrorStreamRedirection, mergingRedirectionAst.Extent); - } - - return null; - } - - object ICustomAstVisitor.VisitBinaryExpression(BinaryExpressionAst binaryExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitUnaryExpression(UnaryExpressionAst unaryExpressionAst) - { - VariableExpressionAst referenceVariable = unaryExpressionAst.Child as VariableExpressionAst; - string expression = GetPowerShellValueExpression(unaryExpressionAst); - - switch (unaryExpressionAst.TokenKind) - { - case TokenKind.PlusPlus: - case TokenKind.MinusMinus: - case TokenKind.PostfixPlusPlus: - case TokenKind.PostfixMinusMinus: - if (referenceVariable != null) - { - string variableName = referenceVariable.VariablePath.ToString(); - GenerateAssignment(variableName, unaryExpressionAst.Extent, unaryExpressionAst.TokenKind, unaryExpressionAst, expression); - } - else - { - ReportError("OperatorRequiresVariable", ActivityResources.OperatorRequiresVariable, unaryExpressionAst.Extent); - } - - break; - case TokenKind.Minus: - case TokenKind.Plus: - case TokenKind.Not: - case TokenKind.Bnot: - case TokenKind.Exclaim: - case TokenKind.Comma: - case TokenKind.Csplit: - case TokenKind.Isplit: - case TokenKind.Join: - var currentVariable = GetVariableToUse(); - string variableToUse = null; - bool isAggregatingVariable = false; - if (currentVariable != null) - { - variableToUse = currentVariable.VariableName; - isAggregatingVariable = currentVariable.IsAggregatingVariable; - } - - string writeOutputFriendlyName = GetFriendlyName(null, typeof(Microsoft.PowerShell.Utility.Activities.WriteOutput)); - bool needWriteOutput = isAggregatingVariable || String.IsNullOrEmpty(variableToUse); - Type variableType = null; - - if (needWriteOutput) - { - variableType = typeof(PSObject[]); - GenerateWriteOutputStart(writeOutputFriendlyName, variableToUse, unaryExpressionAst.Extent); - } - else - { - variableType = GetVariableDefinition(variableToUse).Type; - } - - // Evaluate the expression - GeneratePowerShellValue(variableType, expression, false, true); - - if (needWriteOutput) - { - GenerateWriteOutputEnd(writeOutputFriendlyName); - } - - break; - default: - throw new NotSupportedException(); - } - - return null; - } - - object ICustomAstVisitor.VisitConvertExpression(ConvertExpressionAst convertExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitConstantExpression(ConstantExpressionAst constantExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitStringConstantExpression(StringConstantExpressionAst stringConstantExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitSubExpression(SubExpressionAst subExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitUsingExpression(UsingExpressionAst usingExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitCommand(CommandAst commandAst) - { - if (commandAst.InvocationOperator != TokenKind.Unknown) - { - ReportError("AlternateInvocationNotSupported", ActivityResources.AlternateInvocationNotSupported, commandAst.Extent); - } - - if (commandAst.Redirections.Count > 0) - { - foreach (RedirectionAst redirection in commandAst.Redirections) - { - redirection.Visit(this); - } - - this.mergeErrorToOutput = true; - } - - try - { - string commandName = commandAst.GetCommandName(); - CommandInfo command = null; - - bool searchSessionState = !this.ValidateOnly; - ActivityKind activityKind = ResolveActivityKindBasedOnCommandName(commandName, commandAst, out command, searchSessionState); - - switch (activityKind) - { - case ActivityKind.InlineScript: - ProcessInlineScriptAst(commandAst); - return null; - - case ActivityKind.Persist: - GeneratePersist(commandAst); - return null; - - case ActivityKind.Suspend: - GenerateSuspend(commandAst); - return null; - - case ActivityKind.InvokeExpression: - GenerateInvokeExpression(commandAst); - return null; - - case ActivityKind.Delay: - if (this.mergeErrorToOutput) - { - ReportError("CannotRedirectErrorStreamForStartSleep", - ActivityResources.CannotRedirectErrorStreamForStartSleep, - commandAst.Redirections[0].Extent); - } - - GenerateStartSleep(commandAst); - return null; - - case ActivityKind.NewObject: - if (this.mergeErrorToOutput) - { - ReportError("CannotRedirectErrorStreamForNewObject", - ActivityResources.CannotRedirectErrorStreamForNewObject, - commandAst.Redirections[0].Extent); - } - - if (GetVariableToUse() == null) - { - ReportError("NewObjectMustBeAssigned", - ActivityResources.NewObjectMustBeAssigned, - commandAst.Extent); - } - - GenerateNewObject(commandAst); - return null; - - case ActivityKind.RegularCommand: - - // If the command resolved to a workflow, generate that as a nested workflow - if ((command != null) && (command.CommandType == CommandTypes.Workflow)) - { - WorkflowInfo nestedWorkflow = (WorkflowInfo)command; - CreateNestedWorkflow(nestedWorkflow, commandAst, commandAst.Extent); - } - - GenerateCommandCall(commandAst, command); - return null; - - default: - // Should not get to default - break; - } - } - finally - { - this.mergeErrorToOutput = false; - } - - throw new NotSupportedException(); - } - - private void GenerateCommandCall(CommandAst commandAst, CommandInfo command) - { - string commandName = commandAst.GetCommandName(); - - var scopeEntry = scope.LookupCommand(commandName); - - // If the named command maps to a function with workflow binding, then we process that - // function, and create a "workflow calling workflow" scenario.) - if (scopeEntry != null) - { - if (scopeEntry.workflowInfo != null) - { - IScriptExtent extent = null; - if(scopeEntry.functionDefinition != null) - { - extent = scopeEntry.functionDefinition.Extent; - } - CreateNestedWorkflow(scopeEntry.workflowInfo, commandAst, extent); - GenerateWorkflowCallingWorkflowCall(commandAst, scopeEntry.workflowInfo.NestedXamlDefinition, command); - } - else - { - // If the named command maps to a regular PowerShell function, then we compile - // to an inline script. - // If we're in a pipeline, generate an error. The InlineScript wrapper we generate for these - // is not capable of passing along input. - if (this.isVisitingPipeline) - { - ReportError("ActivityNotSupportedInPipeline", - String.Format(CultureInfo.InvariantCulture, ActivityResources.ActivityNotSupportedInPipeline, commandName), commandAst.Extent); - } - - // Although the function may be defined separately from the invocation, - // we generate the InlineScript of: - // function foo($bar) { ... }; foo "Test" - string functionDefinition = scopeEntry.functionDefinition.Extent.Text; - GenerateInlineScriptForFunctionCall(null, functionDefinition, commandAst); - } - } - else if ((command != null) && - (command.CommandType == CommandTypes.Function) && - (((command.Module == null) || ((definingModule != null) && (String.Equals(command.Module.Path, definingModule.Path, StringComparison.OrdinalIgnoreCase)))))) - { - // Extract functions from the session state, as long as they are not defined in a module - // (as they probably have requirements that cannot be met). - - // If we're in a pipeline, generate an error. The InlineScript wrapper we generate for these - // is not capable of passing along input. - if (this.isVisitingPipeline) - { - ReportError("ActivityNotSupportedInPipeline", - String.Format(CultureInfo.InvariantCulture, ActivityResources.ActivityNotSupportedInPipeline, commandName), commandAst.Extent); - } - - GenerateInlineScriptForFunctionCall(command.Name, command.Definition, commandAst); - } - else - { - // Skip this expensive step during the parse phase - if (!this.ValidateOnly) - { - // If the command maps to an activity, then we compile it into that activity - bool activityFound = GenerateActivityCallFromCommand(commandName, commandAst); - if (!activityFound) - { - GenerateNativeCommandCallFromCommand(commandName, commandAst); - } - } - } - } - - private void GenerateWorkflowCallingWorkflowCall(CommandAst commandAst, string xaml, CommandInfo command) - { - DynamicActivity result; - using (StringReader xamlReader = new StringReader(xaml)) - { - result = (DynamicActivity)System.Activities.XamlIntegration.ActivityXamlServices.Load(xamlReader); - } - - ProcessAssembly(result.GetType().Assembly, processedActivityLibraries, activityMap); - - StaticBindingResult bindingResult = StaticParameterBinder.BindCommand(commandAst, false); - Dictionary convertedParameters = ResolveParameters(bindingResult); - - // If we are calling a nested workflow and are also storing the result, we need to create - // a new instance of the storage variable. - var currentVariable = GetVariableToUse(); - string storageVariable = null; - bool isAggregatingVariable = false; - if (currentVariable != null) - { - storageVariable = currentVariable.VariableName; - isAggregatingVariable = currentVariable.IsAggregatingVariable; - } - - if (!String.IsNullOrEmpty(storageVariable) && !isAggregatingVariable) - { - string constructor = "New-Object -Type System.Management.Automation.PSDataCollection[PSObject]"; - GeneratePowerShellValue(typeof(System.Management.Automation.PSDataCollection), constructor, false, true); - } - - // Create Inline Script for parameter validation of the inner workflow. - string paramBlock = GetWorkflowParamBlock(command); - - bool inlineScriptGenerated = false; - if (!string.IsNullOrEmpty(paramBlock)) - { - StringBuilder actualParamBlock = AddAdditionalWorkflowParameters(paramBlock); - - // Add inline script parameters to ensure that validation is run locally - Dictionary inlineScriptParameters = new Dictionary(StringComparer.OrdinalIgnoreCase); - inlineScriptParameters.Add("PSComputerName", new CommandArgumentInfo { Value = "$null" }); - - // Generate Inline Script - GenerateInlineScriptForFunctionCall(command.Name, inlineScriptParameters, actualParamBlock.ToString(), commandAst); - inlineScriptGenerated = true; - } - - // Prevent symbols for this workflow call from being added twice. - bool prevDisableSymbolGeneration = this.disableSymbolGeneration; - try - { - this.disableSymbolGeneration = inlineScriptGenerated || this.disableSymbolGeneration; - GenerateActivityCall(null, result.Name, result.GetType(), result, convertedParameters, bindingResult, null, commandAst.Extent); - } - finally - { - this.disableSymbolGeneration = prevDisableSymbolGeneration; - } - } - - private static StringBuilder AddAdditionalWorkflowParameters(string paramBlock) - { - const string additionalParameters = - @" - , - [System.Collections.ArrayList] $Result, - [System.Collections.ArrayList] $PSError, - [System.Collections.ArrayList] $PSProgress, - [System.Collections.ArrayList] $PSVerbose, - [System.Collections.ArrayList] $PSDebug, - [System.Collections.ArrayList] $PSWarning, - [System.Collections.ArrayList] $PSInformation, - [Nullable[uint32]] $PSActionRetryCount, - [bool] $PSDisableSerialization, - [NUllable[uint32]] $PSActionRunningTimeoutSec, - [NUllable[uint32]] $PSActionRetryIntervalSec, - [string[]] $PSRequiredModules"; - - // Remove the ")" from the end - string newParamBlock = paramBlock.Substring(0, paramBlock.Length - 2); - - StringBuilder actualParamBlock = new StringBuilder(); - actualParamBlock.Append(newParamBlock); - actualParamBlock.Append(additionalParameters); - - // Add the ")" at the end - actualParamBlock.Append("\n)"); - - return actualParamBlock; - } - - private string GetWorkflowParamBlock(CommandInfo command) - { - var paramBlock = string.Empty; - if (command != null) - { - WorkflowInfo workflowInfo = (WorkflowInfo)command; - ScriptBlockAst sb; - if (workflowInfo.ScriptBlock != null) - { - sb = workflowInfo.ScriptBlock.Ast as ScriptBlockAst; - if (sb != null) - { - if (sb.BeginBlock != null && sb.BeginBlock.Statements != null && - sb.BeginBlock.Statements.Count > 0) - { - FunctionDefinitionAst functionAst = sb.BeginBlock.Statements[0] as FunctionDefinitionAst; - if (functionAst != null) - { - if (functionAst.Body != null && functionAst.Body.ParamBlock != null) - { - paramBlock = functionAst.Body.ParamBlock.ToString(); - } - } - } - } - } - } - return paramBlock; - } - - private void GenerateInlineScriptForFunctionCall(string name, Dictionary parameters, string definition, CommandAst commandAst) - { - // We add a trap / break so that the InlineScript actually generates an exception when a terminating - // error happens. - string inlineScript = "trap { break }\r\n"; - string functionCall = AddUsingPrefixToWorkflowVariablesForFunctionCall(commandAst); - - if (!String.IsNullOrEmpty(name)) - { - inlineScript += String.Format( - CultureInfo.InvariantCulture, - "function {0}\r\n{{\r\n{1}\r\n}}\r\n", - name, definition); - } - else - { - inlineScript += definition + "\r\n"; - } - - // Use the function name as the display name of the InlineScript activity - string displayName = name ?? commandAst.GetCommandName(); - - inlineScript += functionCall; - GenerateInlineScript(inlineScript, displayName, parameters, commandAst.Extent, false); - } - - private void GenerateInlineScriptForFunctionCall(string name, string definition, CommandAst commandAst) - { - GenerateInlineScriptForFunctionCall(name, null, definition, commandAst); - } - - // Get all variable expressions, sort them and return - private static IEnumerable GetVariableExpressionAsts(CommandAst command) - { - var list = command.FindAll(ast => ast is VariableExpressionAst, searchNestedScriptBlocks: true).ToList(); - if (list.Count > 1) - { - return list.OrderBy(a => a.Extent.StartOffset); - } - return list; - } - - private static string AddUsingPrefixToWorkflowVariablesForFunctionCall(CommandAst command) - { - string functionCall = command.Extent.Text; - IEnumerable variableExprs = GetVariableExpressionAsts(command); - if (!variableExprs.Any()) { return functionCall; } - - StringBuilder newFunctionCall = null; - int baseOffset = command.Extent.StartOffset; - int commandTextRelativeStartOffset = 0; - - foreach (Ast ast in variableExprs) - { - var variableExpr = ast as VariableExpressionAst; - if (variableExpr == null) { continue; } - if (IsVariableFromUsingExpression(variableExpr, topParent: command)) { continue; } - if (variableExpr.IsConstantVariable()) { continue; } - - string varName = variableExpr.VariablePath.UserPath; - if (varName.IndexOf(':') >= 0) - { - if (varName.StartsWith("WORKFLOW:", StringComparison.OrdinalIgnoreCase)) - { - // If the variable has a 'workflow' scope prefix, we always add 'using' prefix to it - varName = varName.Remove(0, "WORKFLOW:".Length); - } - else - { - continue; // Something like $env:PSModulePath - } - } - else - { - // We add 'using' prefix to all other variables except $input. - // $input doesn't need the 'using' prefix to work within an InlineScript: - // PS\> workflow bar { 1..2 | inlinescript { $input } } - // PS\> bar - // 1 - // 2 - if (String.Equals(varName, "Input", StringComparison.OrdinalIgnoreCase)) - { - continue; - } - } - - // Check if we need to include the using variable in a parenthesis - bool needParen = false; - var indexExprParent = variableExpr.Parent as IndexExpressionAst; - if (indexExprParent != null && indexExprParent.Target == variableExpr) - { - needParen = true; - } - else - { - var memberExprParent = variableExpr.Parent as MemberExpressionAst; - if (memberExprParent != null && memberExprParent.Expression == variableExpr) - { - needParen = true; - } - } - - // We need to alter the function call script by this point - if (newFunctionCall == null) - { - newFunctionCall = new StringBuilder(); - } - - string newVarName = (variableExpr.Splatted ? "@" : "$") + "using:" + varName; - newVarName = needParen ? "(" + newVarName + ")" : newVarName; - int variableRelativeStartOffset = variableExpr.Extent.StartOffset - baseOffset; - int variableRelativeEndOffset = variableExpr.Extent.EndOffset - baseOffset; - - newFunctionCall.Append(functionCall.Substring(commandTextRelativeStartOffset, variableRelativeStartOffset - commandTextRelativeStartOffset)); - newFunctionCall.Append(newVarName); - commandTextRelativeStartOffset = variableRelativeEndOffset; - } - - if (newFunctionCall != null) - { - newFunctionCall.Append(functionCall.Substring(commandTextRelativeStartOffset)); - return newFunctionCall.ToString(); - } - - return functionCall; - } - - private static bool IsVariableFromUsingExpression(VariableExpressionAst variableExpr, Ast topParent) - { - var parent = variableExpr.Parent; - while (parent != topParent) - { - if (parent is UsingExpressionAst) - { - return true; - } - parent = parent.Parent; - } - return false; - } - - private void GenerateNativeCommandCallFromCommand(string commandName, CommandAst commandAst) - { - // If it parses like a command but isn't a regular PowerShell command, then - // it's likely a native command. Convert this into an InlineScript call, since - // we can't do anything intelligent about parameter parsing. - // Use the command name as the display name of the InlineScript activity. - string inlineScript = AddUsingPrefixToWorkflowVariablesForFunctionCall(commandAst); - GenerateInlineScript(inlineScript, commandName, null, commandAst.Extent, false); - } - - // If the named command is in any of the referenced DLLs, then we call it as an activity. - // If the adjusted named command (i.e.: Get-Process -> GetProcessActivity) is in any of the - // referenced DLLs, then we call it as an activity. - private bool GenerateActivityCallFromCommand(string commandName, CommandAst commandAst) - { - CommandInfo resolvedCommand; - Type[] genericTypes; - - // Find the activity for this name - Type activityType = ResolveActivityType(commandName, commandAst, true, out resolvedCommand, out genericTypes); - - // If this didn't map to a specific command, generate an error that tells the user to use an - // InlineScript - if ((activityType == null) && (resolvedCommand == null)) - { - // Do not report this error at validation time, as it will only ever work - // at run-time. - if (!ValidateOnly) - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.CommandNotFound, commandName); - ReportError("CommandNotFound", error, commandAst.Extent); - } - } - - if (activityType == null) { return false; } - - // Get the parameters used - StaticBindingResult syntacticResult = StaticParameterBinder.BindCommand(commandAst, false); - StaticBindingResult bindingResult = StaticParameterBinder.BindCommand(commandAst, true); - - // See if there are any errors to report - if (bindingResult.BindingExceptions != null) - { - foreach(KeyValuePair bindingException in bindingResult.BindingExceptions) - { - if (String.Equals("ParameterAlreadyBound", - bindingException.Value.BindingException.ErrorId, StringComparison.OrdinalIgnoreCase)) - { - // throw Duplicate parameters error - ReportError("DuplicateParametersNotAllowed", - string.Format(CultureInfo.CurrentCulture, ActivityResources.DuplicateParametersNotAllowed, bindingException.Key), - bindingException.Value.CommandElement.Extent); - } - else if (String.Equals("NamedParameterNotFound", - bindingException.Value.BindingException.ErrorId, StringComparison.OrdinalIgnoreCase)) - { - // Skip for now, handled during activity generation. - } - else - { - // throw the other error - ReportError( - bindingException.Value.BindingException.ErrorId, - bindingException.Value.BindingException.Message, - bindingException.Value.CommandElement.Extent); - } - } - } - - Dictionary convertedParameters = ResolveParameters(bindingResult); - - if (genericTypes != null && genericTypes.Length > 0) - { - var genericTypeArg = new CommandArgumentInfo() {Value = genericTypes}; - convertedParameters.Add(GenericTypesKey, genericTypeArg); - } - - GenerateActivityCall(resolvedCommand, null, activityType, null, convertedParameters, bindingResult, syntacticResult, commandAst.Extent); - return true; - } - - /// - /// Resolve the activity type based on the given command name - /// - /// - /// - /// Indicate the error action - /// The CommandInfo instance resolved from the command name - /// If it is a generic activity, genericTypes contains the actual types in the order they get declared - /// - internal Type ResolveActivityType(string commandName, CommandAst commandAst, bool throwError, out CommandInfo resolvedCommand, out Type[] genericTypes) - { - genericTypes = null; - - int index = commandName.IndexOf('['); - if (index != -1 && commandName.EndsWith("]", StringComparison.Ordinal)) - { - string typeNames = commandName.Substring(index + 1, commandName.Length - index - 2); - commandName = commandName.Substring(0, index).Trim(); - genericTypes = ResolveGenericTypes(typeNames, commandAst.CommandElements[0]); - } - - // Resolve the command - resolvedCommand = ResolveCommand(commandName); - commandName = resolvedCommand != null ? resolvedCommand.Name : commandName; - - // Replace any dashes, and search for activities that match. - string searchName = commandName.Replace("-", ""); - - // Verify it isn't a built-in command - CommandInfo unused = null; - - bool searchSessionState = !this.ValidateOnly; - ActivityKind activityKind = ResolveActivityKindBasedOnCommandName(searchName, commandAst, out unused, searchSessionState); - if (activityKind != ActivityKind.RegularCommand) - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.CommandHandledByKeyword, commandName, searchName); - ReportError("CommandHandledByKeyword", error, commandAst.Extent); - } - - if (genericTypes != null && genericTypes.Length > 0) - { - searchName += String.Format(CultureInfo.InvariantCulture, "`{0}", genericTypes.Length); - } - - if (!activityMap.ContainsKey(searchName)) - { - if ((resolvedCommand != null) && (resolvedCommand.CommandType != CommandTypes.Application)) - { - // Check if it was explicitly excluded. - // - We check for null module names, as this may have come from an activity in SMA (which is a snapin). - // - We check for Microsoft.PowerShell.Host, as that module has only two commands (that are not intended to be activities). - // - We check to see if this command comes from a module that has defined activities for OTHER commands. - string moduleName = resolvedCommand.ModuleName; - if ((String.IsNullOrEmpty(moduleName) || - String.Equals("Microsoft.PowerShell.Host", moduleName, StringComparison.OrdinalIgnoreCase) || - String.Equals("CimCmdlets", moduleName, StringComparison.OrdinalIgnoreCase) || - processedActivityLibraries.Contains(moduleName)) && throwError) - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.CommandActivityExcluded, commandName); - ReportError("CommandActivityExcluded", error, commandAst.Extent); - } - } - - return null; - } - - // Find the activity for this name - Type activityType = activityMap[searchName]; - - // The name was cached, but the type is null. That means the command name - // is ambiguous. - if (activityType == null && throwError) - { - String errorMessage = String.Format(CultureInfo.InvariantCulture, - ActivityResources.AmbiguousCommand, - commandName); - ReportError("AmbiguousCommand", errorMessage, commandAst.Extent); - } - - return activityType; - } - - private Type[] ResolveGenericTypes(string typeNames, Ast targetAst) - { - string[] names = typeNames.Split(','); - var result = new List(); - - foreach (string typeName in names) - { - try - { - var outputType = LanguagePrimitives.ConvertTo(typeName.Trim()); - result.Add(outputType); - } - catch (PSInvalidCastException) - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.NewObjectCouldNotFindType, typeName); - ReportError("GenericTypeNotFound", error, targetAst.Extent); - } - } - - return result.ToArray(); - } - - private void CreateNestedWorkflow(WorkflowInfo command, CommandAst commandAst, IScriptExtent extent) - { - AddWorkflowCommonParameters(command, commandAst, extent); - - // Register the conversion of the outer workflow - var entry = scope.LookupCommand(command.Name); - if (entry == null) - { - entry = new Scope.Entry { workflowInfo = command, scope = scope }; - scope.functionDefinitions.Add(command.Name, entry); - } - - nestedWorkflows.Add(command); - - foreach (var nested in command.WorkflowsCalled) - { - nestedWorkflows.Add(nested); - } - } - - private void AddWorkflowCommonParameters(WorkflowInfo workflowInfo, CommandAst commandAst, IScriptExtent extent) - { - // Verify it doesn't use any advanced validation - foreach (string parameter in workflowInfo.Parameters.Keys) - { - // Skip validation on WF-common parameters - if (parameter.StartsWith("PS", StringComparison.OrdinalIgnoreCase) || Cmdlet.CommonParameters.Contains(parameter)) - { - continue; - } - - ParameterMetadata metadata = workflowInfo.Parameters[parameter]; - foreach (Attribute validationAttribute in metadata.Attributes) - { - if ((validationAttribute is ValidateArgumentsAttribute) || - (validationAttribute is AliasAttribute)) - { - ReportError("ParameterValidationNotSupportedOnNestedWorkflows", - ActivityResources.ParameterValidationNotSupportedOnNestedWorkflows, - extent); - } - } - - } - - - if (this.ValidateOnly) { return; } - - - string xaml = workflowInfo.XamlDefinition; - string nestedXaml = workflowInfo.NestedXamlDefinition; - - // See if it's already been compiled to contain the wrapper properties. If so, just exit. - // If we haven't compiled this workflow before (or it's never been called with the - // ubiquitous parameters), then keep on processing. - if (!String.IsNullOrEmpty(nestedXaml)) - { - if (Regex.IsMatch(nestedXaml, "(]*>)")) - { - return; - } - } - - // We can only add the common parameters to workflows that don't - // depend on any others. We don't generate an error here, as these - // nested workflows can still be useful without these common parameters. - // - // Given workflow A calling B, calling C, (...), calling Z, we can only support workflow - // common parameters on Z. This is due to a technical limitation. When we analyze a workflow - // to add emulation of workflow-common parameters, the API that does this tries to resolve all - // of the activities and types in that workflow. Workflows that already call workflows (B, C,...) - // rely on a temporary DLL that we don't have access to (and can't supply to the - // API that requires it). - - if (workflowInfo.WorkflowsCalled.Count > 0) - { - workflowInfo.NestedXamlDefinition = xaml; - return; - } - - // Read the XAML into an activity builder to determine what properties the - // actual workflow has. - ActivityBuilder activityBuilder = (ActivityBuilder)XamlServices.Load( - ActivityXamlServices.CreateBuilderReader( - new XamlXmlReader( - new StringReader(xaml)))); - - HashSet existingProperties = new HashSet(StringComparer.OrdinalIgnoreCase); - for (int index = 0; index < activityBuilder.Properties.Count; index++) - { - existingProperties.Add(activityBuilder.Properties[index].Name); - } - - // Extract what parameters they used - StaticBindingResult specifiedParameters = StaticParameterBinder.BindCommand(commandAst, false); - List parameterNames = specifiedParameters.BoundParameters.Keys.ToList(); - - // See what properties are on PSRemotingActivity - PropertyInfo[] psRemotingProperties = typeof(PSRemotingActivity).GetProperties(); - bool usesPsRemotingProperties = false; - - // See if they use any PSRemoting properties - foreach (PropertyInfo property in psRemotingProperties) - { - foreach (string parameterName in parameterNames) - { - if (property.Name.StartsWith(parameterName, StringComparison.OrdinalIgnoreCase)) - { - if (! existingProperties.Contains(parameterName)) - { - usesPsRemotingProperties = true; - break; - } - } - } - - if (usesPsRemotingProperties) { break; } - } - - PropertyInfo[] propertiesToUse; - if (! usesPsRemotingProperties) - { - if (String.IsNullOrEmpty(workflowInfo.NestedXamlDefinition)) - { - workflowInfo.NestedXamlDefinition = xaml; - - // Replace the name with _Nested - workflowInfo.NestedXamlDefinition = Regex.Replace( - workflowInfo.NestedXamlDefinition, - "(]*>)", - "$1$2_Nested$3", - RegexOptions.Singleline); - - // Replace any parameter defaults - while (Regex.IsMatch(workflowInfo.NestedXamlDefinition, - "]*>", RegexOptions.Singleline)) - { - workflowInfo.NestedXamlDefinition = Regex.Replace( - workflowInfo.NestedXamlDefinition, - "(]*>)", - "$1$2_Nested$3", - RegexOptions.Singleline); - } - } - - // For nested workflows we want to be able to flow preference variables. To do this we need - // to include the Verbose, Debug, ErrorAction, WarningAction, and InformationAction parameters in the - // nested Xaml definition. - Collection properties = new Collection(); - foreach (var property in psRemotingProperties) - { - if (property.Name.Equals("Verbose", StringComparison.OrdinalIgnoreCase) || - property.Name.Equals("Debug", StringComparison.OrdinalIgnoreCase) || - property.Name.Equals("ErrorAction", StringComparison.OrdinalIgnoreCase) || - property.Name.Equals("WarningAction", StringComparison.OrdinalIgnoreCase) || - property.Name.Equals("InformationAction", StringComparison.OrdinalIgnoreCase)) - { - properties.Add(property); - } - } - - if (properties.Count > 0) - { - propertiesToUse = new PropertyInfo[properties.Count]; - properties.CopyTo(propertiesToUse, 0); - } - else - { - // If they don't use any "workflow calling workflow" common parameters, - // Just use the existing XAML - return; - } - } - else - { - propertiesToUse = psRemotingProperties; - } - - // Otherwise, crack open the XAML and create a new workflow that has all of the common - // parameters they might use. - activityBuilder.Name = activityBuilder.Name + "_Nested"; - - // Sequence to set host defaults from the incoming parameters that were auto-generated - // for the function.. - Sequence configureSequence = new Sequence() - { - Activities = { } - }; - - // Activity that holds the existing logic of the current activity - Activity existingLogic = activityBuilder.Implementation; - - // Sequence to restore values back to the host defaults that were present when - // we entered the function. Needs to be duplicated at the end of the existing logic - // and also in the catch() clause. - Sequence undoSequence = new Sequence() { Activities = { } }; - Sequence undoSequenceInCatch = new Sequence() { Activities = { } }; - - Collection savedHostDefaults = new Collection(); - - // Go through all the properties in PSRemotingActivity they use, and add them as - // virtual properties to this activity - foreach (PropertyInfo field in propertiesToUse) - { - // Don't generate wrapper properties for ones that are already defined - if (existingProperties.Contains(field.Name)) { continue; } - - // See if it's an argument - if (typeof(Argument).IsAssignableFrom(field.PropertyType)) - { - // Create a new property - DynamicActivityProperty newProperty = new DynamicActivityProperty(); - newProperty.Name = field.Name; - newProperty.Type = field.PropertyType; - activityBuilder.Properties.Add(newProperty); - - // Create a variable to hold the saved host default - savedHostDefaults.Add( - new Variable() { Name = "Saved_" + field.Name } - ); - - // Add the configuration of this property to the sequence that sets - // the host defaults. - IsArgumentSet isArgumentSetActivity = new IsArgumentSet(); - ActivityBuilder.SetPropertyReference(isArgumentSetActivity, new ActivityPropertyReference { SourceProperty = field.Name, TargetProperty = "Argument" }); - configureSequence.Activities.Add( - new If() - { - Condition = isArgumentSetActivity, - Then = new Sequence - { - Activities = { - new GetPSWorkflowData { - VariableToRetrieve = PSWorkflowRuntimeVariable.Other, - OtherVariableName = field.Name, - Result = new VisualBasic.Activities.VisualBasicReference("Saved_" + field.Name) - }, - new SetPSWorkflowData() - { - OtherVariableName = field.Name, - Value = new InArgument((System.Activities.Activity)new VisualBasic.Activities.VisualBasicValue(field.Name)) - } - } - } - } - ); - - // Add the restoration of this property to the undo sequence - isArgumentSetActivity = new IsArgumentSet(); - ActivityBuilder.SetPropertyReference(isArgumentSetActivity, new ActivityPropertyReference { SourceProperty = field.Name, TargetProperty = "Argument" }); - undoSequence.Activities.Add( - new If() - { - Condition = isArgumentSetActivity, - Then = new SetPSWorkflowData() - { - OtherVariableName = field.Name, - Value = new InArgument((System.Activities.Activity)new VisualBasic.Activities.VisualBasicValue("Saved_" + field.Name)) - } - } - ); - - // And the version in the catch block - isArgumentSetActivity = new IsArgumentSet(); - ActivityBuilder.SetPropertyReference(isArgumentSetActivity, new ActivityPropertyReference { SourceProperty = field.Name, TargetProperty = "Argument" }); - undoSequenceInCatch.Activities.Add( - new If() - { - Condition = isArgumentSetActivity, - Then = new SetPSWorkflowData() - { - OtherVariableName = field.Name, - Value = new InArgument((System.Activities.Activity)new VisualBasic.Activities.VisualBasicValue("Saved_" + field.Name)) - } - } - ); - } - } - - // Wrapper commands to save the current host settings, change them based on the parameters that have - // been passed in, and then restore them. - Sequence hostSettingWrapper = new Sequence() - { - Activities = { - new TryCatch() - { - Try = new Sequence() - { - Activities = { - configureSequence, - existingLogic, - undoSequence - } - }, - Catches = { - new Catch() - { - Action = new ActivityAction() - { - Handler = new Sequence() { - Activities = { - undoSequenceInCatch, - new Rethrow() - } - } - } - } - } - } - } - }; - - foreach (Variable savedHostDefault in savedHostDefaults) - { - hostSettingWrapper.Variables.Add(savedHostDefault); - } - - activityBuilder.Implementation = hostSettingWrapper; - - XmlWriterSettings settings = new XmlWriterSettings(); - settings.OmitXmlDeclaration = true; - settings.Indent = true; - - StringBuilder resultWriter = new StringBuilder(); - XmlWriter xmlWriter = XmlWriter.Create(resultWriter, settings); - XamlSchemaContext xamlSchemaContext = new XamlSchemaContext(); - XamlXmlWriter xamlXmlWriter = new XamlXmlWriter(xmlWriter, xamlSchemaContext); - XamlWriter xamlWriter = ActivityXamlServices.CreateBuilderWriter(xamlXmlWriter); - XamlServices.Save(xamlWriter, activityBuilder); - - workflowInfo.NestedXamlDefinition = resultWriter.ToString(); - } - - private Dictionary resolvedCommands = new Dictionary(StringComparer.OrdinalIgnoreCase); - - private CommandInfo ResolveCommand(string commandName) - { - CommandInfo resolvedCommand = null; - - if (resolvedCommands.TryGetValue(commandName, out resolvedCommand)) - { - return resolvedCommand; - } - - var scopeEntry = scope.LookupCommand(commandName); - if (scopeEntry != null) - { - resolvedCommands[commandName] = null; - return null; - } - - // Make sure we only call the cmdlet. - var getCommandCommand = new CmdletInfo("Get-Command", typeof(GetCommandCommand)); - do - { - // Look in the session for the command name. - invoker.Commands.Clear(); - invoker.AddCommand(getCommandCommand) - .AddParameter("Name", commandName) - .AddParameter("ErrorAction", ActionPreference.Ignore); - var result = invoker.Invoke(); - - // There was a result - this is a command from the session. - // Resolve an aliases, and figure out the actual command name. - if (result.Count > 0) - { - foreach (CommandInfo currentResult in result) - { - string compareName = currentResult.Name; - string moduleQualifiedName = currentResult.ModuleName + "\\" + currentResult.Name; - - if (currentResult.CommandType == CommandTypes.Application) - { - compareName = System.IO.Path.GetFileNameWithoutExtension(currentResult.Name); - } - - if (String.Equals(commandName, currentResult.Name, StringComparison.OrdinalIgnoreCase) || - String.Equals(commandName, moduleQualifiedName, StringComparison.OrdinalIgnoreCase) || - String.Equals(commandName, compareName, StringComparison.OrdinalIgnoreCase)) - { - resolvedCommand = currentResult; - - if (resolvedCommand is AliasInfo) - { - commandName = resolvedCommand.Definition; - } - break; - } - } - } - - // Also chase down aliases - } while (resolvedCommand is AliasInfo); - - resolvedCommands[commandName] = resolvedCommand; - return resolvedCommand; - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Microsoft.Reliability", - "CA2001:AvoidCallingProblematicMethods", - MessageId = "System.Reflection.Assembly.LoadFrom")] - private static void PopulateActivityStaticMap() - { - string[] defaultAssemblies = { - "Microsoft.PowerShell.Activities", - "Microsoft.PowerShell.Core.Activities", - "Microsoft.PowerShell.Diagnostics.Activities", - "Microsoft.PowerShell.Management.Activities", - "Microsoft.PowerShell.Security.Activities", - "Microsoft.PowerShell.Utility.Activities", - "Microsoft.WSMan.Management.Activities", - "Microsoft.PowerShell.Workflow.ServiceCore" - }; - - // Add our default assemblies - foreach (string assembly in defaultAssemblies) - { - Assembly loadedAssembly = null; - - try - { - loadedAssembly = Assembly.Load(assembly); - } - catch (IOException) - { - string newAssembly = assembly + ", Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; - loadedAssembly = Assembly.Load(newAssembly); - } - - ProcessAssembly(loadedAssembly, staticProcessedActivityLibraries, staticActivityMap); - } - } - - [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")] - internal static Dictionary GetActivityMap(IEnumerable assembliesToScan, out HashSet processedActivityLibraries) - { - // Guard access to private static variables. IEnumerable use is not thread safe. - Dictionary activityMap = null; - lock (staticProcessedActivityLibraries) - { - activityMap = new Dictionary(staticActivityMap, StringComparer.OrdinalIgnoreCase); - - if (assembliesToScan == null) - { - processedActivityLibraries = new HashSet(staticProcessedActivityLibraries, StringComparer.OrdinalIgnoreCase); - return activityMap; - } - - processedActivityLibraries = new HashSet(staticProcessedActivityLibraries, StringComparer.OrdinalIgnoreCase); - } - - foreach (string assembly in assembliesToScan) - { - Assembly loadedAssembly = null; - - try - { - // Try first from the GAC - loadedAssembly = Assembly.Load(assembly); - } - catch (IOException) - { - try - { - // And second by path - loadedAssembly = Assembly.LoadFrom(assembly); - } - catch (IOException) - { - // Finally, by relative path - if (CoreRunspaces.Runspace.DefaultRunspace != null) - { - using (System.Management.Automation.PowerShell nestedPs = - System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace)) - { - nestedPs.AddCommand("Get-Location"); - PathInfo result = nestedPs.Invoke()[0]; - - string currentLocation = result.ProviderPath; - - try - { - loadedAssembly = Assembly.LoadFrom(Path.Combine(currentLocation, assembly)); - } - catch (IOException) - { - } - } - } - } - } - - // Throw an error if we weren't able to load the assembly. - if (loadedAssembly == null) - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.CouldNotLoadRequiredAssembly, assembly); - throw new IOException(error); - } - - ProcessAssembly(loadedAssembly, processedActivityLibraries, activityMap); - } - - return activityMap; - } - - private static void ProcessAssembly(Assembly activityAssembly, HashSet processedActivityLibraries, Dictionary activityMap) - { - // Remember that we've processed this assembly (and therefore - // the module). - string assemblyName = activityAssembly.ManifestModule.Name; - int activityIndex = assemblyName.IndexOf(".Activities.dll", StringComparison.OrdinalIgnoreCase); - if(activityIndex > 0) - { - string moduleName = assemblyName.Substring(0, activityIndex); - processedActivityLibraries.Add(moduleName); - } - - bool isRunningInConstrainedLanguage = false; - - // If we're in ConstrainedLanguage mode, block inline XAML as it can't be verified. - CoreRunspaces.Runspace currentRunspace = (CoreRunspaces.Runspace)CoreRunspaces.Runspace.DefaultRunspace; - if (currentRunspace != null) - { - if (currentRunspace.SessionStateProxy.LanguageMode == PSLanguageMode.ConstrainedLanguage) - { - isRunningInConstrainedLanguage = true; - } - } - - - foreach (Type type in activityAssembly.GetTypes()) - { - // Process activities exported by this assembly - if (!typeof(System.Activities.Activity).IsAssignableFrom(type)) - { - continue; - } - - // Ensure it derives from PSActivity if it's in constrained language, - // as arbitrary workflow activities (like VisualBasicValue) may be - // unsafe - if (isRunningInConstrainedLanguage && - (!typeof(Microsoft.PowerShell.Activities.PSActivity).IsAssignableFrom(type))) - { - continue; - } - - // If the activity map already contains an assembly with this name, - // then set the value to NULL. During processing, we will recognize - // this and throw an exception about this type name being ambiguous. - if (activityMap.ContainsKey(type.Name)) - { - activityMap[type.Name] = null; - } - else - { - activityMap[type.Name] = type; - } - - // Update the activity map with the full name to support users specifying - // an activity with full name. - // If the activity map already contains an assembly with this full name, - // set the value to NULL as is done for Name key. - if (activityMap.ContainsKey(type.FullName)) - { - activityMap[type.FullName] = null; - } - else - { - activityMap[type.FullName] = type; - } - - // Update the activity map with both the - // short name and full name. By convention, activities generated from commands - // get put in a namespace with ".Activities" after the module name. Remove the - // ".Activities" bit so that module-qualified command lookups work - i.e.: - // Microsoft.PowerShell.Utility\Write-Output - activityMap[type.Namespace.Replace(".Activities", "") + "\\" + type.Name] = type; - } - } - - private void GeneratePersist(CommandAst commandAst) - { - // Verify they've used the correct syntax - if (commandAst.CommandElements.Count > 1) - { - ReportError("CheckpointWorkflowSyntax", ActivityResources.CheckpointWorkflowSyntax, commandAst.Extent); - } - - GenerateActivityCall(null, null, typeof(Microsoft.PowerShell.Activities.PSPersist), null, null, null, null, commandAst.Extent); - } - - private void GenerateSuspend(CommandAst commandAst) - { - StaticBindingResult bindingResult = StaticParameterBinder.BindCommand(commandAst, false); - - // Verify they've used the correct syntax - if (bindingResult.BoundParameters.Count == 0) - { - GenerateActivityCall(null, null, typeof(Microsoft.PowerShell.Activities.Suspend), null, null, null, null, commandAst.Extent); - return; - } - - if (bindingResult.BoundParameters.Count == 1 && bindingResult.BoundParameters.ContainsKey("Label")) - { - Object label = bindingResult.BoundParameters["Label"].ConstantValue; - if (label == null) - { - ReportError("SuspendWorkflowSyntax", ActivityResources.SuspendWorkflowSyntax, commandAst.Extent); - return; - } - - CommandArgumentInfo argumentInfo = new CommandArgumentInfo(); - - argumentInfo.Value = label.ToString(); - argumentInfo.IsLiteral = true; - - // Prepare the parameter used - Dictionary finalParameters = new Dictionary(StringComparer.OrdinalIgnoreCase); - finalParameters["Label"] = argumentInfo; - - GenerateActivityCall(null, null, typeof(Microsoft.PowerShell.Activities.Suspend), null, finalParameters, null, null, commandAst.Extent); - - return; - } - - ReportError("SuspendWorkflowSyntax", ActivityResources.SuspendWorkflowSyntax, commandAst.Extent); - } - - private void GenerateInvokeExpression(CommandAst commandAst) - { - StaticBindingResult bindingResult = StaticParameterBinder.BindCommand(commandAst, false); - - // Verify they've used the correct syntax - if (bindingResult.BoundParameters.Count != 2) - { - ReportError("InvokeExpressionSyntaxTooManyParameters", ActivityResources.InvokeExpressionSyntax, commandAst.Extent); - return; - } - - // Validate the 'Language' parameter - if (bindingResult.BoundParameters.ContainsKey("Language")) - { - ParameterBindingResult language = bindingResult.BoundParameters["Language"]; - Object constantLanguage = language.ConstantValue; - if (constantLanguage == null) - { - ReportError("InvokeExpressionSyntaxLanguageNotConstant", ActivityResources.InvokeExpressionSyntax, commandAst.Extent); - return; - } - - if (!String.Equals("XAML", constantLanguage.ToString(), StringComparison.OrdinalIgnoreCase)) - { - ReportError("MustUseXamlLanguage", ActivityResources.MustUseXamlLanguage, language.Value.Extent); - } - } - else - { - ReportError("InvokeExpressionSyntaxLanguageMissing", ActivityResources.InvokeExpressionSyntax, commandAst.Extent); - return; - } - - // Validate the 'Command' parameter - if (bindingResult.BoundParameters.ContainsKey("Command")) - { - ParameterBindingResult command = bindingResult.BoundParameters["Command"]; - Object constantCommand = command.ConstantValue; - if (constantCommand == null) - { - ReportError("InvokeExpressionSyntaxCommandNotConstant", ActivityResources.InvokeExpressionSyntax, commandAst.Extent); - return; - } - - // If we're in ConstrainedLanguage mode, block inline XAML as it can't be verified. - CoreRunspaces.Runspace currentRunspace = (CoreRunspaces.Runspace) CoreRunspaces.Runspace.DefaultRunspace; - if (currentRunspace != null) - { - if (currentRunspace.SessionStateProxy.LanguageMode == PSLanguageMode.ConstrainedLanguage) - { - ReportError("InlineXamlNotSupported", ActivityResources.InlineXamlNotSupported, commandAst.Extent); - return; - } - } - - string inlineXaml = constantCommand.ToString(); - bodyElements.Add(inlineXaml); - } - else - { - ReportError("InvokeExpressionSyntaxCommandMissing", ActivityResources.InvokeExpressionSyntax, commandAst.Extent); - return; - } - } - - private void GenerateStartSleep(CommandAst commandAst) - { - CommandInfo command = ResolveCommand("Start-Sleep"); - Dictionary parameters = GetAndResolveParameters(commandAst, true); - - // Verify they've used the correct syntax - if (parameters.Count != 1) - { - ReportError("StartSleepSyntaxTooManyParameters", ActivityResources.StartSleepSyntax, commandAst.Extent); - return; - } - - CommandArgumentInfo argumentInfo = new CommandArgumentInfo(); - - if (parameters.ContainsKey("Seconds")) - { - // 'Seconds' parameter - string paramValue = parameters["Seconds"].Value.ToString(); - if (paramValue == null) - { - ReportError("StartSleepSyntaxCouldNotParseSeconds", ActivityResources.StartSleepSyntax, commandAst.Extent); - return; - } - - int secondsInt = -1; - if (Int32.TryParse(paramValue, out secondsInt)) - { - // Create literal TimeSpan argument type from seconds. - argumentInfo.Value = new System.TimeSpan(0, 0, secondsInt).ToString(); - argumentInfo.IsLiteral = true; - } - else - { - // Create expression argument with conversion from seconds to ticks for TimeSpan type. - argumentInfo.Value = String.Format(CultureInfo.InvariantCulture, - @"([Int64]({0}) * 10000000)", paramValue); - - argumentInfo.IsLiteral = false; - } - } - else if (parameters.ContainsKey("Milliseconds")) - { - // 'Milliseconds' parameter - string paramValue = parameters["Milliseconds"].Value.ToString(); - if (paramValue == null) - { - ReportError("StartSleepSyntaxCouldNotParseSeconds", ActivityResources.StartSleepSyntax, commandAst.Extent); - return; - } - - int mSecondsInt = -1; - if (Int32.TryParse(paramValue, out mSecondsInt)) - { - // Create literal TimeSpan argument type from milliseconds. - argumentInfo.Value = new System.TimeSpan(0, 0, 0, 0, mSecondsInt).ToString(); - argumentInfo.IsLiteral = true; - } - else - { - // Create expression argument with conversion from milliseconds to ticks for TimeSpan type. - argumentInfo.Value = String.Format(CultureInfo.InvariantCulture, - @"([Int64]({0}) * 10000)", paramValue); - - argumentInfo.IsLiteral = false; - } - } - else - { - ReportError("StartSleepSyntaxSecondsMissing", ActivityResources.StartSleepSyntax, commandAst.Extent); - return; - } - - // Prepare the parameter used - Dictionary finalParameters = new Dictionary(StringComparer.OrdinalIgnoreCase); - finalParameters["Duration"] = argumentInfo; - - GenerateActivityCall(null, null, typeof(System.Activities.Statements.Delay), null, finalParameters, null, null, commandAst.Extent); - } - - private void GenerateNewObject(CommandAst commandAst) - { - CommandInfo command = ResolveCommand("New-Object"); - Dictionary parameters = GetAndResolveParameters(commandAst, true); - - // Verify they've used the correct syntax - if ((parameters.Count == 0) || (parameters.Count > 2)) - { - ReportError("NewObjectSyntaxTooManyParameters", ActivityResources.NewObjectSyntax, commandAst.Extent); - return; - } - - if (parameters.ContainsKey("TypeName")) - { - // 'TypeName' parameter - string paramValue = parameters["TypeName"].OriginalValue.ToString(); - Type outputType = ResolveTypeFromParameterValue(commandAst, paramValue); - if (outputType == null) - { - // Error reporting already handled by ResolveTypeFromParameterValue - return; - } - - string expression = GetPowerShellValueExpression(commandAst); - GeneratePowerShellValue(outputType, expression, false, true); - } - else - { - ReportError("NewObjectSyntaxMissingTypeName", ActivityResources.NewObjectSyntax, commandAst.Extent); - } - } - - private Type ResolveTypeFromParameterValue(CommandAst commandAst, string paramValue) - { - Type outputType = null; - - try - { - outputType = LanguagePrimitives.ConvertTo(paramValue); - } - catch (PSInvalidCastException) - { - // Find the actual parameter AST - Ast resultAst = commandAst; - foreach (CommandElementAst commandElement in commandAst.CommandElements) - { - var parameter = commandElement as CommandParameterAst; - if (parameter != null) - { - if (String.Equals("TypeName", parameter.ParameterName, StringComparison.OrdinalIgnoreCase)) - { - resultAst = parameter; - break; - } - } - } - - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.NewObjectCouldNotFindType, paramValue); - ReportError("NewObjectCouldNotFindType", error, resultAst.Extent); - } - - return outputType; - } - - // We need to convert command arguments to their script representation - // for the following scenario: - // Get-Process -Name Foo,Bar - // When we call the Get-Process activity, we need to coerce its arguments - // to the type expected by the parameter - for example, string[]. - // To do this, we generate basically the following XAML: - // - // - // - // - // - // Get-Process -Name $arguments - // But since the arguments were retrieved in parameter parsing mode, we need - // to quote strings (since they may be considered commands) before supplying - // them as a PowerShell expression. - private string ProcessCommandArgument(CommandElementAst argument) - { - if (argument == null) - return null; - string argumentValue = ""; - - ArrayLiteralAst arrayLiteralArgument = argument as ArrayLiteralAst; - - if (arrayLiteralArgument != null) - { - foreach (ExpressionAst expression in arrayLiteralArgument.Elements) - { - if (!String.IsNullOrEmpty(argumentValue)) - argumentValue += ","; - - argumentValue += ProcessCommandArgumentElement(expression); - } - } - else - { - argumentValue = ProcessCommandArgumentElement(argument); - } - - return argumentValue; - } - - private string ProcessCommandArgumentElement(CommandElementAst argument) - { - // If it's a string constant, single quote it. - StringConstantExpressionAst stringAst = argument as StringConstantExpressionAst; - if (stringAst != null && stringAst.StringConstantType == StringConstantType.BareWord) - { - string bareContent = argument.Extent.Text.Replace("'", "''"); - bareContent = "'" + bareContent + "'"; - - return bareContent; - } - - // If it's an expandable string, double quote it - ExpandableStringExpressionAst expandableString = argument as ExpandableStringExpressionAst; - if (expandableString != null && expandableString.StringConstantType == StringConstantType.BareWord) - { - string bareContent = argument.Extent.Text.Replace("\"", "`\""); - bareContent = "\"" + bareContent + "\""; - - return bareContent; - } - - return argument.Extent.Text; - } - - private void ProcessInlineScriptAst(CommandAst commandAst) - { - if (commandAst.CommandElements.Count == 1) - { - ReportError("InlineScriptSyntaxTooFewParameters", ActivityResources.InlineScriptSyntax, commandAst.Extent); - return; - } - - var scriptBlock = commandAst.CommandElements[1] as ScriptBlockExpressionAst; - bool scriptBlockExists = scriptBlock != null; - if (!scriptBlockExists) - { - ReportError("InlineScriptMissingStatementBlock", ActivityResources.InlineScriptSyntax, commandAst.Extent); - return; - } - - List variableExprsWithWorkflowPrefix = ContainVariablesWithWorkflowPrefix(scriptBlock); - if (variableExprsWithWorkflowPrefix.Any()) - { - ReportError("CannotUseWorkflowPrefixInInlineScript", ActivityResources.CannotUseWorkflowPrefixInInlineScript, variableExprsWithWorkflowPrefix[0].Extent); - } - - StaticBindingResult bindingResult = StaticParameterBinder.BindCommand(commandAst, false); - - // Remove the first positional element (the script) if there is one - if (bindingResult.BoundParameters.ContainsKey("0")) - { - bindingResult.BoundParameters.Remove("0"); - } - - bool isCommandSpecified = bindingResult.BoundParameters.ContainsKey("Command"); - bool isCommandNameSpecified = bindingResult.BoundParameters.ContainsKey("CommandName"); - bool isParametersSpecified = bindingResult.BoundParameters.ContainsKey("Parameters"); - var sbExpr = commandAst.CommandElements[1] as ScriptBlockExpressionAst; - - IScriptExtent errorParameterExtent = null; - if (isCommandSpecified) - { - errorParameterExtent = bindingResult.BoundParameters["Command"].Value.Extent; - } - else if (isCommandNameSpecified) - { - errorParameterExtent = bindingResult.BoundParameters["CommandName"].Value.Extent; - } - else if (isParametersSpecified) - { - errorParameterExtent = bindingResult.BoundParameters["Parameters"].Value.Extent; - } - - if (errorParameterExtent != null) - { - ReportError("InlineScriptParameterNotSupported", ActivityResources.InlineScriptSyntax, errorParameterExtent); - } - - Dictionary convertedParameters = ResolveParameters(bindingResult); - String scriptToProcess = sbExpr.ScriptBlock.EndBlock.Extent.Text; - GenerateInlineScript(scriptToProcess, null, convertedParameters, commandAst.Extent, true); - } - - private List ContainVariablesWithWorkflowPrefix(Ast scriptBlock) - { - Func variableExprWithWorkflowPrefixSearcher = - (ast) => - { - var variableExpr = ast as VariableExpressionAst; - if (variableExpr == null) { return false; } - - return variableExpr.VariablePath.UserPath.StartsWith("WORKFLOW:", StringComparison.OrdinalIgnoreCase); - }; - - return scriptBlock.FindAll(variableExprWithWorkflowPrefixSearcher, searchNestedScriptBlocks: true).ToList(); - } - - private const string PSRequiredModules = "PSRequiredModules"; - private void GenerateInlineScript(string inlineScript, string displayName, Dictionary parameters, IScriptExtent extent, bool isExplicit) - { - Dictionary arguments = new Dictionary(StringComparer.OrdinalIgnoreCase); - var argumentInfo = new CommandArgumentInfo { Value = inlineScript, IsLiteral = true }; - arguments.Add("Command", argumentInfo); - - if (displayName != null) - { - var displayNameArgInfo = new CommandArgumentInfo { Value = displayName, IsLiteral = true }; - arguments.Add("DisplayName", displayNameArgInfo); - } - - if (!isExplicit) - { - string moduleQualifier = GetModuleQualifier(inlineScript); - if (moduleQualifier != null) - { - CommandArgumentInfo requiredModuleArgument = new CommandArgumentInfo(); - requiredModuleArgument.Value = string.Format(CultureInfo.InvariantCulture, - "'{0}'", moduleQualifier); - requiredModuleArgument.IsLiteral = false; - arguments[PSRequiredModules] = requiredModuleArgument; - } - } - - // Copy the parameters - if (parameters != null) - { - foreach (string key in parameters.Keys) - { - arguments.Add(key, parameters[key]); - } - } - - GenerateActivityCall(null, "InlineScript", typeof(InlineScript), null, arguments, null, null, extent); - } - - private string GetModuleQualifier(string command) - { - if (string.IsNullOrEmpty(command)) - return null; - - int pos = command.IndexOf('\\'); - - if (pos < 0) - return null; - - System.Management.Automation.Language.Token[] tokens = null; - System.Management.Automation.Language.ParseError[] errors = null; - - System.Management.Automation.Language.Parser.ParseInput(command, out tokens, out errors); - if (tokens == null || errors == null || tokens.Length == 0 || errors.Length > 0) - return null; - - command = tokens[0].Text; - pos = command.IndexOf('\\'); - - if (pos > 0 && pos < command.Length - 1) - return command.Substring(0, pos); - - return null; - } - - private void SetVariableArgumentValue(CommandArgumentInfo argument, ref object argumentValue) - { - System.Diagnostics.Debug.Assert(argumentValue != null, "argumentValue should not be null"); - - if (argument != null) - { - argumentValue = "$" + argument.OriginalValue; - } - else if (argumentValue is CommandElementAst) - { - var cmdElement = argumentValue as CommandElementAst; - argumentValue = "$" + cmdElement; - } - } - - private void GenerateActivityCall( - CommandInfo commandInfo, - string invocationName, - Type activityType, - DynamicActivity activityInstance, - Dictionary arguments, - StaticBindingResult argumentResolution, - StaticBindingResult syntacticResolution, - IScriptExtent extent - ) - { - bool isNestedWorkflow = activityInstance != null; - - // If we're in a pipeline, ensure that this activity derives from PipelineEnabledActivity - if (this.isVisitingPipeline) - { - if ((activityType != null) && (! typeof(PipelineEnabledActivity).IsAssignableFrom(activityType))) - { - string activityName = extent.ToString(); - if (commandInfo != null) - { - activityName = commandInfo.Name; - } - - ReportError("ActivityNotSupportedInPipeline", - String.Format(CultureInfo.InvariantCulture, ActivityResources.ActivityNotSupportedInPipeline, activityName), extent); - } - } - - // Generate symbolic information for this activity call. - if (!String.Equals("SetPSWorkflowData", invocationName, StringComparison.OrdinalIgnoreCase)) - { - GenerateSymbolicInformation(extent); - } - - if ((arguments != null) && arguments.ContainsKey("Result")) - { - if(! this.ValidateOnly) - { - ReportError("CannotSpecifyResultArgument", ActivityResources.CannotSpecifyResultArgument, extent); - } - } - - string attributes = string.Empty; - if (string.Equals("InlineScript", invocationName)) - { - if (arguments.ContainsKey("Command")) - { - CommandArgumentInfo argument = arguments["Command"]; - arguments.Remove("Command"); - string argumentValue = argument.Value.ToString(); - if (argumentValue == null) - { - argumentValue = string.Empty; - } - attributes = " Command=\"" + - EncodeStringArgument(argumentValue, false) + - "\""; - } - } - - Dictionary propertiesToEmulate = new Dictionary(StringComparer.OrdinalIgnoreCase); - - // Check if the error stream is redirected for the current command - if (this.mergeErrorToOutput) - { - // Check if the dynamic activity instance contains the properties we need - Type parameterType = null; - if (!IsParameterAvailable(activityType, activityInstance, "MergeErrorToOutput", false, extent, out parameterType)) - { - // If this is a workflow calling workflow, we'll emulate the property - if (isNestedWorkflow) - { - propertiesToEmulate.Add("MergeErrorToOutput", "[True]"); - } - else - { - // Don't report on parameter errors from nested workflows, as they require compilation - if (!this.ValidateOnly) - { - ReportError("CannotMergeErrorToOutput", - String.Format(CultureInfo.InvariantCulture, ActivityResources.CannotMergeErrorToOutput, invocationName), extent); - } - } - } - else - { - attributes += @" MergeErrorToOutput = ""True"""; - } - } - - // Process the generic activity type - Dictionary genericTypeMap = null; - if (activityType.IsGenericType && arguments.ContainsKey(GenericTypesKey)) - { - var genericTypes = (Type[]) arguments[GenericTypesKey].Value; - var concatenatedTypeNames = new StringBuilder(); - foreach (Type type in genericTypes) - { - string convertedTypeName = GetConvertedTypeName(type); - concatenatedTypeNames.Append(convertedTypeName); - concatenatedTypeNames.Append(", "); - } - concatenatedTypeNames.Remove(concatenatedTypeNames.Length - 2, 2); - attributes += String.Format(CultureInfo.InvariantCulture, @" x:TypeArguments=""{0}""", concatenatedTypeNames); - arguments.Remove(GenericTypesKey); - - genericTypeMap = GetGenericTypeMap(activityType, genericTypes); - } - - // Create an assembly name reference - string friendlyName = GetFriendlyName(invocationName, activityType); - - if ((commandInfo != null) && (invocationName == null)) - { - invocationName = commandInfo.Name; - } - - if (String.IsNullOrEmpty(invocationName)) - { - invocationName = extent.Text; - } - - // Generate the call to the activity - - // Capture the result if there is any output variable defined - var currentVariable = GetVariableToUse(); - string variableToUse = null; - bool isAggregatingVariable = false; - if (currentVariable != null) - { - variableToUse = currentVariable.VariableName; - isAggregatingVariable = currentVariable.IsAggregatingVariable; - } - VariableDefinition variableToUseDefinition = null; - - if (!String.IsNullOrEmpty(variableToUse)) - { - variableToUseDefinition = GetVariableDefinition(variableToUse); - variableToUseDefinition = variableToUseDefinition ?? members[variableToUse]; - } - - string appendOutput = String.Empty; - string actualAggregatingVariable = String.Empty; - bool needAggregationVariable = false; - bool needConversionVariable = false; - - if (!String.IsNullOrEmpty(variableToUse)) - { - if (activityType.Equals(typeof(System.Activities.Statements.Delay))) - { - if (!isAggregatingVariable) - { - ReportError("CannotAssignStartSleepToVariable", ActivityResources.CannotAssignStartSleepToVariable, extent); - } - else - { - // ignore the storagescope variable for start-sleep - attributes = null; - } - } - else - { - // Activities derived from Activity have two Result properties, one from the Activity - // the other from ActivityWithResult. So we cannot handle the property Result as a regular property. - Type[] genericArgumentTypes = null; - bool isActivityWithResult = activityType.IsGenericType && IsAssignableFromGenericType(typeof(Activity<>), activityType, out genericArgumentTypes); - Type activityOutputType = null; - - // Check if the dynamic activity instance contains the properties we need - Type parameterType = null; - if (!IsParameterAvailable(activityType, activityInstance, "Result", isActivityWithResult, extent, out parameterType)) - { - // If this is a workflow calling workflow, we'll emulate the property - if (isNestedWorkflow) - { - propertiesToEmulate.Add("Result", "[" + variableToUse + "]"); - } - else - { - if (!this.ValidateOnly) - { - ReportError("ActivityDoesNotContainResultProperty", - String.Format(CultureInfo.InvariantCulture, ActivityResources.ActivityDoesNotContainResultProperty, variableToUse, invocationName), extent); - } - else - { - return; - } - } - } - - // Get the activity output type - if (parameterType != null) - { - activityOutputType = GetActualPropertyType( - isActivityWithResult ? genericArgumentTypes[genericArgumentTypes.Length - 1] : parameterType, - genericTypeMap, "Result", extent); - } - - Type unused = null; - - // Check if we need to make a temporary variable for either aggregation, or conversion. - if (isAggregatingVariable && - !IsParameterAvailable(activityType, activityInstance, "AppendOutput", false, extent, out unused)) - { - needAggregationVariable = true; - } - if ((variableToUseDefinition.Type != activityOutputType) && (! isNestedWorkflow)) - { - needConversionVariable = true; - } - - // If we need a temporary variable, create it. - if (needAggregationVariable || needConversionVariable) - { - Type tempVarType = isNestedWorkflow - ? typeof(PSDataCollection) - : activityOutputType; - - // Define the temporary variable - string tempVarName = GenerateUniqueVariableName("__AggregatingTempVar"); - DefineVariable(tempVarName, tempVarType, extent, null); - - if (isNestedWorkflow) - { - // We are calling a nested workflow. we need to create a new instance of the storage variable. - try - { - EnterStorage(tempVarName, false); - string constructor = "New-Object -Type System.Management.Automation.PSDataCollection[PSObject]"; - GeneratePowerShellValue(typeof(System.Management.Automation.PSDataCollection), constructor, false, true); - } - finally - { - LeaveStorage(); - } - } - - actualAggregatingVariable = variableToUse; - variableToUse = tempVarName; - } - - if (isActivityWithResult) - { - appendOutput = String.Format(CultureInfo.InvariantCulture, " Result=\"[{0}]\"", variableToUse); - } - else - { - if (!propertiesToEmulate.ContainsKey("Result")) - { - arguments["Result"] = new CommandArgumentInfo() { Value = "$" + variableToUse }; - } - - if (isAggregatingVariable && !needAggregationVariable) { appendOutput = AppendOutputTemplate; } - } - } - } - - string getPSWorkflowDataFriendlyName = GetFriendlyName("GetPSWorkflowData", typeof(GetPSWorkflowData)); - string setPSWorkflowDataFriendlyName = GetFriendlyName("SetPSWorkflowData", typeof(SetPSWorkflowData)); - - // If we have any properties to emulate, save the old values and set the new ones - if (propertiesToEmulate.Count > 0) - { - WriteLine(""); - IndentLevel(); - WriteLine(""); - IndentLevel(); - WriteLine(""); - - IndentLevel(); - - // Prepare the variables - foreach (string propertyToEmulate in propertiesToEmulate.Keys) - { - // Create variables for the saved values if we need them - string variableName = "PSSaved_" + propertyToEmulate; - if (!VariableDefinedInCurrentScope(variableName)) - { - DefineVariable(variableName, typeof(Object), extent, null); - } - - // Save the existing variable, and set the new one. - WriteLine(@"<" + getPSWorkflowDataFriendlyName + @" x:TypeArguments=""x:Object"" OtherVariableName=""" + - propertyToEmulate + @""" Result=""[" + variableName + @"]"" VariableToRetrieve=""Other"" />"); - WriteLine(@"<" + setPSWorkflowDataFriendlyName + @" PSRemotingBehavior=""{x:Null}"" OtherVariableName=""" + - propertyToEmulate + @""" Value=""" + propertiesToEmulate[propertyToEmulate] + @""" />"); - } - } - - WriteLine("<" + friendlyName + attributes + appendOutput + ">"); - IndentLevel(); - - // Now process the arguments - if (arguments != null) - { - // Attempt to add any parameter defaults if they have been supplied from preference variables - UpdateArgumentsFromPreferenceVariables(activityType, arguments, activityInstance); - var boundParameters = new HashSet(StringComparer.OrdinalIgnoreCase); - - List argumentsToProcess = arguments.Keys.ToList(); - if((argumentResolution != null) && (argumentResolution.BindingExceptions != null)) - { - argumentsToProcess.AddRange(argumentResolution.BindingExceptions.Keys); - } - - foreach (string parameterNameIterator in argumentsToProcess) - { - string parameterName = parameterNameIterator; - - CommandArgumentInfo argument = null; - object argumentValue = null; - bool isLiteral = false; - bool wasSpecifiedAsSwitch = false; - - if (arguments.ContainsKey(parameterName)) - { - argument = arguments[parameterName]; - argumentValue = argument.Value; - isLiteral = argument.IsLiteral; - - // Detect a boolean that was used like a switch - if ((syntacticResolution != null) && - ((string)argumentValue == "-" + parameterName) && - (syntacticResolution.BoundParameters[parameterName].ConstantValue is bool)) - { - argument = null; - argumentValue = syntacticResolution.BoundParameters[parameterName].ConstantValue; - isLiteral = true; - wasSpecifiedAsSwitch = true; - } - } - else if (syntacticResolution != null) - { - // This was not bound successfully, look in the syntactic - // version of the bound parameters. - argumentValue = syntacticResolution.BoundParameters[parameterName].Value; - isLiteral = (syntacticResolution.BoundParameters[parameterName].ConstantValue != null); - } - - // If this is 'PipelineVariable', ignore this argument as it is implemented - // by workflow compilation itself. - if (String.Equals("PipelineVariable", parameterName, StringComparison.OrdinalIgnoreCase)) - { - continue; - } - - // If the argument value is NULL, then this was a switch parameter and - // we change it to $true - if (argumentValue == null) - { - argumentValue = "$true"; - } - - // If this is ErrorVariable or WarningVariable, switch it to PSError and PSWarning, - // respectively - if (String.Equals("ErrorVariable", parameterName, StringComparison.OrdinalIgnoreCase) || - String.Equals("EV", parameterName, StringComparison.OrdinalIgnoreCase)) - - { - parameterName = "PSError"; - SetVariableArgumentValue(argument, ref argumentValue); - } - - if (String.Equals("WarningVariable", parameterName, StringComparison.OrdinalIgnoreCase) || - String.Equals("WV", parameterName, StringComparison.OrdinalIgnoreCase)) - { - parameterName = "PSWarning"; - SetVariableArgumentValue(argument, ref argumentValue); - isLiteral = true; - } - - if (String.Equals("InformationVariable", parameterName, StringComparison.OrdinalIgnoreCase) || - String.Equals("IV", parameterName, StringComparison.OrdinalIgnoreCase)) - { - parameterName = "PSInformation"; - SetVariableArgumentValue(argument, ref argumentValue); - isLiteral = true; - } - - Type propertyType = GetPropertyType(activityType, activityInstance, ref parameterName, extent); - - // Flatten Nullable arguments down to their base - if ((propertyType != null) && propertyType.IsGenericType && (propertyType.GetGenericTypeDefinition().IsAssignableFrom(typeof(Nullable<>)))) - { - propertyType = propertyType.GetGenericArguments()[0]; - } - - // If we can't find the property name, we may have done parameter avoidance and renamed the - // activity's parameter so that it didn't conflict with something in workflow. Try to - // undo it and try again. - if ((invocationName != null) && (propertyType == null)) - { - // If it has a noun, trim it to include only the noun - string avoidanceQualifier = invocationName; - int nounIndex = avoidanceQualifier.IndexOf('-'); - if (nounIndex >= 0) - { - avoidanceQualifier = avoidanceQualifier.Substring(nounIndex + 1); - } - - // Try again - parameterName = avoidanceQualifier + parameterNameIterator; - propertyType = GetPropertyType(activityType, activityInstance, ref parameterName, extent); - } - - // If we couldn't find the parameter, generate an error. - if (propertyType == null) - { - if ((invocationName != null) && (argumentResolution != null) && argumentResolution.BoundParameters.ContainsKey(parameterName)) - { - StaticBindingError bindingException = argumentResolution.BindingExceptions[parameterName]; - ReportError("CannotFindParameter", bindingException.BindingException.Message, extent); - return; - } - else - { - Dictionary availableProperties = GetAvailableProperties(activityType, activityInstance); - - // Check if this is "Workflows calling workflows" - if ((activityInstance != null) && (parameterNameIterator.StartsWith("PS", StringComparison.OrdinalIgnoreCase))) - { - // Don't report on parameter errors from nested workflows, as they require compilation - if (!this.ValidateOnly) - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.CouldNotFindParameterNameNested, parameterNameIterator); - ReportError("CouldNotFindWorkflowCommonParameterNameNested", error, extent); - } - - return; - } - else if (IsNotSupportedCommonParameter(parameterNameIterator)) - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.CommonParameterNotSupported, parameterNameIterator, invocationName); - ReportError("CommonParameterNotSupported", error, extent); - return; - } - else if (String.Equals("ComputerName", parameterNameIterator, StringComparison.OrdinalIgnoreCase) && - availableProperties.ContainsKey("PSComputerName")) - { - ReportError("RemotingHandledByPSComputerName", ActivityResources.RemotingHandledByPSComputerName, extent); - return; - } - else - { - // They've typed a parameter that we can't map. Since there is no "Get-Command -Syntax" option, dump out all - // of the properties for them. - List completeProperties = new List(availableProperties.Keys); - - // If this is a workflow calling workflow, add in the virtual properties that don't exist, since they may not - // have been actually compiled (if they were not used). - foreach(PropertyInfo psRemotingProperty in typeof(PSRemotingActivity).GetProperties()) - { - if (typeof(Argument).IsAssignableFrom(psRemotingProperty.PropertyType)) - { - if (!completeProperties.Contains(psRemotingProperty.Name, StringComparer.OrdinalIgnoreCase)) - { - completeProperties.Add(psRemotingProperty.Name); - } - } - } - - string[] sortedParameters = completeProperties.ToArray(); - Array.Sort(sortedParameters); - - string supportedParametersString = String.Join(", ", sortedParameters); - - // Check if this is one of our activities that shadow a cmdlet name - List shadowedCmdlets = new List() { "Invoke-Command" }; - if (shadowedCmdlets.Contains(invocationName, StringComparer.OrdinalIgnoreCase)) - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.CouldNotFindParameterNameShadowedActivity, parameterNameIterator, supportedParametersString); - ReportError("CouldNotFindParameterNameShadowedActivity", error, extent); - return; - } - else - { - // Don't report on parameter errors from nested workflows, as they require compilation - if (!this.ValidateOnly) - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.CouldNotFindParameterName, parameterNameIterator, supportedParametersString); - ReportError("CouldNotFindParameterName", error, extent); - } - - return; - } - } - } - } - - // Check if multiple specified parameters can be resolved to the same actual parameter - if (!boundParameters.Contains(parameterName)) - { - boundParameters.Add(parameterName); - } - else - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.DuplicateParametersNotAllowed, parameterName); - ReportError("DuplicateParametersNotAllowed", error, argument.ArgumentAst != null ? argument.ArgumentAst.Extent : extent); - } - - Type actualPropertyType = GetActualPropertyType(propertyType, genericTypeMap, parameterName, extent); - - // Detect calls to non-boolean properties that were specified like a switch - if ((actualPropertyType != typeof(bool)) && (actualPropertyType != typeof(SwitchParameter))) - { - if (wasSpecifiedAsSwitch) - { - string errorMsg = String.Format(CultureInfo.InvariantCulture, ActivityResources.MissingValueForParameter, parameterName); - ReportError("MissingValueForParameter", errorMsg, extent); - } - } - - ScriptBlockExpressionAst argumentValueAsScriptBlock = null; - if (argument != null) - { - argumentValueAsScriptBlock = argument.ArgumentAst as ScriptBlockExpressionAst; - } - - // See if this is a script block being bound to an activity - this is a container activity. - if( - argumentValueAsScriptBlock != null && - ( - typeof(Activity).IsAssignableFrom(propertyType) || - typeof(Activity[]).IsAssignableFrom(propertyType) || - (propertyType.IsGenericType && (typeof(Activity).IsAssignableFrom(propertyType.GetGenericArguments()[0]))) - )) - { - bool previousDisableSymbolGeneration = this.disableSymbolGeneration; - - WriteLine("<" + friendlyName + "." + parameterName + ">"); - IndentLevel(); - - WriteLine(""); - IndentLevel(); - - try - { - this.disableSymbolGeneration = true; - - foreach (StatementAst statement in argumentValueAsScriptBlock.ScriptBlock.EndBlock.Statements) - { - statement.Visit(this); - } - } - finally - { - this.disableSymbolGeneration = previousDisableSymbolGeneration; - - UnindentLevel(); - WriteLine(""); - - UnindentLevel(); - WriteLine(""); - } - } - // If the property type is not generic, then we have to in-line the string representation - // Or, if the incoming argument is of the exact type, and it's not a string (because then it could contain variable - // references etc), then use its string representation - else if ((!propertyType.IsGenericType) || - ((!ContainsLanguageElements(argumentValue.ToString())) && - (actualPropertyType == argumentValue.GetType()))) - { - string valueToUse = argumentValue.ToString(); - if ((argument != null) && (argument.OriginalValue != null)) - { - valueToUse = argument.OriginalValue.ToString(); - } - - if (ContainsLanguageElements(argumentValue.ToString())) - { - string convertedText = GetEquivalentVBTextForLiteralValue(actualPropertyType, valueToUse); - if (String.IsNullOrEmpty(convertedText)) - { - // If this is a direct property assignment, ensure it doesn't contain any PowerShell language - // elements. - - IScriptExtent errorExtent = null; - Ast argumentAst = argumentValue as Ast; - if (argumentAst != null) - { - errorExtent = argumentAst.Extent; - } - else - { - errorExtent = argument.ArgumentAst.Extent; - } - - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.PropertyDoesNotSupportPowerShellLanguage, parameterNameIterator); - ReportError("PropertyDoesNotSupportPowerShellLanguage", error, errorExtent); - } - - valueToUse = convertedText; - } - else - { - // This will be injected directly into the XAML - escape it - if (propertyType.IsGenericType) - { - valueToUse = EncodeStringArgument(valueToUse, false); - } - else - { - valueToUse = EncodeStringArgumentLiteral(valueToUse, false); - } - } - - // In the XAML processing sequence, provided values from a markup extension do not invoke additional value conversion. (http://msdn.microsoft.com/en-us/library/ms742135.aspx) - // So we use the markup extension to represent an empty string only if the property type is exactly System.String - if (String.Empty.Equals(valueToUse)) - { - if (propertyType.Equals(typeof(string))) - { - valueToUse = ""; - } - else - { - valueToUse = "[\"\"]"; - } - } - - WriteLine("<" + friendlyName + "." + parameterName + ">" + valueToUse + ""); - } - else - { - string argumentValueString = argumentValue.ToString(); - string variableName = argumentValueString.Substring(1); - - // If this is is an OutArgument or InOutArgument, they must supply a variable name. - // If they've supplied a variable name and the type matches, use that directly. - if ((propertyType.BaseType != null) && - (typeof(InOutArgument).IsAssignableFrom(propertyType.BaseType) || - typeof(OutArgument).IsAssignableFrom(propertyType.BaseType))) - { - if (argumentValueString.StartsWith("$", StringComparison.OrdinalIgnoreCase)) - { - if(! (VariableDefined(variableName) || members.ContainsKey(variableName))) - { - DefineVariable(variableName, actualPropertyType, extent, null); - } - - WriteLine("<" + friendlyName + "." + parameterName + ">[" + variableName + "]"); - } - else - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.MustSupplyVariableReferenceForInOutArgument, parameterName); - ReportError("MustSupplyVariableReferenceForInOutArgument", error, extent); - } - } - else - { - // Otherwise, go through PowerShellValue to resolve variables, expressions, etc. - string propertyFriendlyName = GetConvertedTypeName(actualPropertyType); - - WriteLine("<" + friendlyName + "." + parameterName + ">"); - IndentLevel(); - - String argumentLine = String.Format(CultureInfo.InvariantCulture, - @"<{0} x:TypeArguments=""{1}"">", - GetFriendlyName(null, propertyType), - propertyFriendlyName); - WriteLine(argumentLine); - IndentLevel(); - - // Now make the call - string expression = argumentValue.ToString(); - if (argumentValue is Ast) - { - expression = GetPowerShellValueExpression((Ast)argumentValue); - } - GeneratePowerShellValue(actualPropertyType, expression, isLiteral, false); - - UnindentLevel(); - WriteLine(""); - - UnindentLevel(); - WriteLine(""); - } - } - } - } - - // Close the activity call - UnindentLevel(); - WriteLine(""); - - // If we had any properties to emulate, restore the old values - if (propertiesToEmulate.Count > 0) - { - string exceptionFriendlyName = GetFriendlyName(null, typeof(Exception)); - // Restore the variables if there was no error - foreach(string propertyToEmulate in propertiesToEmulate.Keys) - { - // Variable names from the saved values if we need them - string variableName = "PSSaved_" + propertyToEmulate; - - WriteLine(@"<" + setPSWorkflowDataFriendlyName + @" PSRemotingBehavior=""{x:Null}"" OtherVariableName=""" + - propertyToEmulate + @""" Value=""[" + variableName + @"]"" />"); - } - - // Close the sequence and Try / Catch - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(""); - WriteLine(""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - WriteLine(""); - IndentLevel(); - - // Restore the variables in the Catch - foreach(string propertyToEmulate in propertiesToEmulate.Keys) - { - // Variable names from the saved values if we need them - string variableName = "PSSaved_" + propertyToEmulate; - - WriteLine(@"<" + setPSWorkflowDataFriendlyName + @" PSRemotingBehavior=""{x:Null}"" OtherVariableName=""" + - propertyToEmulate + @""" Value=""[" + variableName + @"]"" />"); - } - - WriteLine(""); - UnindentLevel(); - - WriteLine(""); - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(""); - - } - - // If we created an aggregation variable, emit its results into the actual storage variable - if (needAggregationVariable) - { - string writeOutputFriendlyName = GetFriendlyName(null, typeof(Microsoft.PowerShell.Utility.Activities.WriteOutput)); - GenerateWriteOutputStart(writeOutputFriendlyName, actualAggregatingVariable, extent); - - GeneratePowerShellValue(typeof(PSObject[]), "$" + variableToUse, false, false); - GenerateWriteOutputEnd(writeOutputFriendlyName); - } - - // If we needed a conversion variable, use PowerShellValue to do the conversion - if (needConversionVariable && (! needAggregationVariable)) - { - // We rewrite an assignment such as: "$x += 1" to "$x = $x + 1; $x" so that - // PowerShell returns the new value after assignment. - string assignmentExpression = null; - - if (isAggregatingVariable) - { - assignmentExpression = "$" + actualAggregatingVariable + " + $" + variableToUse; - } - else - { - assignmentExpression = "$" + variableToUse; - } - - GeneratePowerShellValue(variableToUseDefinition.Type, assignmentExpression, false, actualAggregatingVariable); - } - } - - // Map the generic argument type names to their actual types - // For example: - // input: List --- output: {T, string} - private static Dictionary GetGenericTypeMap(Type activityType, Type[] genericTypeArray) - { - if (!activityType.IsGenericType) - { - return null; - } - - var genericTypeMap = new Dictionary(StringComparer.OrdinalIgnoreCase); - var activityTypeDefinition = activityType.GetGenericTypeDefinition(); - var genericParamTypes = activityTypeDefinition.GetGenericArguments(); - - for (int i = 0; i < genericParamTypes.Length; i++) - { - genericTypeMap.Add(genericParamTypes[i].Name, genericTypeArray[i]); - } - - return genericTypeMap; - } - - private Type GetActualPropertyType(Type rawPropertyType, Dictionary genericTypeMap, string parameterName, IScriptExtent extent) - { - Type[] unusedGenericArgumentTypes; - bool isActivityArgument = - IsAssignableFromGenericType(typeof (InArgument<>), rawPropertyType, out unusedGenericArgumentTypes) || - IsAssignableFromGenericType(typeof (InOutArgument<>), rawPropertyType, out unusedGenericArgumentTypes) || - IsAssignableFromGenericType(typeof (OutArgument<>), rawPropertyType, out unusedGenericArgumentTypes); - - Type actualPropertyType = isActivityArgument ? rawPropertyType.GetGenericArguments()[0] : rawPropertyType; - - if (actualPropertyType.IsGenericParameter) - { - // If it's in process of the compilation - // --- 'ResolveGenericParameterType' throws if we cannot find the actual type of the specified generic parameter - // If it's only for validation - // --- 'ResolveGenericParameterType' returns null if we cannot find the actual type of the specified generic parameter, - // in that case, we use the "actualPropertyType" directly - Type parameterType = ResolveGenericParameterType(actualPropertyType, genericTypeMap, parameterName, extent); - actualPropertyType = !this.validateOnly - ? parameterType - : (parameterType ?? actualPropertyType); - } - else if (actualPropertyType.IsGenericType && actualPropertyType.ContainsGenericParameters) - { - // If it's in process of the compilation - // --- 'ResolveTypeWithGenericParameters' throws if we cannot resolve the specified generic type - // If it's only for validation - // --- 'ResolveTypeWithGenericParameters' returns null if we cannot resolve the specified generic type, - // in that case, we use the "actualPropertyType" directly - Type resolvedPropertyType = ResolveTypeWithGenericParameters(actualPropertyType, genericTypeMap, parameterName, extent); - actualPropertyType = !this.validateOnly - ? resolvedPropertyType - : (resolvedPropertyType ?? actualPropertyType); - } - - return actualPropertyType; - } - - // Return the actual type for the generic parameter. - // If "this.ValidateOnly == true", this method returns null when no actual type can be found for the generic parameter - // If "this.ValidateOnly == false", this method throws when no actual type can be found for the generic parameter - private Type ResolveGenericParameterType(Type genericParameter, Dictionary genericTypeMap, string parameterName, IScriptExtent extent) - { - Type actualParameterType = null; - if (genericTypeMap == null || !genericTypeMap.TryGetValue(genericParameter.Name, out actualParameterType)) - { - string errorMsg = String.Format(CultureInfo.InvariantCulture, ActivityResources.GenericParameterTypeNotFound, genericParameter.Name, parameterName); - ReportError("GenericParameterTypeNotFound", errorMsg, extent); - } - - return actualParameterType; - } - - // Resolve the specified generic type that contains generic parameters - // If "this.ValidateOnly == true", this method returns null when the resolution fails - // If "this.ValidateOnly == false", this method throws when the resolution fails - private Type ResolveTypeWithGenericParameters(Type genericPropertyType, Dictionary genericTypeMap, string parameterName, IScriptExtent extent) - { - Type[] genericArguments = genericPropertyType.GetGenericArguments(); - var resolvedArgumentTypes = new List(genericArguments.Length); - - foreach (Type argument in genericArguments) - { - if (argument.IsGenericParameter) - { - Type resolvedParameterType = ResolveGenericParameterType(argument, genericTypeMap, parameterName, extent); - // It's for validation only, and we cannot find the actual type of the specified generic parameter - if (resolvedParameterType == null) { return null; } - resolvedArgumentTypes.Add(resolvedParameterType); - } - else if (argument.IsGenericType && argument.ContainsGenericParameters) - { - Type resolvedGenericArgument = ResolveTypeWithGenericParameters(argument, genericTypeMap, parameterName, extent); - if (resolvedGenericArgument == null) { return null; } - resolvedArgumentTypes.Add(resolvedGenericArgument); - } - else - { - resolvedArgumentTypes.Add(argument); - } - } - - Type resolvedGenericPropertyType = null; - try - { - Type genericTypeDefinition = genericPropertyType.GetGenericTypeDefinition(); - resolvedGenericPropertyType = genericTypeDefinition.MakeGenericType(resolvedArgumentTypes.ToArray()); - } - catch - { - string errorMsg = String.Format(CultureInfo.InvariantCulture, ActivityResources.GenericPropertyTypeNotResolved, genericPropertyType.Name, parameterName); - ReportError("GenericParameterTypeNotFound", errorMsg, extent); - } - - return resolvedGenericPropertyType; - } - - private bool IsParameterAvailable(Type activityType, DynamicActivity activityInstance, string parameterName, bool ignoreAmbiguousMatch, IScriptExtent extent, out Type propertyType) - { - propertyType = null; - try - { - propertyType = GetPropertyType(activityType, activityInstance, ref parameterName, extent); - return propertyType != null; - } - catch (AmbiguousMatchException) - { - // ignore the AmbiguousMatchException. The Activity has two Result parameters. - if (ignoreAmbiguousMatch) - { - return true; - } - - string errorMsg = String.Format(CultureInfo.InvariantCulture, ActivityResources.AmbiguousPropertiesFound, parameterName); - ReportError("AmbiguousParametersFound", errorMsg, extent); - return false; - } - } - - private static bool IsAssignableFromGenericType(Type parentType, Type fromType, out Type[] genericArgumentTypes) - { - genericArgumentTypes = null; - if (!fromType.IsGenericType) { return false; } - - // Check the interfaces - if (CheckInterface(parentType, fromType, out genericArgumentTypes)) { return true; } - - // No match in interfaces, then we check the class hierarchy - return CheckClass(parentType, fromType, out genericArgumentTypes); - } - - private static bool CheckInterface(Type parentType, Type fromType, out Type[] genericArgumentTypes) - { - genericArgumentTypes = null; - var interfaceTypes = fromType.GetInterfaces(); - foreach (var it in interfaceTypes) - { - if (it.IsGenericType) - { - if (it.GetGenericTypeDefinition() == parentType) - { - genericArgumentTypes = it.GetGenericArguments(); - return true; - } - } - } - - return false; - } - - private static bool CheckClass(Type parentType, Type fromType, out Type[] genericArgumentTypes) - { - genericArgumentTypes = null; - if (fromType.GetGenericTypeDefinition() == parentType) - { - genericArgumentTypes = fromType.GetGenericArguments(); - return true; - } - - Type baseType = fromType.BaseType; - if (baseType == null || !baseType.IsGenericType) return false; - - return CheckClass(parentType, baseType, out genericArgumentTypes); - } - - private bool ContainsLanguageElements(string input) - { - if (String.IsNullOrEmpty(input)) - { - return false; - } - - if (input[0] == '\'' && input[input.Length - 1] == '\'') - { - return false; - } - - char[] languageElementIdentifiers = { '`', '$', '(', '@' }; - if (input.IndexOfAny(languageElementIdentifiers) >= 0) - { - return true; - } - - return false; - } - - private void GenerateSymbolicInformation(IScriptExtent extent) - { - // Generate the symbolic metadata for this command call - if (! this.disableSymbolGeneration) - { - string position = String.Format(CultureInfo.InvariantCulture, "{0}:{1}:{2}", extent.StartLineNumber, extent.StartColumnNumber, this.name); - - // Stop storing results into the storage variable - Stack savedStorage = this.resultVariables; - bool savedMergeErrorToOutput = this.mergeErrorToOutput; - - try - { - this.resultVariables = null; - this.mergeErrorToOutput = false; - - Dictionary setHostValueArguments = new Dictionary(StringComparer.OrdinalIgnoreCase); - setHostValueArguments["OtherVariableName"] = new CommandArgumentInfo { Value = "Position", IsLiteral = true }; - setHostValueArguments["Value"] = new CommandArgumentInfo { Value = position, IsLiteral = true }; - - GenerateActivityCall(null, "SetPSWorkflowData", typeof(SetPSWorkflowData), null, setHostValueArguments, null, null, extent); - } - finally - { - this.resultVariables = savedStorage; - this.mergeErrorToOutput = savedMergeErrorToOutput; - } - } - } - - // The list of parameters that need to be ignored. - static List ignoredParameters; - - private static bool IsNotSupportedCommonParameter(string parameterName) - { - return ignoredParameters.Contains(parameterName, StringComparer.OrdinalIgnoreCase); - } - - private void UpdateArgumentsFromPreferenceVariables(Type activityType, Dictionary arguments, DynamicActivity activityInstance) - { - string preferenceVariable = null; - - if (typeof(PSActivity).IsAssignableFrom(activityType)) - { - // Process any of the ubiquitous parameters for PSActivity - - preferenceVariable = "DebugPreference"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable))) - { - SetDebugPreferenceArg(arguments, preferenceVariable); - } - - preferenceVariable = "ErrorActionPreference"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable))) - { - SetErrorActionPreferenceArg(arguments, preferenceVariable); - } - - preferenceVariable = "VerbosePreference"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable))) - { - SetVerbosePreferenceArg(arguments, preferenceVariable); - } - - preferenceVariable = "WarningPreference"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable))) - { - SetWarningActionPreferenceArg(arguments, preferenceVariable); - } - - preferenceVariable = "InformationPreference"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable))) - { - SetInformationActionPreferenceArg(arguments, preferenceVariable); - } - - preferenceVariable = "WhatIfPreference"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable))) - { - CommandArgumentInfo preferenceVariableInfo = new CommandArgumentInfo(); - preferenceVariableInfo.Value = "$" + preferenceVariable; - arguments["WhatIf"] = preferenceVariableInfo; - } - } - else if (typeof(DynamicActivity).IsAssignableFrom(activityType) && (activityInstance != null)) - { - // Process ubiquitous parameters for DynamicActivity if supported. - - preferenceVariable = "VerbosePreference"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable)) && activityInstance.Properties.Contains("Verbose")) - { - SetVerbosePreferenceArg(arguments, preferenceVariable); - } - - preferenceVariable = "DebugPreference"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable)) && activityInstance.Properties.Contains("Debug")) - { - SetDebugPreferenceArg(arguments, preferenceVariable); - } - - preferenceVariable = "ErrorActionPreference"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable)) && activityInstance.Properties.Contains("ErrorAction")) - { - SetErrorActionPreferenceArg(arguments, preferenceVariable); - } - - preferenceVariable = "WarningPreference"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable)) && activityInstance.Properties.Contains("WarningAction")) - { - SetWarningActionPreferenceArg(arguments, preferenceVariable); - } - - preferenceVariable = "InformationPreference"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable)) && activityInstance.Properties.Contains("InformationAction")) - { - SetInformationActionPreferenceArg(arguments, preferenceVariable); - } - } - - // Process any of the ubiquitous parameters for PSRemotingActivity - if (typeof(PSRemotingActivity).IsAssignableFrom(activityType)) - { - // PSSessionApplicationName - preferenceVariable = "PSSessionApplicationName"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable))) - { - CommandArgumentInfo preferenceVariableInfo = new CommandArgumentInfo(); - preferenceVariableInfo.Value = "$" + preferenceVariable; - arguments["PSApplicationName"] = preferenceVariableInfo; - } - - // PSSessionConfigurationName - preferenceVariable = "PSSessionConfigurationName"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable))) - { - CommandArgumentInfo preferenceVariableInfo = new CommandArgumentInfo(); - preferenceVariableInfo.Value = "$" + preferenceVariable; - arguments["PSConfigurationName"] = preferenceVariableInfo; - } - - // PSSessionOption - preferenceVariable = "PSSessionOption"; - if (VariableDefined(preferenceVariable) && (!arguments.ContainsKey(preferenceVariable))) - { - CommandArgumentInfo preferenceVariableInfo = new CommandArgumentInfo(); - preferenceVariableInfo.Value = "$" + preferenceVariable; - arguments["PSSessionOption"] = preferenceVariableInfo; - } - } - } - - private static void SetVerbosePreferenceArg(Dictionary arguments, string preferenceVariable) - { - CommandArgumentInfo preferenceVariableInfo = new CommandArgumentInfo(); - preferenceVariableInfo.Value = "if($" + preferenceVariable + " -eq 'Continue') { $true } else { $false }"; - arguments["Verbose"] = preferenceVariableInfo; - } - - private static void SetDebugPreferenceArg(Dictionary arguments, string preferenceVariable) - { - CommandArgumentInfo preferenceVariableInfo = new CommandArgumentInfo(); - preferenceVariableInfo.Value = "if($" + preferenceVariable + " -eq 'Continue') { $true } else { $false }"; - arguments["Debug"] = preferenceVariableInfo; - } - - private static void SetErrorActionPreferenceArg(Dictionary arguments, string preferenceVariable) - { - SetSimpleActionPreferenceArg("ErrorAction", arguments, preferenceVariable); - } - - private static void SetWarningActionPreferenceArg(Dictionary arguments, string preferenceVariable) - { - SetSimpleActionPreferenceArg("WarningAction", arguments, preferenceVariable); - } - - private static void SetInformationActionPreferenceArg(Dictionary arguments, string preferenceVariable) - { - SetSimpleActionPreferenceArg("InformationAction", arguments, preferenceVariable); - } - - private static void SetSimpleActionPreferenceArg(string preference, Dictionary arguments, string preferenceVariable) - { - CommandArgumentInfo preferenceVariableInfo = new CommandArgumentInfo(); - preferenceVariableInfo.Value = "$" + preferenceVariable; - arguments[preference] = preferenceVariableInfo; - } - - - private Type GetPropertyType(Type activityType, DynamicActivity activityInstance, ref string parameterName, IScriptExtent extent) - { - Dictionary mergedProperties = GetAvailableProperties(activityType, activityInstance); - Type resultType = null; - - // Map their case-insensitive property lookup to the actual property - // name, and do minimal substring matching. - List parameterMatches = new List(); - foreach(string propertyName in mergedProperties.Keys) - { - // Check if it is an exact match. If so, return immediately. - if(String.Equals(propertyName, parameterName, StringComparison.OrdinalIgnoreCase)) - { - resultType = mergedProperties[propertyName]; - parameterName = propertyName; - return resultType; - } - - // Check if it is a substring match. If so, remember which parameters have - // matched and store the result type of the last one. - if(propertyName.StartsWith(parameterName, StringComparison.OrdinalIgnoreCase)) - { - resultType = mergedProperties[propertyName]; - parameterMatches.Add("-" + propertyName); - } - } - - // Verify there were not multiple substring matches - if (parameterMatches.Count > 1) - { - string combinedMatches = String.Join(" ", parameterMatches); - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.AmbiguousParameter, parameterName, combinedMatches); - ReportError("AmbiguousParameter", error, extent); - } - else if(parameterMatches.Count == 1) - { - parameterName = parameterMatches[0].Substring(1); - } - - return resultType; - } - - internal static Dictionary GetAvailableProperties(Type activityType, DynamicActivity activityInstance) - { - Dictionary mergedProperties = new Dictionary(StringComparer.OrdinalIgnoreCase); - - // If this is a dynamic activity, pull the info from activityInstance - if (activityInstance != null) - { - for (int index = 0; index < activityInstance.Properties.Count; index++) - { - string propertyName = activityInstance.Properties[index].Name; - Type propertyType = activityInstance.Properties[index].Type; - mergedProperties[propertyName] = propertyType; - } - } - else - { - // This is a concrete activity - foreach (PropertyInfo property in activityType.GetProperties(BindingFlags.Public | BindingFlags.SetProperty | BindingFlags.Instance)) - { - mergedProperties[property.Name] = property.PropertyType; - } - } - - // Remove the "ID" property, as it is in the Activity base class and will be avoided - // by cmdlets - if (mergedProperties.ContainsKey("Id")) - { - mergedProperties.Remove("Id"); - } - - return mergedProperties; - } - - // Gets properties understood / handled by workflow compilation but not by the activity itself - internal static Dictionary GetVirtualProperties(Type activityType, DynamicActivity activityInstance) - { - if (String.Equals(activityType.FullName, "Microsoft.PowerShell.Core.Activities.ForEachObject", StringComparison.OrdinalIgnoreCase)) - { - return new Dictionary { { "PipelineVariable", typeof(string) } }; - } - else - { - return null; - } - } - - /// - /// Utility to encode an expression so it can be inserted in the generated XAML. - /// - /// The expression to encode - /// - /// If true, the string should be wrapped in quotes to it works - /// like a literal expression. - /// - /// - private string EncodeStringArgument(string bareContent, bool isLiteral) - { - // First, do XAML encoding - bareContent = EncodeStringNonArgument(bareContent, isLiteral); - - // Since this is an argument, escape content (i.e.: '[') to prevent - // the expression from looking like a VB value - var literal = new System.Activities.Expressions.Literal(bareContent); - string literalEncoded = literal.ConvertToString(null); - bareContent = literalEncoded; - - return bareContent; - } - - // Encodes a string so that it can be used directly in XAML. - private string EncodeStringNonArgument(string bareContent, bool isLiteral) - { - bareContent = EncodeStringArgumentLiteral(bareContent, isLiteral); - - // Escape markup extensions - if (bareContent.StartsWith("{", StringComparison.OrdinalIgnoreCase)) - { - bareContent = "{}" + bareContent; - } - - return bareContent; - } - - // Encodes a string so that it can be used directly in XAML. - private string EncodeStringArgumentLiteral(string bareContent, bool isLiteral) - { - StringBuilder encodedString = new StringBuilder(bareContent.Length); - System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings(); - settings.ConformanceLevel = System.Xml.ConformanceLevel.Fragment; - using (var writer = System.Xml.XmlWriter.Create(encodedString, settings)) - { - writer.WriteString(bareContent); - } - - bareContent = encodedString.ToString(); - - bareContent = bareContent.Replace("\r", " "); - bareContent = bareContent.Replace("\n", " "); - bareContent = bareContent.Replace(@"""", """); - - // If the target to assign to is an argument, it expects - // an expression so re-write - // hello - // as - // 'hello' - if (isLiteral) - { - bareContent = bareContent.Replace("'", "''"); - bareContent = "'" + bareContent + "'"; - } - - return bareContent; - } - - private Dictionary GetAndResolveParameters(CommandAst commandAst, bool searchSessionState) - { - StaticBindingResult bindingResult = StaticParameterBinder.BindCommand(commandAst, searchSessionState); - Dictionary convertedParameters = ResolveParameters(bindingResult); - - return convertedParameters; - } - - private Dictionary ResolveParameters(StaticBindingResult parameters) - { - Dictionary convertedParameters = new Dictionary(StringComparer.OrdinalIgnoreCase); - - foreach (string parameterName in parameters.BoundParameters.Keys) - { - CommandArgumentInfo argumentInfo = new CommandArgumentInfo(); - argumentInfo.Value = ProcessCommandArgument(parameters.BoundParameters[parameterName].Value); - argumentInfo.ArgumentAst = parameters.BoundParameters[parameterName].Value; - - if(argumentInfo.Value != null) - { - StringConstantExpressionAst stringAst = parameters.BoundParameters[parameterName].Value as StringConstantExpressionAst; - if (stringAst != null) - { - argumentInfo.OriginalValue = stringAst.Value; - } - else - { - argumentInfo.OriginalValue = parameters.BoundParameters[parameterName].Value.Extent.Text; - } - } - convertedParameters.Add(parameterName, argumentInfo); - } - - return convertedParameters; - } - - object ICustomAstVisitor.VisitCommandExpression(CommandExpressionAst commandExpressionAst) - { - // If this is a unary expression, it will update the variable in-place. Generate an assignment - // statement. - if (commandExpressionAst.Expression is UnaryExpressionAst) - { - return commandExpressionAst.Expression.Visit(this); - } - - // If it is a parenthesized expression, visit what's in the parens - ParenExpressionAst parenExpression = commandExpressionAst.Expression as ParenExpressionAst; - if (parenExpression != null) - { - return parenExpression.Pipeline.Visit(this); - } - - // If this is a method call, throw an error that they should use Inline Script instead. - if (commandExpressionAst.Expression is InvokeMemberExpressionAst) - { - ReportError("MethodInvocationNotSupported", ActivityResources.MethodInvocationNotSupported, commandExpressionAst.Expression.Extent); - } - - // If this is a sub expression, throw an error that they should use Inline Script instead. - if (commandExpressionAst.Expression is SubExpressionAst) - { - ReportError("SubExpressionNotSupported", ActivityResources.SubExpressionNotSupported, commandExpressionAst.Expression.Extent); - } - - // If this is an attributed expression, throw an error that they should use attribute expression only when declaring parameters for the script workflow - if ((commandExpressionAst.Expression is AttributedExpressionAst) && - (! (commandExpressionAst.Expression is ConvertExpressionAst))) - { - ReportError("AttributedExpressionNotSupported", ActivityResources.AttributedExpressionNotSupported, commandExpressionAst.Expression.Extent); - } - - if (commandExpressionAst.Redirections.Count > 0) - { - foreach (RedirectionAst redirection in commandExpressionAst.Redirections) - { - redirection.Visit(this); - } - - this.mergeErrorToOutput = true; - } - - // They've done a simple variable reference. - - // Ensure it has no side-effects, as we aren't capturing them. - string nameOfUnSupportedVariableFound = null; - if (CheckIfExpressionHasUnsupportedVariableOrHasSideEffects(null, commandExpressionAst, out nameOfUnSupportedVariableFound)) - { - if (string.IsNullOrEmpty(nameOfUnSupportedVariableFound)) - { - string errorTemplate = ActivityResources.CannotStoreResultsInUnsupportedElement; - ReportError("CannotStoreResultsInUnsupportedElement", - ActivityResources.CannotStoreResultsInUnsupportedElement, - commandExpressionAst.Expression.Extent); - } - else - { - string error = String.Format(CultureInfo.InvariantCulture, - ActivityResources.VariableNotSupportedInWorkflow, - nameOfUnSupportedVariableFound); - ReportError("VariableNotSupportedInWorkflow", error, commandExpressionAst.Expression.Extent); - } - } - - try - { - var currentVariable = GetVariableToUse(); - string variableToUse = null; - bool isAggregatingVariable = false; - if (currentVariable != null) - { - variableToUse = currentVariable.VariableName; - isAggregatingVariable = currentVariable.IsAggregatingVariable; - } - - // They're accessing the $input variable. Convert it to a simple call to Write-Output, which will - // pick up the input stream from the parameter defaults. - // We ignore error redirection in this case - VariableExpressionAst inputVariable = commandExpressionAst.Expression as VariableExpressionAst; - string writeOutputFriendlyName = GetFriendlyName(null, typeof(Microsoft.PowerShell.Utility.Activities.WriteOutput)); - if (inputVariable != null) - { - if (String.Equals("input", inputVariable.VariablePath.UserPath, StringComparison.OrdinalIgnoreCase)) - { - if (String.IsNullOrEmpty(variableToUse)) - { - WriteLine(String.Format(CultureInfo.InvariantCulture, "<{0} UseDefaultInput=\"true\" />", writeOutputFriendlyName)); - } - else - { - string appendOutput = isAggregatingVariable ? AppendOutputTemplate : string.Empty; - WriteLine(String.Format(CultureInfo.InvariantCulture, "<{0} UseDefaultInput=\"true\" Result = \"[{1}]\"{2} />", writeOutputFriendlyName, variableToUse, appendOutput)); - } - return null; - } - } - - // If we aren't storing an assignment, then add a call to Write-Output so that - // it can be sent to the output stream. - bool isOutputExpression = isAggregatingVariable || String.IsNullOrEmpty(variableToUse); - - // Generate the outer call to WriteOutput - Type variableType = null; - if (isOutputExpression) - { - // Otherwise, make the following value the input object of the - // Write-Output activity. - variableType = typeof(PSObject[]); - GenerateWriteOutputStart(writeOutputFriendlyName, variableToUse, commandExpressionAst.Extent); - } - else - { - variableType = GetVariableDefinition(variableToUse).Type; - } - - // Evaluate the expression - string expression = GetPowerShellValueExpression(commandExpressionAst.Expression); - GeneratePowerShellValue(variableType, expression, false, true); - - // Complete the outer call to WriteObject - if (isOutputExpression) - { - GenerateWriteOutputEnd(writeOutputFriendlyName); - } - } - finally - { - this.mergeErrorToOutput = false; - } - - return null; - } - - private void GenerateWriteOutputStart(string writeOutputFriendlyName, string storageScopeVariable, IScriptExtent extent) - { - GenerateSymbolicInformation(extent); - - Type inputType = typeof(PSObject[]); - string convertedTypeName = GetConvertedTypeName(inputType); - - if (String.IsNullOrEmpty(storageScopeVariable)) - { - WriteLine("<" + writeOutputFriendlyName + ">"); - } - else - { - WriteLine(String.Format(CultureInfo.InvariantCulture, "<{0} Result = \"[{1}]\"{2} >", writeOutputFriendlyName, storageScopeVariable, AppendOutputTemplate)); - } - IndentLevel(); - - WriteLine("<" + writeOutputFriendlyName + ".NoEnumerate>[System.Management.Automation.SwitchParameter.Present]"); - WriteLine("<" + writeOutputFriendlyName + ".InputObject>"); - IndentLevel(); - - // Assign the value to the InputObject argument - string template = @""; - WriteLine(String.Format(CultureInfo.InvariantCulture, template, convertedTypeName)); - IndentLevel(); - } - - private void GenerateWriteOutputEnd(string writeOutputFriendlyName) - { - UnindentLevel(); - - WriteLine(""); - UnindentLevel(); - - WriteLine(""); - UnindentLevel(); - - WriteLine(""); - } - - object ICustomAstVisitor.VisitCommandParameter(CommandParameterAst commandParameterAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitSwitchStatement(SwitchStatementAst switchStatementAst) - { - Type switchType = typeof(object); - - // Figure out the type of the switch statement by examining its expression (first), or - // its clauses (second). We need a strongly-typed switch statement, as workflow uses - // a hashtable lookup to determine condition hits. - ExpressionAst conditionExpressionAst = switchStatementAst.Condition.GetPureExpression(); - if (conditionExpressionAst != null) - { - switchType = conditionExpressionAst.StaticType; - } - - // Elevate ints to doubles so that the WF switch can handle the conversion - if ((switchType == typeof(int)) || - (switchType == typeof(Int32)) || - (switchType == typeof(UInt32))) - { - switchType = typeof(double); - } - - if ((switchType == typeof(object)) || - (!IsSupportedSwitchExpressionType(switchType)) - ) - { - switchType = null; - - foreach (Tuple switchClause in switchStatementAst.Clauses) - { - // Verify they've typed a literal (i.e.: integer, string) - ConstantExpressionAst key = switchClause.Item1 as ConstantExpressionAst; - if (key == null) - { - ReportError("SwitchOnlySupportsConstantExpression", ActivityResources.SwitchOnlySupportsConstantExpression, switchClause.Item1.Extent); - return null; - } - - if (switchType == null) - { - switchType = key.StaticType; - } - else - { - // Validate they only have one key type - if (key.StaticType != switchType) - { - ReportError("SwitchClauseMustBeOfSameType", ActivityResources.SwitchClauseMustBeOfSameType, key.Extent); - } - } - } - } - - if (switchType == null) - { - switchType = typeof(object); - } - - // Generic flag errors - if ( - ((switchStatementAst.Flags & SwitchFlags.Regex) == SwitchFlags.Regex) || - ((switchStatementAst.Flags & SwitchFlags.Wildcard) == SwitchFlags.Wildcard) || - ((switchStatementAst.Flags & SwitchFlags.File) == SwitchFlags.File) || - ((switchStatementAst.Flags & SwitchFlags.Parallel) == SwitchFlags.Parallel)) - { - ReportError("SwitchFlagNotSupported", ActivityResources.SwitchFlagNotSupported, switchStatementAst.Extent); - } - - // Validate any parameters to the switch statement - if ((switchType == typeof(string)) || (switchType == typeof(char))) - { - if ((switchStatementAst.Flags & SwitchFlags.CaseSensitive) != SwitchFlags.CaseSensitive) - { - ReportError("SwitchCaseSensitive", ActivityResources.SwitchCaseSensitive, switchStatementAst.Extent); - } - } - - GenerateSymbolicInformation(switchStatementAst.Extent); - - // Generate a temporary variable for the switch condition - string tempVarName = GenerateUniqueVariableName("SwitchCondition"); - Type conditionType = DetectType(tempVarName, false, switchStatementAst.Condition); - DefineVariable(tempVarName, conditionType, switchStatementAst.Condition.Extent, null); - - // Generate the assignment of the the clause to the temporary variable - string conditionExpression = GetPowerShellValueExpression(switchStatementAst.Condition); - GenerateAssignment(tempVarName, switchStatementAst.Condition.Extent, TokenKind.Equals, switchStatementAst.Condition, conditionExpression); - - - string switchTypeFriendlyName = GetConvertedTypeName(switchType); - WriteLine(@""); - IndentLevel(); - - WriteLine(""); - IndentLevel(); - - WriteLine(@""); - IndentLevel(); - - // Evaluate the switch expression - string errorMessage = ActivityResources.SwitchEnumerationNotSupported; - string switchExpressionTemplate = "$switchCondition = ${0}; if(@($switchCondition).Count -gt 1) {{ throw '{1}' }}; $switchCondition"; - string switchConditionExpression = String.Format(CultureInfo.InvariantCulture, switchExpressionTemplate, tempVarName, errorMessage); - GeneratePowerShellValue(switchType, switchConditionExpression, false, false); - - UnindentLevel(); - WriteLine(""); - - UnindentLevel(); - WriteLine(""); - - if (switchStatementAst.Default != null) - { - WriteLine(""); - IndentLevel(); - - WriteLine(""); - IndentLevel(); - - switchStatementAst.Default.Visit(this); - - UnindentLevel(); - WriteLine(""); - - UnindentLevel(); - WriteLine(""); - } - - foreach (Tuple switchClause in switchStatementAst.Clauses) - { - // Verify they've typed a literal (i.e.: integer, string) - ConstantExpressionAst key = switchClause.Item1 as ConstantExpressionAst; - if (key == null) - { - ReportError("SwitchOnlySupportsConstantExpression", ActivityResources.SwitchOnlySupportsConstantExpression, switchClause.Item1.Extent); - return null; - } - string switchKey = key.Value.ToString(); - - WriteLine(@""); - IndentLevel(); - - switchClause.Item2.Visit(this); - - UnindentLevel(); - WriteLine(""); - } - - UnindentLevel(); - WriteLine(""); - - return null; - } - - private bool IsSupportedSwitchExpressionType(Type switchType) - { - bool isSupportedSwitchExpressionType = - switchType.IsPrimitive || - (switchType == typeof(string)); - - return isSupportedSwitchExpressionType; - } - - object ICustomAstVisitor.VisitDataStatement(DataStatementAst dataStatementAst) - { - ReportError("DataSectionNotSupported", ActivityResources.DataSectionNotSupported, dataStatementAst.Extent); - return null; - } - - object ICustomAstVisitor.VisitForEachStatement(ForEachStatementAst forEachStatementAst) - { - if (!String.IsNullOrEmpty(forEachStatementAst.Label)) - { - ReportError("LoopLabelNotSupported", ActivityResources.LoopLabelNotSupported, forEachStatementAst.Extent); - } - - GenerateSymbolicInformation(forEachStatementAst.Extent); - - // Generate a temporary variable for the foreach condition - string tempVarName = GenerateUniqueVariableName("ForeachCondition"); - Type conditionType = DetectType(tempVarName, false, forEachStatementAst.Condition); - DefineVariable(tempVarName, conditionType, forEachStatementAst.Condition.Extent, null); - - // Generate the assignment of the the clause to the temporary variable - string conditionExpression = GetPowerShellValueExpression(forEachStatementAst.Condition); - GenerateAssignment(tempVarName, forEachStatementAst.Condition.Extent, TokenKind.Equals, forEachStatementAst.Condition, conditionExpression); - - // Clear the storage variable if there is one - if(forEachStatementAst.Parent is AssignmentStatementAst) - { - StorageVariable currentVariable = GetVariableToUse(); - GeneratePowerShellValue(conditionType, "$null", false, currentVariable.VariableName); - } - - // Check if this is a parallel foreach. If so, update the activity name. - string activityName = "ForEach"; - bool isParallel = false; - - if ((forEachStatementAst.Flags & ForEachFlags.Parallel) == ForEachFlags.Parallel) - { - activityName = GetFriendlyName(null, typeof(ThrottledParallelForEach)); - isParallel = true; - } - - WriteLine("<" + activityName + @" x:TypeArguments=""x:Object"">"); - IndentLevel(); - - WriteLine("<" + activityName + ".Values>"); - IndentLevel(); - - Type resultType = typeof(IEnumerable); - string convertedTypeName = GetConvertedTypeName(resultType); - - WriteLine(@""); - IndentLevel(); - - // Evaluate the expression for the ForEach values. We force this to evaluate as a list so that we - // can be guaranteed to iterate over it. - string expression = "$foreachIterator = $" + tempVarName + "; if($null -eq $foreachIterator) { ,@() } else { ,@($foreachIterator) }"; - GeneratePowerShellValue(resultType, expression, false, false); - - UnindentLevel(); - WriteLine(""); - - UnindentLevel(); - WriteLine(""); - - // Generate throttle limit if specified - if (isParallel && (forEachStatementAst.ThrottleLimit != null)) - { - WriteLine("<" + activityName + ".ThrottleLimit>"); - IndentLevel(); - - resultType = typeof(int); - convertedTypeName = GetConvertedTypeName(resultType); - - WriteLine(@""); - IndentLevel(); - - GeneratePowerShellValue(typeof(int), forEachStatementAst.ThrottleLimit.Extent.Text, false, false); - - UnindentLevel(); - WriteLine(""); - - UnindentLevel(); - WriteLine(""); - } - - // Generate the index variable - WriteLine(@""); - IndentLevel(); - - WriteLine(""); - IndentLevel(); - - // Convert their variable name to the original case if needed - string variableName = forEachStatementAst.Variable.VariablePath.ToString(); - VariableDefinition existingVariableDefinition = GetVariableDefinition(variableName); - if (existingVariableDefinition != null) - { - variableName = existingVariableDefinition.Name; - } - - WriteLine(@""); - - UnindentLevel(); - WriteLine(""); - - // Generate the Try/Catch block to capture all terminating errors - // so that that terminating error won't terminate other branches - if (isParallel) - { - AddTryCatchForParallelStart(); - } - - // And the statement body - WriteLine(""); - IndentLevel(); - - if (isParallel) - { - EnterScope(); - } - - try - { - forEachStatementAst.Body.Visit(this); - } - finally - { - if (isParallel) - { - DumpVariables("Sequence"); - LeaveScope(); - } - - UnindentLevel(); - WriteLine(""); - - // Finish the Try/Catch block that is to capture all terminating errors - if (isParallel) - { - AddTryCatchForParallelEnd(); - } - - UnindentLevel(); - WriteLine(@""); - - UnindentLevel(); - WriteLine(""); - } - - return null; - } - - object ICustomAstVisitor.VisitDoWhileStatement(DoWhileStatementAst doWhileStatementAst) - { - if (!String.IsNullOrEmpty(doWhileStatementAst.Label)) - { - ReportError("LoopLabelNotSupported", ActivityResources.LoopLabelNotSupported, doWhileStatementAst.Extent); - } - - GenerateSymbolicInformation(doWhileStatementAst.Extent); - GenerateLoop(doWhileStatementAst.Condition, doWhileStatementAst.Body, null, "DoWhile", false); - return null; - } - - object ICustomAstVisitor.VisitForStatement(ForStatementAst forStatementAst) - { - if (!String.IsNullOrEmpty(forStatementAst.Label)) - { - ReportError("LoopLabelNotSupported", ActivityResources.LoopLabelNotSupported, forStatementAst.Extent); - } - - // We compile a 'for' statement into a while statement. - // for(; ; ) { } - // Converts to: - // - // while() { ; } - - GenerateSymbolicInformation(forStatementAst.Extent); - - // Visit the initializer - if (forStatementAst.Initializer != null) - { - forStatementAst.Initializer.Visit(this); - } - - // Generate the loop - GenerateLoop(forStatementAst.Condition, forStatementAst.Body, forStatementAst.Iterator, "While", false); - - return null; - } - - object ICustomAstVisitor.VisitWhileStatement(WhileStatementAst whileStatementAst) - { - if (!String.IsNullOrEmpty(whileStatementAst.Label)) - { - ReportError("LoopLabelNotSupported", ActivityResources.LoopLabelNotSupported, whileStatementAst.Extent); - } - - GenerateSymbolicInformation(whileStatementAst.Extent); - GenerateLoop(whileStatementAst.Condition, whileStatementAst.Body, null, "While", false); - return null; - } - - private void GenerateLoop(PipelineBaseAst condition, StatementBlockAst body, PipelineBaseAst iterator, string whileType, bool isUntil) - { - // Check if the condition itself contains side-effects. If so, generate an error. - string nameOfUnSupportedVariableFound; - if ((condition != null) && CheckIfExpressionHasUnsupportedVariableOrHasSideEffects(null, condition, out nameOfUnSupportedVariableFound)) - { - if (string.IsNullOrEmpty(nameOfUnSupportedVariableFound)) - { - string errorTemplate = ActivityResources.ConditionsCannotHaveSideEffects; - ReportError("ConditionsCannotHaveSideEffects", errorTemplate, condition.Extent); - } - else - { - string error = String.Format(CultureInfo.InvariantCulture, - ActivityResources.VariableNotSupportedInWorkflow, - nameOfUnSupportedVariableFound); - ReportError("VariableNotSupportedInWorkflow", error, condition.Extent); - } - } - - // Check if the condition contains a command call. If so, generate an error - if ((condition != null) && AstContainsCommandCall(condition, null)) - { - string errorTemplate = ActivityResources.ConditionsCannotInvokeActivities; - ReportError("ConditionsCannotInvokeActivities", errorTemplate, condition.Extent); - } - - WriteLine(String.Format(CultureInfo.InvariantCulture, "<{0}>", whileType)); - IndentLevel(); - - WriteLine(String.Format(CultureInfo.InvariantCulture, "<{0}.Condition>", whileType)); - IndentLevel(); - - // Get a default condition if needed - string conditionExpression = null; - if (condition == null) - { - conditionExpression = "$true"; - } - else - { - conditionExpression = GetPowerShellValueExpression(condition); - } - - // If this is an 'until' loop, negate the condition - if (isUntil) - { - conditionExpression = "-not (" + conditionExpression + ")"; - } - - // Evaluate the PowerShell value of the condition - GeneratePowerShellValue(typeof(bool), conditionExpression, false, false); - - UnindentLevel(); - WriteLine(String.Format(CultureInfo.InvariantCulture, "", whileType)); - - WriteLine(""); - IndentLevel(); - - body.Visit(this); - if (iterator != null) - { - iterator.Visit(this); - } - - UnindentLevel(); - WriteLine(""); - - UnindentLevel(); - WriteLine(String.Format(CultureInfo.InvariantCulture, "", whileType)); - } - - private static bool AstContainsCommandCall(PipelineBaseAst condition, HashSet allowedCommands) - { - Func searcher = (ast) => - { - CommandAst command = ast as CommandAst; - if (command == null) - { - return false; - } - - if (allowedCommands == null) - return true; - - var commandName = command.GetCommandName(); - return commandName == null || !allowedCommands.Contains(commandName); - }; - - Ast result = condition.Find(searcher, searchNestedScriptBlocks: true); - return result != null; - } - - object ICustomAstVisitor.VisitCatchClause(CatchClauseAst catchClauseAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitTryStatement(TryStatementAst tryStatementAst) - { - GenerateSymbolicInformation(tryStatementAst.Extent); - - string exceptionToRethrowName = GenerateUniqueVariableName("__ExceptionToRethrow"); - string exceptionTypeFriendlyName = GetConvertedTypeName(typeof(Exception)); - - // In Workflow, try / catch / finally acts unlike any other common language. - // The Finally block is only processed if the try block is fully processed, - // or one of its catch clauses are fully processed. - // To work around this, we need to wrap the try / catch in another try / catch - // and rethrow it in the finally clause if one is there. - if (tryStatementAst.Finally != null) - { - // Create the exceptionToRethrow variable - if (!VariableDefinedInCurrentScope(exceptionToRethrowName)) - { - DefineVariable(exceptionToRethrowName, typeof(Exception), tryStatementAst.Finally.Extent, null); - } - - WriteLine(""); - IndentLevel(); - WriteLine(""); - IndentLevel(); - } - - // Generate the original try - WriteLine(""); - IndentLevel(); - WriteLine(""); - IndentLevel(); - - // Generate an inner Try/Catch that can unwrap the RuntimeExceptions that we - // get from remoting. - WriteLine(""); - IndentLevel(); - WriteLine(""); - - IndentLevel(); - WriteLine(""); - IndentLevel(); - - tryStatementAst.Body.Visit(this); - - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(""); - WriteLine(""); - IndentLevel(); - Type runtimeExceptionType = typeof(RuntimeException); - string runtimeExceptionTypeFriendlyName = GetConvertedTypeName(runtimeExceptionType); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(@""); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(@""); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(@""); - - UnindentLevel(); - WriteLine(""); - - UnindentLevel(); - WriteLine(""); - - UnindentLevel(); - WriteLine(""); - - // Generate the catches - if (tryStatementAst.CatchClauses.Count > 0) - { - WriteLine(""); - IndentLevel(); - string friendlyTypeName = string.Empty; - - if (hasControlFlowException) - { - friendlyTypeName = GetConvertedTypeName(typeof(Microsoft.PowerShell.Workflow.WorkflowReturnException)); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(@""); - WriteLine(@""); - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(@""); - } - - foreach (CatchClauseAst catchClause in tryStatementAst.CatchClauses) - { - List catchTypes = new List(); - - if (catchClause.IsCatchAll) - { - catchTypes.Add(typeof(System.Exception)); - } - else - { - foreach (TypeConstraintAst catchType in catchClause.CatchTypes) - { - Type reflectionType = catchType.TypeName.GetReflectionType(); - if (reflectionType != null) - { - catchTypes.Add(reflectionType); - } - else - { - string error = String.Format(CultureInfo.InvariantCulture, ActivityResources.NewObjectCouldNotFindType, catchType.TypeName); - ReportError("ExceptionTypeNotFound", error, tryStatementAst.Extent); - } - } - } - - foreach (Type actualType in catchTypes) - { - friendlyTypeName = GetConvertedTypeName(actualType); - - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(@""); - - - WriteLine(""); - IndentLevel(); - - catchClause.Body.Visit(this); - - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - - WriteLine(""); - UnindentLevel(); - WriteLine(@""); - } - } - - UnindentLevel(); - WriteLine(""); - } - - // Generate the finally - if (tryStatementAst.Finally != null) - { - // Close the original try / catch. Since we're bringing the original - // finally into a new catch statement, we need to synthesize a dummy one here. - if (tryStatementAst.CatchClauses.Count == 0) - { - WriteLine(""); - } - - UnindentLevel(); - WriteLine(""); - - // Now add our catch statement to emulate a real finally block - UnindentLevel(); - WriteLine(""); - WriteLine(""); - IndentLevel(); - - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - // Store the variable we caught - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(@""); - - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - WriteLine(@"[" + exceptionToRethrowName + @"]"); - UnindentLevel(); - WriteLine(@""); - WriteLine(@""); - IndentLevel(); - WriteLine(@"[__UnhandledException]"); - UnindentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(@""); - - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(""); - - WriteLine(""); - IndentLevel(); - WriteLine(""); - IndentLevel(); - - tryStatementAst.Finally.Visit(this); - - // Rethrow any exception we may have eaten - WriteLine(@""); - IndentLevel(); - WriteLine(""); - IndentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(""); - - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(""); - } - - UnindentLevel(); - WriteLine(""); - - return null; - } - - object ICustomAstVisitor.VisitBreakStatement(BreakStatementAst breakStatementAst) - { - ReportError("BreakContinueNotSupported", ActivityResources.BreakContinueNotSupported, breakStatementAst.Extent); - return null; - } - - object ICustomAstVisitor.VisitContinueStatement(ContinueStatementAst continueStatementAst) - { - ReportError("BreakContinueNotSupported", ActivityResources.BreakContinueNotSupported, continueStatementAst.Extent); - return null; - } - - object ICustomAstVisitor.VisitReturnStatement(ReturnStatementAst returnStatementAst) - { - if (returnStatementAst.Pipeline != null) - { - returnStatementAst.Pipeline.Visit(this); - } - - // Throw a hard-coded exception here. Our global exception handler catches this and exits quietly. - WriteLine(@""); - this.hasControlFlowException = true; - - return null; - } - - object ICustomAstVisitor.VisitExitStatement(ExitStatementAst exitStatementAst) - { - // Throw a hard-coded exception here. Our global exception handler catches this and exits quietly. - WriteLine(@""); - this.hasControlFlowException = true; - - return null; - } - - object ICustomAstVisitor.VisitThrowStatement(ThrowStatementAst throwStatementAst) - { - GenerateSymbolicInformation(throwStatementAst.Extent); - - Type exceptionType = typeof(System.Exception); - bool isInParallelBlock = IsThrowStatementInParallelBlock(throwStatementAst); - - if (throwStatementAst.IsRethrow) - { - if (isInParallelBlock) - { - // Define the temp variable - string rethrowExceptionName = GenerateUniqueVariableName("__RethrowException"); - if (!VariableDefinedInCurrentScope(rethrowExceptionName)) - { - DefineVariable(rethrowExceptionName, exceptionType, throwStatementAst.Extent, null); - } - - try - { - // Generate the exception and assign it to the 'rethrowExceptionName' variable - EnterStorage(rethrowExceptionName, false); - GeneratePowerShellValue(exceptionType, "$_", false, true); - } - finally - { - LeaveStorage(); - } - - // Check if the exception is thrown by the 'Throw' statement. If not, add the special key-value pair to - // the 'Data' property. Then we re-throw the exception. - GenerateXamlForThrowStatement(rethrowExceptionName, isRethrow: true); - } - else - { - WriteLine(""); - } - } - else - { - if (throwStatementAst.Pipeline == null) - { - ReportError("ReasonRequiredInThrowStatement", ActivityResources.ReasonRequiredInThrowStatement, throwStatementAst.Extent); - return null; - } - - // Verify it's not a pipeline with commands - HashSet allowedCommands = new HashSet(StringComparer.OrdinalIgnoreCase) { "New-Object", "new" }; - if (AstContainsCommandCall(throwStatementAst.Pipeline, allowedCommands)) - { - string errorTemplate = ActivityResources.ThrowStatementCannotInvokeActivities; - ReportError("ThrowStatementCannotInvokeActivities", errorTemplate, throwStatementAst.Pipeline.Extent); - } - - if (isInParallelBlock) - { - // Define the temp variable - string throwExceptionName = GenerateUniqueVariableName("__ThrowException"); - if (!VariableDefinedInCurrentScope(throwExceptionName)) - { - DefineVariable(throwExceptionName, exceptionType, throwStatementAst.Pipeline.Extent, null); - } - - try - { - // Generate the exception and assign it to the 'throwExceptionName' variable - EnterStorage(throwExceptionName, false); - string expression = GetPowerShellValueExpression(throwStatementAst.Pipeline); - GeneratePowerShellValue(exceptionType, expression, false, true); - } - finally - { - LeaveStorage(); - } - - // Check if the exception is thrown by the 'Throw' statement. If not, add the special key-value pair to - // the 'Data' property. Then we throw the exception. - GenerateXamlForThrowStatement(throwExceptionName, isRethrow: false); - } - else - { - string exceptionTypeFriendlyName = GetConvertedTypeName(exceptionType); - - WriteLine(""); - IndentLevel(); - - WriteLine(""); - IndentLevel(); - - WriteLine(@""); - IndentLevel(); - - string expression = GetPowerShellValueExpression(throwStatementAst.Pipeline); - GeneratePowerShellValue(exceptionType, expression, false, false); - - UnindentLevel(); - WriteLine(""); - - UnindentLevel(); - WriteLine(""); - - UnindentLevel(); - WriteLine(""); - } - } - - return null; - } - - /// - /// Check if the 'Throw' statement is in a parallel block - /// - /// - /// - private static bool IsThrowStatementInParallelBlock(ThrowStatementAst throwStatementAst) - { - var parent = throwStatementAst.Parent; - while (parent != null) - { - var blockStatementAst = parent as BlockStatementAst; - if (blockStatementAst != null) - { - if (blockStatementAst.Kind.Kind == TokenKind.Parallel) - { - return true; - } - } - else - { - var forEachStatementAst = parent as ForEachStatementAst; - if (forEachStatementAst != null && (forEachStatementAst.Flags & ForEachFlags.Parallel) == ForEachFlags.Parallel) - { - return true; - } - } - - parent = parent.Parent; - } - - return false; - } - - /// - /// Generate the XAML for the 'Throw' statement - /// - /// - /// - private void GenerateXamlForThrowStatement(string variableName, bool isRethrow) - { - // Add a special key value pair to the Data property of the exception, so that we know it's thrown by the 'Throw' statement - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - - AddOrRemoveSpecialKey(variableName, addKey: true); - - UnindentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(@""); - - if (isRethrow) - { - WriteLine(@""); - } - else - { - WriteLine(@""); - } - } - - /// - /// Add or remove the special key-value pair to/from the exception - /// - /// - /// - private void AddOrRemoveSpecialKey(string variableName, bool addKey) - { - string iDictionaryTypeFriendlyName = GetConvertedTypeName(typeof(System.Collections.IDictionary)); - string objectTypeFriendlyName = GetConvertedTypeName(typeof(object)); - string method = addKey ? "Add" : "Remove"; - - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - WriteLine(@"[" + variableName + @".Data]"); - UnindentLevel(); - WriteLine(@""); - WriteLine(@"[""" + M3PKeyForThrowStatement + @"""]"); - - if (addKey) - { - WriteLine(@"[""""]"); - } - - UnindentLevel(); - WriteLine(@""); - } - - /// - /// Start to add the Try/Catch block for the parallel statement/block - /// - private void AddTryCatchForParallelStart() - { - WriteLine(""); - IndentLevel(); - WriteLine(""); - IndentLevel(); - } - - /// - /// Finish the Try/Catch block for the parallel statement/block - /// - private void AddTryCatchForParallelEnd() - { - UnindentLevel(); - WriteLine(""); - WriteLine(""); - IndentLevel(); - - string exceptionTypeFriendlyName = GetConvertedTypeName(typeof(Exception)); - string writeErrorFriendlyName = GetFriendlyName(null, typeof(Microsoft.PowerShell.Utility.Activities.WriteError)); - - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(@""); - WriteLine(@""); - IndentLevel(); - WriteLine(@""); - IndentLevel(); - - WriteLine(@""); - IndentLevel(); - AddOrRemoveSpecialKey("__UnhandledException", addKey: false); // Remove the special key-value pair - WriteLine(@""); // Rethrow the exception if it was thrown by the 'Throw' statement - UnindentLevel(); - WriteLine(@""); - - UnindentLevel(); - WriteLine(@""); - WriteLine(@""); - IndentLevel(); - WriteLine(@"<" + writeErrorFriendlyName + @" Exception=""[__UnhandledException]"" />"); // Otherwise, write to the error stream - UnindentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(@""); - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(@""); - - UnindentLevel(); - WriteLine(""); - UnindentLevel(); - WriteLine(""); - } - - object ICustomAstVisitor.VisitVariableExpression(VariableExpressionAst variableExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitDoUntilStatement(DoUntilStatementAst doUntilStatementAst) - { - if (!String.IsNullOrEmpty(doUntilStatementAst.Label)) - { - ReportError("LoopLabelNotSupported", ActivityResources.LoopLabelNotSupported, doUntilStatementAst.Extent); - } - - GenerateSymbolicInformation(doUntilStatementAst.Extent); - GenerateLoop(doUntilStatementAst.Condition, doUntilStatementAst.Body, null, "DoWhile", true); - return null; - } - - object ICustomAstVisitor.VisitMemberExpression(MemberExpressionAst memberExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitInvokeMemberExpression(InvokeMemberExpressionAst invokeMemberExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitArrayExpression(ArrayExpressionAst arrayExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitArrayLiteral(ArrayLiteralAst arrayLiteralAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitHashtable(HashtableAst hashtableAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitScriptBlockExpression(ScriptBlockExpressionAst scriptBlockExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitParenExpression(ParenExpressionAst parenExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitExpandableStringExpression(ExpandableStringExpressionAst expandableStringExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitIndexExpression(IndexExpressionAst indexExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitBlockStatement(BlockStatementAst blockStatementAst) - { - GenerateSymbolicInformation(blockStatementAst.Extent); - - bool isParallelBlock = String.Equals(blockStatementAst.Kind.Text, TokenKind.Parallel.Text(), StringComparison.OrdinalIgnoreCase); - string containerType = isParallelBlock ? "Parallel" : "Sequence"; - WriteLine("<" + containerType + ">"); - IndentLevel(); - EnterScope(); - - try - { - blockStatementAst.Body.Visit(this); - } - finally - { - DumpVariables(containerType); - LeaveScope(); - - UnindentLevel(); - WriteLine(""); - } - - return null; - } - - object ICustomAstVisitor.VisitAttributedExpression(AttributedExpressionAst attributedExpressionAst) - { - throw new NotSupportedException(); - } - - object ICustomAstVisitor.VisitNamedAttributeArgument(NamedAttributeArgumentAst namedAttributeArgumentAst) - { - throw new NotSupportedException(); - } - - private void ReportError(string errorId, string errorText, IScriptExtent extent) - { - _parseErrors.Add(new ParseError(extent, errorId, errorText)); - - if (!this.ValidateOnly) - { - throw new ParseException(_parseErrors.ToArray()); - } - } - - private int uniqueVariableDisambiguator = 0; - private string GenerateUniqueVariableName(string basename) - { - return basename + "_" + (this.uniqueVariableDisambiguator++).ToString(CultureInfo.InvariantCulture); - } - - internal enum ActivityKind - { - /// - /// Delay activity - /// - Delay = 0, - - /// - /// An InlineScript activity - /// - InlineScript = 1, - - /// - /// Xaml injection activity. inline XAML - /// - InvokeExpression = 2, - - /// - /// New-Object activity - /// - NewObject = 3, - - /// - /// Persist activity - /// - Persist = 4, - - /// - /// Other command activity - /// - RegularCommand = 5, - - /// - /// Suspend activity - /// - Suspend = 6, - } - - private enum IterativeCommands - { - None = 0, - ForEachSequence, - WhereSequence - } - } - - class CommandArgumentInfo - { - internal object Value { get; set; } - internal object OriginalValue { get; set; } - internal Ast ArgumentAst { get; set; } - internal bool IsLiteral { get; set; } - } - - class VariableScope - { - internal VariableScope() - { - Variables = new Dictionary(StringComparer.OrdinalIgnoreCase); - } - - internal Dictionary Variables { get; set; } - } - - class StorageVariable - { - internal StorageVariable(string variableName, bool isAggregatingVariable) - { - if (string.IsNullOrEmpty(variableName)) - { - // caller needs to make sure the argument is not null or empty - throw new PSArgumentNullException(variableName); - } - - IsAggregatingVariable = isAggregatingVariable; - VariableName = variableName; - } - - /// - /// This indicates if the variable is one that will aggregate results from a parallel/sequence/foreach block. - /// For example: - /// workflow bar { $a = parallel { Get-Process -Name powershell; Get-Service -Name Dhcp } } - /// $a here will contain all results generated from the parallel block, including a process object "powershell" - /// and a service object "Dhcp". We call $a an aggregating variable. - /// - internal bool IsAggregatingVariable { get; set; } - internal string VariableName { get; private set; } - } - - class VariableDefinition - { - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal string Name { get; set; } - internal string XamlDefinition { get; set; } - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Type Type { get; set; } - } - - /// - /// Used by Script->Xaml converter to give compile time error - /// for variables that are not supported in a workflow context. - /// - internal enum PSWorkflowUnsupportedVariable - { - Args = 0, - Error = 1, - MyInvocation = 2, - PSBoundParameters = 3, - PSCmdlet = 4, - PSCommandPath = 5, - PSDefaultParameterValues = 6, - PSScriptRoot = 7, - StackTrace = 8, - PID = 9 - } - - internal class ExpressionHasUnsupportedVariableOrSideEffectsVisitor : AstVisitor - { - internal bool ExpressionHasSideEffects { get; set; } - internal string NameOfUnsupportedVariableFound { get; set; } - - string variableName; - - internal ExpressionHasUnsupportedVariableOrSideEffectsVisitor(string variableName) - { - ExpressionHasSideEffects = false; - this.variableName = variableName; - } - - public override AstVisitAction VisitBlockStatement(BlockStatementAst blockStatementAst) - { - return AstVisitAction.SkipChildren; - } - - public override AstVisitAction VisitForEachStatement(ForEachStatementAst forEachStatementAst) - { - return AstVisitAction.SkipChildren; - } - - // Stop visiting when we hit a command (like InlineScript) - public override AstVisitAction VisitCommand(CommandAst commandAst) - { - return AstVisitAction.SkipChildren; - } - - // Check if this is an assignment to another variable - public override AstVisitAction VisitAssignmentStatement(AssignmentStatementAst assignmentStatementAst) - { - if (assignmentStatementAst != null) - { - VariableExpressionAst leftExpressionAst = assignmentStatementAst.Left as VariableExpressionAst; - if (leftExpressionAst != null) - { - string targetVariableName = leftExpressionAst.VariablePath.ToString(); - if (!String.Equals(variableName, targetVariableName, StringComparison.OrdinalIgnoreCase)) - { - ExpressionHasSideEffects = true; - return AstVisitAction.StopVisit; - } - } - } - - return base.VisitAssignmentStatement(assignmentStatementAst); - } - - public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst) - { - // ignore patterns like $env: - if (variableExpressionAst.VariablePath.IsVariable) - { - // dont allow patterns like "pscmdlet","workflow:pscmdlet" - string tempVariableName = variableExpressionAst.VariablePath.ToString(); - int indexOfColon = tempVariableName.IndexOf(':'); - if (indexOfColon != -1) - { - tempVariableName = tempVariableName.Substring(indexOfColon + 1); - } - - PSWorkflowUnsupportedVariable unused; - if (Enum.TryParse(tempVariableName, true, out unused)) - { - ExpressionHasSideEffects = true; - NameOfUnsupportedVariableFound = tempVariableName; - - return AstVisitAction.StopVisit; - } - } - return AstVisitAction.Continue; - } - - public override AstVisitAction VisitUnaryExpression(UnaryExpressionAst unaryExpressionAst) - { - // ignore cases like "-bnot 100" - switch (unaryExpressionAst.TokenKind) - { - case TokenKind.Minus: - case TokenKind.Plus: - case TokenKind.Not: - case TokenKind.Bnot: - case TokenKind.Exclaim: - case TokenKind.Comma: - case TokenKind.Csplit: - case TokenKind.Isplit: - case TokenKind.Join: - return AstVisitAction.SkipChildren; - } - - if (unaryExpressionAst.Child is VariableExpressionAst) - { - // If needed, check if it assigned to another variable - if (String.IsNullOrEmpty(variableName)) - { - ExpressionHasSideEffects = true; - return AstVisitAction.StopVisit; - } - - VariableExpressionAst referenceVariable = unaryExpressionAst.Child as VariableExpressionAst; - if (!String.Equals(variableName, referenceVariable.VariablePath.ToString(), StringComparison.OrdinalIgnoreCase)) - { - ExpressionHasSideEffects = true; - return AstVisitAction.StopVisit; - } - } - - return base.VisitUnaryExpression(unaryExpressionAst); - } - } -} - - diff --git a/src/Microsoft.PowerShell.Activities/AssemblyInfo.cs b/src/Microsoft.PowerShell.Activities/AssemblyInfo.cs deleted file mode 100644 index 08318ef68..000000000 --- a/src/Microsoft.PowerShell.Activities/AssemblyInfo.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Reflection; -using System.Security.Permissions; -using System.Runtime.CompilerServices; -using System.Runtime.ConstrainedExecution; -using System.Diagnostics.CodeAnalysis; - -[assembly: AssemblyVersion("3.0.0.0")] -[assembly: AssemblyFileVersionAttribute("3.0.0.0")] -[assembly: System.Resources.NeutralResourcesLanguage("en")] -[assembly: System.Runtime.InteropServices.ComVisible(false)] - -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("VSTS.ActivityTests,PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Microsoft.PowerShell.Utility.Activities,PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Microsoft.PowerShell.Management.Activities,PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] - -[assembly: AssemblyConfiguration("")] -[assembly: ReliabilityContractAttribute(Consistency.MayCorruptAppDomain, Cer.MayFail)] -[assembly: AssemblyTitle("Microsoft.PowerShell.Activities")] -[assembly: AssemblyDescription("Microsoft.PowerShell.Activities")] - -[module: SuppressMessage("Microsoft.Design", "CA1014:MarkAssembliesWithClsCompliant")] -[module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope="resource", Target="ActivityResources.resources", MessageId="InlineScript")] -[module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope="resource", Target="ActivityResources.resources", MessageId="inlinescript")] -[module: SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", Scope="resource", Target="ActivityResources.resources", MessageId="foreach")] - diff --git a/src/Microsoft.PowerShell.Activities/Xamls/InlineScriptDesigner.xaml b/src/Microsoft.PowerShell.Activities/Xamls/InlineScriptDesigner.xaml deleted file mode 100644 index 6b5083509..000000000 --- a/src/Microsoft.PowerShell.Activities/Xamls/InlineScriptDesigner.xaml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - This is the collapsed view - - - - - - - - - - - diff --git a/src/Microsoft.PowerShell.Activities/Xamls/PipelineDesigner.xaml b/src/Microsoft.PowerShell.Activities/Xamls/PipelineDesigner.xaml deleted file mode 100644 index f5eb1ae16..000000000 --- a/src/Microsoft.PowerShell.Activities/Xamls/PipelineDesigner.xaml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Microsoft.PowerShell.Activities/resources/ActivityResources.resx b/src/Microsoft.PowerShell.Activities/resources/ActivityResources.resx deleted file mode 100644 index 32405e990..000000000 --- a/src/Microsoft.PowerShell.Activities/resources/ActivityResources.resx +++ /dev/null @@ -1,561 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Cannot generate activity. The name '{0}' is reserved. - - - Cannot generate activity. The command name '{0}' could not be found in the default runspace. Use the GenerateFromCommandInfo method to generate activities for non-default commands. - GenerateFromCommandInfo should not be localized. It is the name of a method. - - - Activity-Specific Parameters - - - 'Command' is mutually exclusive with 'CommandName'. Either specify 'CommandName' (optionally with 'Parameters'), or 'Command'. - Command, CommandName and Parameters should not be localized. These are parameters. - - - Cannot supply both connection URI and computer name. - - - - ..\..\..\..\src\cimSupport\cmdletization\xml\cmdlets-over-objects.xsd;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 - {Locked} - - - The value of the EnumName attribute does not translate to a valid C# identifier: {0}. Verify the EnumName attribute in Cmdlet Definition XML, and then try again. - {StrContains="EnumName"} - - - The value of the Name attribute is not a valid C# identifier: {0}. Verify the Name attribute in Cmdlet Definition XML and try again. - {StrContains="Enum"} {StrContains="Value"} {StrContains="Name"} - - - A command name is required. - - - The computer name {0} is not valid. If you are trying to supply a Uri, use the Uri parameter. - - - Connectivity - - - Windows PowerShell Workflow cannot continue running the activity because an error occurred while importing dependent module(s) '{0}' specified for activity '{1}'. To fix this problem, make sure that the module exists on the computer. If it is not required, remove references to the module from the activity. - - - Input is defined in Pipeline variable and in the first child activity. Input should be defined only at one place. - - - Result is defined in Pipeline variable and in the last child activity. Result should be defined at one place. - - - Cannot have an empty BaseDirectory for importing localized data. Please specify a valid BaseDirectory and run the command again. - BaseDirectory should not be localized. This is a parameter. - - - Input and Output - - - The input parameter is required. - - - Restart-Computer activity cannot be run because both localhost and managed nodes are provided in the ComputerName parameter. For this scenario please run Restart-Computer activity for managed nodes followed by another Restart-Computer activity for localhost. - Restart-Computer and ComputerName should not be localized. These are a command and parameter. - - - Pipeline activity works with at least one child activity. - - - The following argument can not be null or empty: Expression - - - The result of Windows PowerShell expression evaluation is null or nothing - - - {0} line:{1} char:{2} - - - Parameter 'Wait' cannot be used for Restart-Computer activity when the localhost is being restarted. - Wait and Restart-Computer should not be localized. These are a parameter and command. - - - The activity has exceeded the specified maximum running time of {0} seconds. - - - Cannot generate activity. The name '{0}' is reserved. - - - Cannot generate activity. The command name '{0}' could not be found in the default runspace. Use the GenerateFromCommandInfo method to generate activities for non-default commands. - GenerateFromCommandInfo should not be localized. It is the name of a method. - - - The command name '{0}' is ambiguous and cannot be processed. To use this command, specify a module qualified name such as: 'Microsoft.PowerShell.Management\Get-Process'. - Microsoft.PowerShell.Management\Get-Process should not be localized. It is the qualified command name. - - - This type of assignment is not supported. Only variable names (i.e.: $variable) may be used as the target of an assignment statement. - - - Attributed expression (i.e.: [Parameter()]$x) should be used only when declaring parameters for the script workflow. - Parameter() should not be localized. This is syntax. - - - Begin, Process, and End statements are not supported in a Windows PowerShell Workflow. - Begin, Process, and End should not be localized. These are syntax. - - - Break and Continue statements are not supported in a Windows PowerShell Workflow. Instead, use an 'if' statement to control loop execution. - Break and Continue and 'if' should not be localized. These are syntax. - - - Cannot assign Start-Sleep to a variable. Start-Sleep generates no output. - Start-Sleep should not be localized. This is a command name. - - - Cannot redirect the error stream to the output stream. The target activity '{0}' does not contain the property 'MergeErrorToOutput'. - MergeErrorToOutput should not be localized. It is a property. - - - Cannot process more than one script block. - - - Cannot redirect error stream for the New-Object activity. - New-Object should not be localized. This is a command name. - - - Cannot redirect error stream for the delay activity. Please remove the stream redirection from this activity and try again. - - - Cannot assign the output of the '{1}' activity. It does not contain the 'Result' property. If this is a workflow that calls another workflow, implement a Result property as a [ref] parameter. - Result should not be localized. It is the name of a property. - - - 'Command' is mutually exclusive with 'CommandName'. Either specify 'CommandName' (optionally with 'Parameters'), or 'Command'. - Command, CommandName and Parameters should not be localized. These are parameters. - - - Assigning values to the Result argument is not supported. To store the output of a command, assign it to a variable. For example: $output = Get-Process. - $output = Get-Process should not be localized. This is syntax and command name. Result should not be localized. It is a parameter. - - - Cannot store the results of this type of expression into a variable. Only the results of commands, pipelines, constant expressions, foreach statements, parallel and sequence statements can be stored in variables. - - - Cannot store results in the variable '{0}'. Results are already being collected in the variable '{1}'. - - - The variable with name '{0}' is defined to store results from a parallel or sequence block. Therefore, it cannot be reused inside such blocks. - - - Cannot call the '{0}' command. Other commands from this module have been packaged as workflow activities, but this command was specifically excluded. This is likely because the command requires an interactive Windows PowerShell session, or has behavior not suited for workflows. To run this command anyway, place it within an inline-script (InlineScript {{ {0} }}) where it will be invoked in isolation. - InlineScript should not be localized. This is syntax. - - - A command name is required. - - - Could not find a parameter named '{0}' for the '{1}' command. Windows PowerShell common parameters such as WhatIf and OutVariable are not supported. - WhatIf and OutVariable should not be localized. These are parameter names. - - - The computer name {0} is not valid. If you are trying to supply a Uri, use the Uri parameter. - - - In a Windows PowerShell Workflow, loop conditions that modify variables are not supported. To change a variable, place the modification statement in the loop body itself. - - - Could not find a parameter named '{0}'. Supported parameters are: {1}. - - - Could not find a parameter named '{0}'. Workflow-common parameters such as PSComputerName are not supported in nested workflows that already have nested workflows. - PSComputerName should not be localized. This is a parameter. - - - Could not find a parameter named '{0}'. Note that this activity has the same name as a Windows PowerShell cmdlet, but different parameters. Supported parameters are: {1}. - - - Could not load assembly '{0}' specified in the list of required assemblies. - - - Dot-sourcing (. <command>) and the invocation operator (& <command>) are not supported in a Windows PowerShell Workflow. Wrap this command invocation into an inlinescript { } instead. - - - Input is defined in the Pipeline activity and in the first child activity. Input should be defined in only one place. - - - The result is defined in the Pipeline variable, and in the last child activity. The result should be defined in only one place. - - - Dynamic parameters are not supported in a Windows PowerShell Workflow. - - - The value of the EnumName attribute doesn't translate to a valid C# identifier: {0}. Verify the EnumName attribute in Cmdlet Definition XML and try again. - {StrContains="EnumName"} - - - The value of the Name attribute is not a valid C# identifier: {0}. Verify the Name attribute in Cmdlet Definition XML and try again. - {StrContains="Enum"} {StrContains="Value"} {StrContains="Name"} - - - In a Windows PowerShell Workflow, assignment to environment variables is not supported. - - - Cannot have an empty BaseDirectory for importing localized data. Please specify a valid BaseDirectory and run the command again. - BaseDirectory should not be localized. This is a parameter. - - - In a Windows PowerShell Workflow, the syntax for the InlineScript activity is "InlineScript { <commands> }". - InlineScript should not be localized. This is syntax. - - - The input parameter is required. - - - {0} is not a valid parameter or variable name. Names must start with a letter, and contain only letters, digits, '-', and '_'. - - - A variable scope prefix that is not valid was detected. The only valid scope prefix in the script workflow is "$WORKFLOW:". - $WORKFLOW should not be localized. This is syntax. - - - In a Windows PowerShell Workflow, the syntax for Invoke-Expression is: "Invoke-Expression -Language XAML -Command <string>". - Invoke-Expression -Language XAML -Command should not be localized. This is syntax. - - - The Restart-Computer activity cannot run because both localhost and remote computers are provided in the ComputerName parameter. For this scenario, run the Restart-Computer activity for remote computers first, followed by another Restart-Computer activity for localhost. - Restart-Computer and ComputerName should not be localized. These are a command and parameter. - - - Loop labels are not supported in a Windows PowerShell Workflow. - - - Method invocation is not supported in a Windows PowerShell Workflow. To use .NET scripting, place your commands in an inline script: InlineScript { <commands> }. - - - Invoke-Expression must use "-Language XAML" in a Windows PowerShell Workflow. - Invoke-Expression and -Language XAML should not be localized. These are syntax. - - - Could not find type {0}. Load the type(s) and try again. - - - In a Windows PowerShell Workflow, the syntax for New-Object is: "New-Object -TypeName <TypeName>". - New-Object and -TypeName <TypeName> should not be localized. This is syntax. - - - A pipeline activity must have at least one child activity. - - - The following argument cannot be null or empty: Expression - - - The result of Windows PowerShell expression evaluation is null or nothing. - - - You can provide only one #requires statement per script. - - - Only simple variable references (i.e.: $x) and number constants are supported in a unary expression. - - - Only the merging redirection from the error stream to the output stream is supported. - - - Unary operators '++' and '--' work only on variables in the script workflow. - - - The syntax of a {0} script block is '{0} { <commands> }'. - - - Advanced parameter validation is not supported on nested workflows. - - - Positional parameters are not supported in a Windows PowerShell Workflow. To invoke this command, use explicit parameter names with all values. For example: "Command -Parameter <value>". - - - Parameter 'Wait' cannot be used for Restart-Computer activity when the localhost is being restarted. - Wait and Restart-Computer should not be localized. These are a parameter and command. - - - Script block invocation is not supported in a Windows PowerShell Workflow. To run a set of commands in a similar way as the script block invocation, place your commands in an inline script: InlineScript { <commands> }. - InlineScript should not be localized. This is syntax. - - - In a Windows PowerShell Workflow, the syntax for Start-Sleep is: "Start-Sleep -Seconds <int>" or "Start-Sleep -Milliseconds <int>". - Start-Sleep, -Seconds and -Milliseconds should not be localized. These are a command and parameter names. - - - Sub expression (i.e.: $($x)) should only be used as the parameter value in a Windows PowerShell Workflow. To use .NET scripting, place your commands in an inline script: InlineScript { <commands> }. - InlineScript should not be localized. This is syntax. - - - Case-insensitive switch statements are not supported in a Windows PowerShell Workflow. Supply the -CaseSensitive flag, and ensure that case clauses are written appropriately. To write a case-insensitive case statement, first convert the input to either uppercase or lowercase, and update the case clauses to match. - - - Switch clauses must all be of the same type in a Windows PowerShell Workflow, or the condition expression must be strongly typed. - - - In a Windows PowerShell Workflow, the switch statement supports only the 'CaseSensitive' flag. - CaseSensitive should not be localized, this is a flag. - - - Only constant expressions are supported as switch clauses in a Windows PowerShell Workflow. - - - Trap statements are not supported in a Windows PowerShell Workflow. Instead, use try, catch, or finally. - - - Cannot create workflow. It depends on the type, '{0}', which was generated dynamically. - - - Cannot define variable. A variable with name '{0}' has already been defined. To reference a variable from the top-level scope of this workflow, use the syntax: '$WORKFLOW:{0}'. - $WORKFLOW should not be localized. This is syntax. - - - The Checkpoint-Workflow command accepts no parameters. - Checkpoint-Workflow should not be localized. This is a command name. - - - The Suspend-Workflow command accepts only one optional parameter, the syntax for Suspend-Workflow is: "Suspend-Workflow [-Label <string>]". - Suspend-Workflow should not be localized. This is a command name. - - - Ambiguous properties are found for the property name '{0}'. - - - The generic parameter type '{0}' for the parameter '{1}' cannot be resolved. - - - The value for the parameter '{0}' is not specified. To invoke this command, use explicit parameter names with all values. For example: "Command -Parameter <value>". - - - The parameter cannot be processed because the parameter name '{0}' is ambiguous. Possible matches include: {1}. - - - Data sections are not supported in a Windows PowerShell Workflow. - - - The throw statement requires a reason. - - - In a Windows PowerShell Workflow, switch statements support only expressions that return a single element. - - - In a Windows PowerShell Workflow, loop conditions that invoke activities are not supported. Conditions can use only variable references, and Windows PowerShell language elements that interact with those variables. - - - In a Windows PowerShell Workflow, throw statements that invoke activities (other than New-Object) are not supported. Throw statements can use only strings, variable references, and Windows PowerShell language elements. - New-Object should not be localized. This is a command name. - - - Parameter '{0}' is defined as an InOutArgument or OutArgument and can accept only variable references. - InOutArgument and OutArgument should not be localized. - - - The scope prefix "$WORKFLOW:" cannot be used in an InlineScript activity. To reference a workflow variable in an InlineScript activity, use the prefix "$USING:" instead. Workflow variables cannot be modified from an InlineScript activity. To change a workflow variable, assign the output of the InlineScript activity to that variable. - $USING and $WORKFLOW and InlineScript should not be localized. These are syntax. - - - The '{0}' activity is not supported in a workflow pipeline. - - - The '{0}' command is handled by the built-in '{1}' keyword. Use the built-in keyword instead. - - - In a Windows PowerShell Workflow, parameter defaults may only be simple value types (such as integers) and strings. In addition, the type of the default value must match the type of the parameter. - - - The output of the New-Object cmdlet must be assigned to a variable. - New-Object should not be localized. This is a command. - - - Cannot find the '{0}' command. If this command is defined as a workflow, ensure it is defined before the workflow that calls it. If it is a command intended to run directly within Windows PowerShell (or is not available on this system), place it in an InlineScript: 'InlineScript {{ {0} }}' - InlineScript should not be localized. This is syntax. - - - The value of the variable '{0}' can only be changed using the Set-PSWorkflowData activity. - Set-PSWorkflowData should not be localized. This is a command name. - - - The variable '{0}' is read-only. - - - Cannot start "{0}". Interactive console applications are not supported in a Windows PowerShell Workflow. To run the application, use the Start-Process cmdlet. - - - Cannot bind parameter because parameter '{0}' is specified more than once. To provide multiple values to parameters that can accept multiple values, use the array syntax. For example, "-parameter value1,value2,value3". - - - rootWorkflowName '{0}' is invalid. Make sure it exists in the context. - - - Could not find a parameter named 'ComputerName'. Remote connectivity in this command is handled by the 'PSComputerName' parameter. - - - Cannot define variable. Scope names are only valid in a parallel or sequence block. Within a parallel or sequence block, the only valid scope name is 'workflow'. - - - The '{0}' property does not support elements from the Windows PowerShell language such as parentheses and variables. To use this value, enclose it in a single-quoted string. - - - In a Windows PowerShell Workflow, the CmdletBinding attribute only supports the following values: "DefaultParameterSetName, ConfirmImpact, HelpUri, PositionalBinding". - - - The function or workflow '{0}' cannot be redefined. - - - The session state entry type '{0}' is not supported. - - - A workflow cannot use recursion. - - - The variable '{0}' cannot be used in a script workflow. - - - Cannot create workflow. Inline XAML is not supported in this language mode. - - - The generic type '{0}' cannot be resolved for the parameter '{1}'. - - - Cannot define pipeline. Once a pipeline uses the Sequence parameter of the Foreach-Object or Where-Object cmdlets, all remaining commands must also be either the Foreach-Object or Where-Object cmdlet with the Sequence parameter. - Sequence, Foreach-Object, and Where-Object should not be localized. They are command and parameter names. - - - Cannot call command. When used with the 'Sequence' parameter, the Foreach-Object cmdlet supports only the 'PipelineVariable', 'Begin', 'Sequence', and 'End' parameters. - Sequence, PipelineVariable, Begin, End, and Foreach-Object should not be localized. These are a parameter and command. - - - Cannot create pipeline. The Foreach-Object cmdlet with the -Sequence parameter cannot be used as the first element of a pipeline. - Foreach-Object should not be localized, or -Sequence. They are cmdlet and parameter names. - - - Cannot define pipeline. An iterative pipeline may not be nested within another iterative pipeline. - - - Cannot call command. When used with the 'Sequence' parameter, the Where-Object cmdlet supports only the 'PipelineVariable' and 'Sequence' parameters. - Sequence, PipelineVariable, and Where-Object should not be localized. These are a parameters and command. - - - Cannot create pipeline. The Where-Object cmdlet with the -Sequence parameter cannot be used as the first element of a pipeline. - Sequence and Where-Object should not be localized. These are a parameters and command. - -