/// <summary> /// The principal constructor that most hosts will use when creating /// an instance of the automation engine. It allows you to pass in an /// instance of PSHost that provides the host-specific I/O routines, etc. /// </summary> internal AutomationEngine(PSHost hostInterface, RunspaceConfiguration runspaceConfiguration, InitialSessionState iss) { #if !CORECLR// There is no control panel items in CSS // Update the env variable PathEXT to contain .CPL var pathext = Environment.GetEnvironmentVariable("PathEXT"); pathext = pathext ?? string.Empty; bool cplExist = false; if (pathext != string.Empty) { string[] entries = pathext.Split(Utils.Separators.Semicolon); foreach (string entry in entries) { string ext = entry.Trim(); if (ext.Equals(".CPL", StringComparison.OrdinalIgnoreCase)) { cplExist = true; break; } } } if (!cplExist) { pathext = (pathext == string.Empty) ? ".CPL" : pathext.EndsWith(";", StringComparison.OrdinalIgnoreCase) ? (pathext + ".CPL") : (pathext + ";.CPL"); Environment.SetEnvironmentVariable("PathEXT", pathext); } #endif if (runspaceConfiguration != null) { Context = new ExecutionContext(this, hostInterface, runspaceConfiguration); } else { Context = new ExecutionContext(this, hostInterface, iss); } EngineParser = new Language.Parser(); CommandDiscovery = new CommandDiscovery(Context); // Initialize providers before loading types so that any ScriptBlocks in the // types.ps1xml file can be parsed. // Bind the execution context with RunspaceConfiguration. // This has the side effect of initializing cmdlet cache and providers from runspace configuration. if (runspaceConfiguration != null) { runspaceConfiguration.Bind(Context); } else { // Load the iss, resetting everything to it's defaults... iss.Bind(Context, /*updateOnly*/ false); } InitialSessionState.SetSessionStateDrive(Context, true); InitialSessionState.CreateQuestionVariable(Context); }
private SemanticChecks(Parser parser) { IsConstantValueVisitor visitor = new IsConstantValueVisitor { CheckingAttributeArgument = true }; this._isConstantValueVisitor = visitor; this._parser = parser; }
internal static void CheckAst(Parser parser, ScriptBlockAst ast) { SemanticChecks semanticChecker = new SemanticChecks(parser); semanticChecker._scopeStack.Push(ast); ast.InternalVisit(semanticChecker); semanticChecker._scopeStack.Pop(); Diagnostics.Assert(semanticChecker._memberScopeStack.Count == 0, "Unbalanced push/pop of member scope stack"); Diagnostics.Assert(semanticChecker._scopeStack.Count == 0, "Unbalanced push/pop of scope stack"); }
internal static void CheckDataStatementAstAtRuntime(DataStatementAst dataStatementAst, string[] allowedCommands) { Parser parser = new Parser(); RestrictedLanguageChecker visitor = new RestrictedLanguageChecker(parser, allowedCommands, null, false); dataStatementAst.Body.InternalVisit(visitor); if (parser.ErrorList.Any<ParseError>()) { throw new ParseException(parser.ErrorList.ToArray()); } }
/// <summary> /// Parse input from the specified file. /// </summary> /// <param name="fileName">The name of the file to parse.</param> /// <param name="tokens">Returns the tokens from parsing the script.</param> /// <param name="errors">Returns errors, if any, discovered while parsing the script.</param> /// <returns>The <see cref="ScriptBlockAst"/> that represents the input script file.</returns> public static ScriptBlockAst ParseFile(string fileName, out Token[] tokens, out ParseError[] errors) { const string scriptSchemaExtension = ".schema.psm1"; var parseDscResource = false; // If the file has the 'schema.psm1' extension, then it is a 'DSC module file' however we don't actually load the // module at parse time so we can't use the normal mechanisms to bind the module name for configuration commands. // As an alternative, we extract the base name of the module file and use that as the module name for any keywords exported by this file. var parser = new Parser(); if (!string.IsNullOrEmpty(fileName) && fileName.Length > scriptSchemaExtension.Length && fileName.EndsWith(scriptSchemaExtension, StringComparison.OrdinalIgnoreCase)) { parser._keywordModuleName = Path.GetFileName(fileName.Substring(0, fileName.Length - scriptSchemaExtension.Length)); parseDscResource = true; } string scriptContents; try { var esi = new ExternalScriptInfo(fileName, fileName); scriptContents = esi.ScriptContents; } catch (Exception e) { var emptyExtent = new EmptyScriptExtent(); var errorMsg = string.Format(CultureInfo.CurrentCulture, ParserStrings.FileReadError, e.Message); errors = new[] { new ParseError(emptyExtent, "FileReadError", errorMsg) }; tokens = Utils.EmptyArray<Token>(); return new ScriptBlockAst(emptyExtent, null, new StatementBlockAst(emptyExtent, null, null), false); } var tokenList = new List<Token>(); ScriptBlockAst result; try { if (!parseDscResource) { DynamicKeyword.Push(); } result = parser.Parse(fileName, scriptContents, tokenList, out errors, ParseMode.Default); } catch (Exception e) { throw new ParseException(ParserStrings.UnrecoverableParserError, e); } finally { if (!parseDscResource) { DynamicKeyword.Pop(); } } tokens = tokenList.ToArray(); return result; }
private void Parse(string script) { try { var parser = new Language.Parser { ProduceV2Tokens = true }; parser.Parse(null, script, _tokenList, out _errors, ParseMode.Default); } catch (Exception e) { // Catch everything, die on fatal exceptions, otherwise ignore CommandProcessorBase.CheckForSevereException(e); } }
private void Parse(string script) { try { Parser parser2 = new Parser { ProduceV2Tokens = true }; parser2.Parse(null, script, this.tokenList, out this.errors); } catch (Exception exception) { CommandProcessorBase.CheckForSevereException(exception); } }
private static bool TryConvertArg(object arg, Type type, out object result, Parser parser, IScriptExtent errorExtent) { // This code could be added to LanguagePrimitives.ConvertTo if (arg != null && arg.GetType() == type) { result = arg; return true; } if (!LanguagePrimitives.TryConvertTo(arg, type, out result)) { parser.ReportError(errorExtent, () => ParserStrings.CannotConvertValue, ToStringCodeMethods.Type(type)); return false; } return true; }
internal static void CheckArrayTypeNameDepth(ITypeName typeName, IScriptExtent extent, Parser parser) { int num = 0; for (ITypeName name = typeName; !(name is TypeName); name = ((ArrayTypeName) name).ElementType) { num++; if (num > 200) { parser.ReportError(extent, ParserStrings.ScriptTooComplicated, new object[0]); return; } if (!(name is ArrayTypeName)) { break; } } }
internal AutomationEngine(PSHost hostInterface, RunspaceConfiguration runspaceConfiguration, InitialSessionState iss) { string str = Environment.GetEnvironmentVariable("PathEXT") ?? string.Empty; bool flag = false; if (str != string.Empty) { foreach (string str2 in str.Split(new char[] { ';' })) { if (str2.Trim().Equals(".CPL", StringComparison.OrdinalIgnoreCase)) { flag = true; break; } } } if (!flag) { str = (str == string.Empty) ? ".CPL" : (str.EndsWith(";", StringComparison.OrdinalIgnoreCase) ? (str + ".CPL") : (str + ";.CPL")); Environment.SetEnvironmentVariable("PathEXT", str); } if (runspaceConfiguration != null) { this._context = new ExecutionContext(this, hostInterface, runspaceConfiguration); } else { this._context = new ExecutionContext(this, hostInterface, iss); } this.EngineNewParser = new Parser(); this.commandDiscovery = new System.Management.Automation.CommandDiscovery(this._context); if (runspaceConfiguration != null) { runspaceConfiguration.Bind(this._context); } else { iss.Bind(this._context, false); } InitialSessionState.SetSessionStateDrive(this._context, true); InitialSessionState.CreateQuestionVariable(this._context); }
internal void AddType(Parser parser, TypeDefinitionAst typeDefinitionAst) { TypeLookupResult result; if (_typeTable.TryGetValue(typeDefinitionAst.Name, out result)) { if (result.ExternalNamespaces != null) { // override external type by the type defined in the current namespace result.ExternalNamespaces = null; result.Type = typeDefinitionAst; } else { parser.ReportError(typeDefinitionAst.Extent, () => ParserStrings.MemberAlreadyDefined, typeDefinitionAst.Name); } } else { _typeTable.Add(typeDefinitionAst.Name, new TypeLookupResult(typeDefinitionAst)); } }
internal RestrictedLanguageChecker(Parser parser, IEnumerable<string> allowedCommands, IEnumerable<string> allowedVariables, bool allowEnvironmentVariables) { this._parser = parser; this._allowedCommands = allowedCommands; if (allowedVariables != null) { if ((allowedVariables.Count<string>() == 1) && allowedVariables.Contains<string>("*")) { this._allVariablesAreAllowed = true; } else { this._allowedVariables = new HashSet<string>(_defaultAllowedVariables).Union<string>(allowedVariables); } } else { this._allowedVariables = _defaultAllowedVariables; } this._allowEnvironmentVariables = allowEnvironmentVariables; }
private SymbolResolver(Parser parser, TypeResolutionState typeResolutionState) { _symbolTable = new SymbolTable(parser); _parser = parser; _typeResolutionState = typeResolutionState; _symbolResolvePostActionVisitor = new SymbolResolvePostActionVisitor { _symbolResolver = this }; }
internal SymbolTable(Parser parser) { _scopes = new List<Scope>(); _parser = parser; }
internal void AddTypeFromUsingModule(Parser parser, TypeDefinitionAst typeDefinitionAst, PSModuleInfo moduleInfo) { TypeLookupResult result; if (_typeTable.TryGetValue(typeDefinitionAst.Name, out result)) { if (result.ExternalNamespaces != null) { // override external type by the type defined in the current namespace result.ExternalNamespaces.Add(moduleInfo.Name); } } else { var newLookupEntry = new TypeLookupResult(typeDefinitionAst) { ExternalNamespaces = new List<string>() }; newLookupEntry.ExternalNamespaces.Add(moduleInfo.Name); _typeTable.Add(typeDefinitionAst.Name, newLookupEntry); } string fullName = SymbolResolver.GetModuleQualifiedName(moduleInfo.Name, typeDefinitionAst.Name); if (_typeTable.TryGetValue(fullName, out result)) { parser.ReportError(typeDefinitionAst.Extent, () => ParserStrings.MemberAlreadyDefined, fullName); } else { _typeTable.Add(fullName, new TypeLookupResult(typeDefinitionAst)); } }
internal static ScriptBlock Create(Parser parser, string fileName, string fileContents) { ParseError[] parseErrorArray = null; ScriptBlock scriptBlock = ScriptBlock.TryGetCachedScriptBlock(fileName, fileContents); if (scriptBlock == null) { ScriptBlockAst scriptBlockAst = parser.Parse(fileName, fileContents, null, out parseErrorArray); if ((int)parseErrorArray.Length == 0) { ScriptBlock scriptBlock1 = new ScriptBlock(scriptBlockAst, false); ScriptBlock.CacheScriptBlock(scriptBlock1, fileName, fileContents); return scriptBlock1.Clone(false); } else { throw new ParseException(parseErrorArray); } } else { return scriptBlock; } }
public void CheckRestrictedLanguage(IEnumerable<string> allowedCommands, IEnumerable<string> allowedVariables, bool allowEnvironmentVariables) { Parser parser = new Parser(); if (this.HasBeginBlock || this.HasProcessBlock || this._ast.Body.ParamBlock != null) { NamedBlockAst beginBlock = this._ast.Body.BeginBlock; Ast paramBlock = beginBlock; if (beginBlock == null) { NamedBlockAst processBlock = this._ast.Body.ProcessBlock; paramBlock = processBlock; if (processBlock == null) { paramBlock = this._ast.Body.ParamBlock; } } Ast ast = paramBlock; parser.ReportError(ast.Extent, ParserStrings.InvalidScriptBlockInDataSection, new object[0]); } if (this.HasEndBlock) { RestrictedLanguageChecker restrictedLanguageChecker = new RestrictedLanguageChecker(parser, allowedCommands, allowedVariables, allowEnvironmentVariables); NamedBlockAst endBlock = this._ast.Body.EndBlock; StatementBlockAst.InternalVisit(restrictedLanguageChecker, endBlock.Traps, endBlock.Statements, AstVisitAction.Continue); } if (!parser.ErrorList.Any<ParseError>()) { return; } else { throw new ParseException(parser.ErrorList.ToArray()); } }
/// <summary> /// Check if it is a Get method with correct return type and signature /// </summary> /// <param name="parser"></param> /// <param name="functionMemberAst">The function member AST</param> /// <param name="hasGet">True if it is a Get method with qualified return type and signature; otherwise, false. </param> private static void CheckGet(Parser parser, FunctionMemberAst functionMemberAst, ref bool hasGet) { if (hasGet) { return; } if (functionMemberAst.Name.Equals("Get", StringComparison.OrdinalIgnoreCase) && functionMemberAst.Parameters.Count == 0) { if (functionMemberAst.ReturnType != null) { // Return type is of the class we're defined in //it must return the class type, or array of the class type. var arrayTypeName = functionMemberAst.ReturnType.TypeName as ArrayTypeName; var typeName = (arrayTypeName != null ? arrayTypeName.ElementType : functionMemberAst.ReturnType.TypeName) as TypeName; if (typeName == null || typeName._typeDefinitionAst != functionMemberAst.Parent) { parser.ReportError(functionMemberAst.Extent, () => ParserStrings.DscResourceInvalidGetMethod, ((TypeDefinitionAst)functionMemberAst.Parent).Name); } } else { parser.ReportError(functionMemberAst.Extent, () => ParserStrings.DscResourceInvalidGetMethod, ((TypeDefinitionAst)functionMemberAst.Parent).Name); } //Set hasGet to true to stop look up; it may have invalid get hasGet = true; return; } }
internal static void CheckArrayTypeNameDepth(ITypeName typeName, IScriptExtent extent, Parser parser) { int count = 0; ITypeName type = typeName; while ((type is TypeName) == false) { count++; if (count > 200) { parser.ReportError(extent, () => ParserStrings.ScriptTooComplicated); break; } if (type is ArrayTypeName) { type = ((ArrayTypeName)type).ElementType; } else { break; } } }
internal ScriptBlockAst GetScriptBlockAst() { ParseError[] errorArray; string scriptContents = this.ScriptContents; if (this._scriptBlock == null) { this.ScriptBlock = System.Management.Automation.ScriptBlock.TryGetCachedScriptBlock(this._path, scriptContents); } if (this._scriptBlock != null) { return (ScriptBlockAst) this._scriptBlock.Ast; } ScriptBlockAst ast = new Parser().Parse(this._path, this.ScriptContents, null, out errorArray); if (errorArray.Length == 0) { this.ScriptBlock = new System.Management.Automation.ScriptBlock(ast, false); System.Management.Automation.ScriptBlock.CacheScriptBlock(this._scriptBlock.Clone(false), this._path, scriptContents); } return ast; }
/// <summary> /// Bake types and creates a dynamic assembly. /// This method should be called only for rootAsts (i.e. script file root ScriptBlockAst). /// </summary> /// <param name="rootForDefiningTypes"></param> /// <param name="typeAsts">non-empty array of TypeDefinitionAst</param> /// <returns>Assembly with defined types</returns> internal static Assembly DefinePowerShellTypes(Ast rootForDefiningTypes, TypeDefinitionAst[] typeAsts) { // TODO(sevoroby): this Diagnostic is conceptually right. // BUT It triggers, when we define type in an InitialSessionState and use it later in two different PowerShell instances. // Diagnostics.Assert(typeAsts[0].Type == null, "We must not call DefinePowerShellTypes twice for the same TypeDefinitionAsts"); if (typeAsts[0].Type != null) { // We treat Type as a mutable buffer field and wipe it here to start definitions from scratch. // I didn't find any real scenario when it can cause problems, except multi-threaded environment, which is rear and out-of-scope for now. // Potentially, we can fix it with Ast.Copy() and rewiring ITypeName references for the whole tree. foreach (var typeDefinitionAst in typeAsts) { typeDefinitionAst.Type = null; } } // This is a short term solution - all error messages produced by creating the types should happen // at parse time, not runtime. var parser = new Parser(); var assembly = TypeDefiner.DefineTypes(parser, rootForDefiningTypes, typeAsts); if (parser.ErrorList.Count > 0) { // wipe types, if there are any errors. foreach (var typeDefinitionAst in typeAsts) { typeDefinitionAst.Type = null; } throw new ParseException(parser.ErrorList.ToArray()); } return assembly; }
public ScriptBlock GetScriptBlock() { Parser parser = new Parser(); SemanticChecks.CheckAst(parser, this); if (parser.ErrorList.Any<ParseError>()) { throw new ParseException(parser.ErrorList.ToArray()); } return new ScriptBlock(this, false); }
/// <summary> /// True if it is a key property. /// </summary> /// <param name="parser"></param> /// <param name="propertyMemberAst">The property member AST</param> /// <param name="hasKey">True if it is a key property; otherwise, false.</param> private static void CheckKey(Parser parser, PropertyMemberAst propertyMemberAst, ref bool hasKey) { foreach (var attr in propertyMemberAst.Attributes) { if (attr.TypeName.GetReflectionAttributeType() == typeof(DscPropertyAttribute)) { foreach (var na in attr.NamedArguments) { if (na.ArgumentName.Equals("Key", StringComparison.OrdinalIgnoreCase)) { object attrArgValue; if (IsConstantValueVisitor.IsConstant(na.Argument, out attrArgValue, forAttribute: true, forRequires: false) && LanguagePrimitives.IsTrue(attrArgValue)) { hasKey = true; bool keyPropertyTypeAllowed = false; var propertyType = propertyMemberAst.PropertyType; if (propertyType != null) { TypeName typeName = propertyType.TypeName as TypeName; if (typeName != null) { var type = typeName.GetReflectionType(); if (type != null) { keyPropertyTypeAllowed = type == typeof(string) || type.IsInteger(); } else { var typeDefinitionAst = typeName._typeDefinitionAst; if (typeDefinitionAst != null) { keyPropertyTypeAllowed = typeDefinitionAst.IsEnum; } } } } if (!keyPropertyTypeAllowed) { parser.ReportError(propertyMemberAst.Extent, () => ParserStrings.DscResourceInvalidKeyProperty); } return; } } } } } }
internal static ScriptBlock Create(Parser parser, string fileName, string fileContents) { var scriptBlock = TryGetCachedScriptBlock(fileName, fileContents); if (scriptBlock != null) { return scriptBlock; } ParseError[] errors; var ast = parser.Parse(fileName, fileContents, null, out errors, ParseMode.Default); if (errors.Length != 0) { throw new ParseException(errors); } var result = new ScriptBlock(ast, isFilter: false); CacheScriptBlock(result, fileName, fileContents); // The value returned will potentially be bound to a session state. We don't want // the cached script block to end up being bound to any session state, so clone // the return value to ensure the cached value has no session state. return result.Clone(); }
internal RestrictedLanguageChecker(Parser parser, IEnumerable<string> allowedCommands, IEnumerable<string> allowedVariables, bool allowEnvironmentVariables) { _parser = parser; _allowedCommands = allowedCommands; if (allowedVariables != null) { // A single '*' allows any variable to be used. The use of a single '*' aligns with the // way SessionState.Applications and SessionState.Scripts lists work. var allowedVariablesList = allowedVariables as IList<string> ?? allowedVariables.ToList(); if (allowedVariablesList.Count == 1 && allowedVariablesList.Contains("*")) { _allVariablesAreAllowed = true; } else { // Allowed variables are the union of the default variables plus any the caller has passed in. _allowedVariables = new HashSet<string>(s_defaultAllowedVariables).Union(allowedVariablesList); } } else { _allowedVariables = s_defaultAllowedVariables; } _allowEnvironmentVariables = allowEnvironmentVariables; }
internal static void ResolveSymbols(Parser parser, ScriptBlockAst scriptBlockAst) { Diagnostics.Assert(scriptBlockAst.Parent == null, "Can only resolve starting from the root"); var usingState = scriptBlockAst.UsingStatements.Count > 0 ? new TypeResolutionState(TypeOps.GetNamespacesForTypeResolutionState(scriptBlockAst.UsingStatements), TypeResolutionState.emptyAssemblies) : TypeResolutionState.GetDefaultUsingState(null); var resolver = new SymbolResolver(parser, usingState); resolver._symbolTable.EnterScope(scriptBlockAst, ScopeType.ScriptBlock); scriptBlockAst.Visit(resolver); resolver._symbolTable.LeaveScope(); Diagnostics.Assert(resolver._symbolTable._scopes.Count == 0, "Somebody missed removing a scope"); }
private SemanticChecks(Parser parser) { _parser = parser; _memberScopeStack = new Stack<MemberAst>(); _scopeStack = new Stack<ScriptBlockAst>(); }
internal static void CheckDataStatementLanguageModeAtRuntime(DataStatementAst dataStatementAst, ExecutionContext executionContext) { // If we get here, we have already determined the data statement invokes commands, so // we only need to check the language mode. if (executionContext.LanguageMode == PSLanguageMode.ConstrainedLanguage) { var parser = new Parser(); parser.ReportError(dataStatementAst.CommandsAllowed[0].Extent, () => ParserStrings.DataSectionAllowedCommandDisallowed); throw new ParseException(parser.ErrorList.ToArray()); } }
/// <summary> /// Check the script block to see if it uses any language constructs not allowed in restricted language mode. /// </summary> /// <param name="allowedCommands">The commands that are allowed.</param> /// <param name="allowedVariables"> /// The variables allowed in this scriptblock. If this is null, then the default variable set /// will be allowed. If it is an empty list, no variables will be allowed. If it is "*" then /// any variable will be allowed. /// </param> /// <param name="allowEnvironmentVariables">The environment variables that are allowed.</param> public void CheckRestrictedLanguage(IEnumerable<string> allowedCommands, IEnumerable<string> allowedVariables, bool allowEnvironmentVariables) { Parser parser = new Parser(); var ast = AstInternal; if (HasBeginBlock || HasProcessBlock || ast.Body.ParamBlock != null) { Ast errorAst = ast.Body.BeginBlock ?? (Ast)ast.Body.ProcessBlock ?? ast.Body.ParamBlock; parser.ReportError(errorAst.Extent, () => ParserStrings.InvalidScriptBlockInDataSection); } if (HasEndBlock) { RestrictedLanguageChecker rlc = new RestrictedLanguageChecker(parser, allowedCommands, allowedVariables, allowEnvironmentVariables); var endBlock = ast.Body.EndBlock; StatementBlockAst.InternalVisit(rlc, endBlock.Traps, endBlock.Statements, AstVisitAction.Continue); } if (parser.ErrorList.Any()) { throw new ParseException(parser.ErrorList.ToArray()); } }
internal ScriptBlockAst GetScriptBlockAst() { var scriptContents = ScriptContents; if (_scriptBlock == null) { this.ScriptBlock = ScriptBlock.TryGetCachedScriptBlock(_path, scriptContents); } if (_scriptBlock != null) { return (ScriptBlockAst)_scriptBlock.Ast; } if (_scriptBlockAst == null) { ParseError[] errors; Parser parser = new Parser(); _scriptBlockAst = parser.Parse(_path, ScriptContents, null, out errors, ParseMode.Default); if (errors.Length == 0) { this.ScriptBlock = new ScriptBlock(_scriptBlockAst, isFilter: false); ScriptBlock.CacheScriptBlock(_scriptBlock.Clone(), _path, scriptContents); } } return _scriptBlockAst; }