/
githubmirror
/
PowerShell
Обзор
Документация
Войти
/
githubmirror
/
PowerShell
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/System.Management.Automation/engine/SessionStateFunctionAPIs.cs
791 строка
29 KB
Paul Higinbotham
Add WDAC Audit logging (#19641)
23 май 2023, 02:40
Не верифицирован
23 май 2023, 02:40
e5728b6
Код
Авторство
О чём код?
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Collections; using System.Collections.Generic; using System.Management.Automation.Language; using System.Management.Automation.Runspaces; using System.Management.Automation.Security; using Dbg = System.Management.Automation.Diagnostics; namespace System.Management.Automation { /// <summary> /// Holds the state of a Monad Shell session. /// </summary> internal sealed partial class SessionStateInternal { #region Functions /// <summary> /// Add an new SessionState function entry to this session state object... /// </summary> /// <param name="entry">The entry to add.</param> internal void AddSessionStateEntry(SessionStateFunctionEntry entry) { ScriptBlock sb = entry.ScriptBlock.Clone(); FunctionInfo fn = this.SetFunction(entry.Name, sb, null, entry.Options, false, CommandOrigin.Internal, this.ExecutionContext, entry.HelpFile, true); fn.Visibility = entry.Visibility; fn.Module = entry.Module; fn.ScriptBlock.LanguageMode = entry.ScriptBlock.LanguageMode ?? PSLanguageMode.FullLanguage; } /// <summary> /// Gets a flattened view of the functions that are visible using /// the current scope as a reference and filtering the functions in /// the other scopes based on the scoping rules. /// </summary> /// <returns> /// An IDictionary representing the visible functions. /// </returns> internal IDictionary<string, FunctionInfo> GetFunctionTable() { SessionStateScopeEnumerator scopeEnumerator = new SessionStateScopeEnumerator(_currentScope); Dictionary<string, FunctionInfo> result = new Dictionary<string, FunctionInfo>(StringComparer.OrdinalIgnoreCase); foreach (SessionStateScope scope in scopeEnumerator) { foreach (FunctionInfo entry in scope.FunctionTable.Values) { if (!result.ContainsKey(entry.Name)) { result.Add(entry.Name, entry); } } } return result; } /// <summary> /// Gets an IEnumerable for the function table for a given scope. /// </summary> /// <param name="scopeID"> /// A scope identifier that is either one of the "special" scopes like /// "global", "script", "local", or "private, or a numeric ID of a relative scope /// to the current scope. /// </param> /// <exception cref="ArgumentException"> /// If <paramref name="scopeID"/> is less than zero, or not /// a number and not "script", "global", "local", or "private" /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// If <paramref name="scopeID"/> is less than zero or greater than the number of currently /// active scopes. /// </exception> internal IDictionary<string, FunctionInfo> GetFunctionTableAtScope(string scopeID) { Dictionary<string, FunctionInfo> result = new Dictionary<string, FunctionInfo>(StringComparer.OrdinalIgnoreCase); SessionStateScope scope = GetScopeByID(scopeID); foreach (FunctionInfo entry in scope.FunctionTable.Values) { // Make sure the function/filter isn't private or if it is that the current // scope is the same scope the alias was retrieved from. if ((entry.Options & ScopedItemOptions.Private) == 0 || scope == _currentScope) { result.Add(entry.Name, entry); } } return result; } /// <summary> /// List of functions/filters to export from this session state object... /// </summary> internal List<FunctionInfo> ExportedFunctions { get; } = new List<FunctionInfo>(); internal bool UseExportList { get; set; } = false; /// <summary> /// Set to true when module functions are being explicitly exported using Export-ModuleMember. /// </summary> internal bool FunctionsExported { get; set; } /// <summary> /// Set to true when any processed module functions are being explicitly exported using '*' wildcard. /// </summary> internal bool FunctionsExportedWithWildcard { get { return _functionsExportedWithWildcard; } set { Dbg.Assert((value), "This property should never be set/reset to false"); if (value) { _functionsExportedWithWildcard = value; } } } private bool _functionsExportedWithWildcard; /// <summary> /// Set to true if module loading is performed under a manifest that explicitly exports functions (no wildcards) /// </summary> internal bool ManifestWithExplicitFunctionExport { get; set; } /// <summary> /// Get a functions out of session state. /// </summary> /// <param name="name"> /// name of function to look up /// </param> /// <param name="origin"> /// Origin of the command that called this API... /// </param> /// <returns> /// The value of the specified function. /// </returns> /// <exception cref="ArgumentException"> /// If <paramref name="name"/> is null or empty. /// </exception> internal FunctionInfo GetFunction(string name, CommandOrigin origin) { if (string.IsNullOrEmpty(name)) { throw PSTraceSource.NewArgumentException(nameof(name)); } FunctionInfo result = null; FunctionLookupPath lookupPath = new FunctionLookupPath(name); FunctionScopeItemSearcher searcher = new FunctionScopeItemSearcher(this, lookupPath, origin); if (searcher.MoveNext()) { result = ((IEnumerator<FunctionInfo>)searcher).Current; } return (IsFunctionVisibleInDebugger(result, origin)) ? result : null; } private bool IsFunctionVisibleInDebugger(FunctionInfo fnInfo, CommandOrigin origin) { // Ensure the returned function item is not exposed across language boundaries when in // a debugger breakpoint or nested prompt. // A debugger breakpoint/nested prompt has access to all current scoped functions. // This includes both running commands from the prompt or via a debugger Action scriptblock. // Early out. // Always allow built-in functions needed for command line debugging. if (this.ExecutionContext.LanguageMode == PSLanguageMode.FullLanguage || (fnInfo == null) || (fnInfo.Name.Equals("prompt", StringComparison.OrdinalIgnoreCase)) || (fnInfo.Name.Equals("TabExpansion2", StringComparison.OrdinalIgnoreCase)) || (fnInfo.Name.Equals("Clear-Host", StringComparison.Ordinal))) { return true; } // Check both InNestedPrompt and Debugger.InBreakpoint to ensure we don't miss a case. // Function is not visible if function and context language modes are different. var runspace = this.ExecutionContext.CurrentRunspace; if ((runspace != null) && (runspace.InNestedPrompt || (runspace.Debugger?.InBreakpoint == true)) && (fnInfo.DefiningLanguageMode.HasValue && (fnInfo.DefiningLanguageMode != this.ExecutionContext.LanguageMode))) { return false; } return true; } /// <summary> /// Get a functions out of session state. /// </summary> /// <param name="name"> /// name of function to look up /// </param> /// <returns> /// The value of the specified function. /// </returns> /// <exception cref="ArgumentException"> /// If <paramref name="name"/> is null or empty. /// </exception> internal FunctionInfo GetFunction(string name) { return GetFunction(name, CommandOrigin.Internal); } private static IEnumerable<string> GetFunctionAliases(IParameterMetadataProvider ipmp) { if (ipmp == null || ipmp.Body.ParamBlock == null) yield break; var attributes = ipmp.Body.ParamBlock.Attributes; foreach (var attributeAst in attributes) { var attributeType = attributeAst.TypeName.GetReflectionAttributeType(); if (attributeType == typeof(AliasAttribute)) { var cvv = new ConstantValueVisitor { AttributeArgument = true }; for (int i = 0; i < attributeAst.PositionalArguments.Count; i++) { yield return Compiler.s_attrArgToStringConverter.Target(Compiler.s_attrArgToStringConverter, attributeAst.PositionalArguments[i].Accept(cvv)); } } } } /// <summary> /// Set a function in the current scope of session state. /// </summary> /// <param name="name"> /// The name of the function to set. /// </param> /// <param name="function"> /// The new value of the function being set. /// </param> /// <param name="origin"> /// Origin of the caller of this API /// </param> /// <exception cref="ArgumentException"> /// If <paramref name="name"/> is null or empty. /// </exception> /// <exception cref="ArgumentNullException"> /// If <paramref name="function"/> is null. /// </exception> /// <exception cref="SessionStateUnauthorizedAccessException"> /// If the function is read-only or constant. /// </exception> internal FunctionInfo SetFunctionRaw( string name, ScriptBlock function, CommandOrigin origin) { if (string.IsNullOrEmpty(name)) { throw PSTraceSource.NewArgumentException(nameof(name)); } if (function == null) { throw PSTraceSource.NewArgumentNullException(nameof(function)); } string originalName = name; FunctionLookupPath path = new FunctionLookupPath(name); name = path.UnqualifiedPath; if (string.IsNullOrEmpty(name)) { SessionStateException exception = new SessionStateException( originalName, SessionStateCategory.Function, "ScopedFunctionMustHaveName", SessionStateStrings.ScopedFunctionMustHaveName, ErrorCategory.InvalidArgument); throw exception; } ScopedItemOptions options = ScopedItemOptions.None; if (path.IsPrivate) { options |= ScopedItemOptions.Private; } FunctionScopeItemSearcher searcher = new FunctionScopeItemSearcher( this, path, origin); var functionInfo = searcher.InitialScope.SetFunction(name, function, null, options, false, origin, ExecutionContext); foreach (var aliasName in GetFunctionAliases(function.Ast as IParameterMetadataProvider)) { searcher.InitialScope.SetAliasValue(aliasName, name, ExecutionContext, false, origin); } return functionInfo; } /// <summary> /// Set a function in the current scope of session state. /// </summary> /// <param name="name"> /// The name of the function to set. /// </param> /// <param name="function"> /// The new value of the function being set. /// </param> /// <param name="originalFunction"> /// The original function (if any) from which the ScriptBlock is derived. /// </param> /// <param name="options"> /// The options to set on the function. /// </param> /// <param name="force"> /// If true, the function will be set even if its ReadOnly. /// </param> /// <param name="origin"> /// Origin of the caller of this API /// </param> /// <exception cref="ArgumentException"> /// If <paramref name="name"/> is null or empty. /// </exception> /// <exception cref="ArgumentNullException"> /// If <paramref name="function"/> is null. /// </exception> /// <exception cref="SessionStateUnauthorizedAccessException"> /// If the function is read-only or constant. /// </exception> internal FunctionInfo SetFunction( string name, ScriptBlock function, FunctionInfo originalFunction, ScopedItemOptions options, bool force, CommandOrigin origin) { return SetFunction(name, function, originalFunction, options, force, origin, ExecutionContext, null); } /// <summary> /// Set a function in the current scope of session state. /// </summary> /// <param name="name"> /// The name of the function to set. /// </param> /// <param name="function"> /// The new value of the function being set. /// </param> /// <param name="originalFunction"> /// The original function (if any) from which the ScriptBlock is derived. /// </param> /// <param name="options"> /// The options to set on the function. /// </param> /// <param name="force"> /// If true, the function will be set even if its ReadOnly. /// </param> /// <param name="origin"> /// Origin of the caller of this API /// </param> /// <param name="helpFile"> /// The name of the help file associated with the function. /// </param> /// <exception cref="ArgumentException"> /// If <paramref name="name"/> is null or empty. /// </exception> /// <exception cref="ArgumentNullException"> /// If <paramref name="function"/> is null. /// </exception> /// <exception cref="SessionStateUnauthorizedAccessException"> /// If the function is read-only or constant. /// </exception> internal FunctionInfo SetFunction( string name, ScriptBlock function, FunctionInfo originalFunction, ScopedItemOptions options, bool force, CommandOrigin origin, string helpFile) { return SetFunction(name, function, originalFunction, options, force, origin, ExecutionContext, helpFile, false); } /// <summary> /// Set a function in the current scope of session state. /// </summary> /// <param name="name"> /// The name of the function to set. /// </param> /// <param name="function"> /// The new value of the function being set. /// </param> /// <param name="originalFunction"> /// The original function (if any) from which the ScriptBlock is derived. /// </param> /// <param name="options"> /// The options to set on the function. /// </param> /// <param name="force"> /// If true, the function will be set even if its ReadOnly. /// </param> /// <param name="origin"> /// Origin of the caller of this API /// </param> /// <param name="context"> /// The execution context for the function. /// </param> /// <param name="helpFile"> /// The name of the help file associated with the function. /// </param> /// <exception cref="ArgumentException"> /// If <paramref name="name"/> is null or empty. /// </exception> /// <exception cref="ArgumentNullException"> /// If <paramref name="function"/> is null. /// </exception> /// <exception cref="SessionStateUnauthorizedAccessException"> /// If the function is read-only or constant. /// </exception> internal FunctionInfo SetFunction( string name, ScriptBlock function, FunctionInfo originalFunction, ScopedItemOptions options, bool force, CommandOrigin origin, ExecutionContext context, string helpFile) { return SetFunction(name, function, originalFunction, options, force, origin, context, helpFile, false); } /// <summary> /// Set a function in the current scope of session state. /// </summary> /// <param name="name"> /// The name of the function to set. /// </param> /// <param name="function"> /// The new value of the function being set. /// </param> /// <param name="originalFunction"> /// The original function (if any) from which the ScriptBlock is derived. /// </param> /// <param name="options"> /// The options to set on the function. /// </param> /// <param name="force"> /// If true, the function will be set even if its ReadOnly. /// </param> /// <param name="origin"> /// Origin of the caller of this API /// </param> /// <param name="context"> /// The execution context for the function. /// </param> /// <param name="helpFile"> /// The name of the help file associated with the function. /// </param> /// <param name="isPreValidated"> /// Set to true if it is a regular function (meaning, we do not need to check if the script contains JobDefinition Attribute and then process it) /// </param> /// <exception cref="ArgumentException"> /// If <paramref name="name"/> is null or empty. /// </exception> /// <exception cref="ArgumentNullException"> /// If <paramref name="function"/> is null. /// </exception> /// <exception cref="SessionStateUnauthorizedAccessException"> /// If the function is read-only or constant. /// </exception> internal FunctionInfo SetFunction( string name, ScriptBlock function, FunctionInfo originalFunction, ScopedItemOptions options, bool force, CommandOrigin origin, ExecutionContext context, string helpFile, bool isPreValidated) { if (string.IsNullOrEmpty(name)) { throw PSTraceSource.NewArgumentException(nameof(name)); } if (function == null) { throw PSTraceSource.NewArgumentNullException(nameof(function)); } string originalName = name; FunctionLookupPath path = new FunctionLookupPath(name); name = path.UnqualifiedPath; if (string.IsNullOrEmpty(name)) { SessionStateException exception = new SessionStateException( originalName, SessionStateCategory.Function, "ScopedFunctionMustHaveName", SessionStateStrings.ScopedFunctionMustHaveName, ErrorCategory.InvalidArgument); throw exception; } if (path.IsPrivate) { options |= ScopedItemOptions.Private; } FunctionScopeItemSearcher searcher = new FunctionScopeItemSearcher( this, path, origin); return searcher.InitialScope.SetFunction(name, function, originalFunction, options, force, origin, context, helpFile); } /// <summary> /// Set a function in the current scope of session state. /// </summary> /// <param name="name"> /// The name of the function to set. /// </param> /// <param name="function"> /// The new value of the function being set. /// </param> /// <param name="originalFunction"> /// The original function (if any) from which the ScriptBlock is derived. /// </param> /// <param name="force"> /// If true, the function will be set even if its ReadOnly. /// </param> /// <param name="origin"> /// The origin of the caller /// </param> /// <exception cref="ArgumentException"> /// If <paramref name="name"/> is null or empty. /// or /// If <paramref name="function"/> is not a <see cref="FilterInfo">FilterInfo</see> /// or <see cref="FunctionInfo">FunctionInfo</see> /// </exception> /// <exception cref="ArgumentNullException"> /// If <paramref name="function"/> is null. /// </exception> /// <exception cref="SessionStateUnauthorizedAccessException"> /// If the function is read-only or constant. /// </exception> internal FunctionInfo SetFunction( string name, ScriptBlock function, FunctionInfo originalFunction, bool force, CommandOrigin origin) { if (string.IsNullOrEmpty(name)) { throw PSTraceSource.NewArgumentException(nameof(name)); } if (function == null) { throw PSTraceSource.NewArgumentNullException(nameof(function)); } string originalName = name; FunctionLookupPath path = new FunctionLookupPath(name); name = path.UnqualifiedPath; if (string.IsNullOrEmpty(name)) { SessionStateException exception = new SessionStateException( originalName, SessionStateCategory.Function, "ScopedFunctionMustHaveName", SessionStateStrings.ScopedFunctionMustHaveName, ErrorCategory.InvalidArgument); throw exception; } ScopedItemOptions options = ScopedItemOptions.None; if (path.IsPrivate) { options |= ScopedItemOptions.Private; } FunctionScopeItemSearcher searcher = new FunctionScopeItemSearcher( this, path, origin); FunctionInfo result = null; SessionStateScope scope = searcher.InitialScope; if (searcher.MoveNext()) { scope = searcher.CurrentLookupScope; name = searcher.Name; if (path.IsPrivate) { // Need to add the Private flag FunctionInfo existingFunction = scope.GetFunction(name); options |= existingFunction.Options; result = scope.SetFunction(name, function, originalFunction, options, force, origin, ExecutionContext); } else { result = scope.SetFunction(name, function, force, origin, ExecutionContext); } } else { if (path.IsPrivate) { result = scope.SetFunction(name, function, originalFunction, options, force, origin, ExecutionContext); } else { result = scope.SetFunction(name, function, force, origin, ExecutionContext); } } return result; } /// <summary> /// Set a function in the current scope of session state. /// /// BUGBUG: this overload is preserved because a lot of tests use reflection to /// call it. The tests should be fixed and this API eventually removed. /// </summary> /// <param name="name"> /// The name of the function to set. /// </param> /// <param name="function"> /// The new value of the function being set. /// </param> /// <param name="force"> /// If true, the function will be set even if its ReadOnly. /// </param> /// <exception cref="ArgumentException"> /// If <paramref name="name"/> is null or empty. /// or /// If <paramref name="function"/> is not a <see cref="FilterInfo">FilterInfo</see> /// or <see cref="FunctionInfo">FunctionInfo</see> /// </exception> /// <exception cref="ArgumentNullException"> /// If <paramref name="function"/> is null. /// </exception> /// <exception cref="SessionStateUnauthorizedAccessException"> /// If the function is read-only or constant. /// </exception> internal FunctionInfo SetFunction(string name, ScriptBlock function, bool force) { return SetFunction(name, function, null, force, CommandOrigin.Internal); } /// <summary> /// Removes a function from the function table. /// </summary> /// <param name="name"> /// The name of the function to remove. /// </param> /// <param name="origin"> /// THe origin of the caller of this API /// </param> /// <param name="force"> /// If true, the function is removed even if it is ReadOnly. /// </param> /// <exception cref="ArgumentException"> /// If <paramref name="name"/> is null or empty. /// </exception> /// <exception cref="SessionStateUnauthorizedAccessException"> /// If the function is constant. /// </exception> internal void RemoveFunction(string name, bool force, CommandOrigin origin) { if (string.IsNullOrEmpty(name)) { throw PSTraceSource.NewArgumentException(nameof(name)); } // Use the scope enumerator to find an existing function SessionStateScope scope = _currentScope; FunctionLookupPath path = new FunctionLookupPath(name); FunctionScopeItemSearcher searcher = new FunctionScopeItemSearcher( this, path, origin); if (searcher.MoveNext()) { scope = searcher.CurrentLookupScope; } scope.RemoveFunction(name, force); } /// <summary> /// Removes a function from the function table. /// </summary> /// <param name="name"> /// The name of the function to remove. /// </param> /// <param name="force"> /// If true, the function is removed even if it is ReadOnly. /// </param> /// <exception cref="ArgumentException"> /// If <paramref name="name"/> is null or empty. /// </exception> /// <exception cref="SessionStateUnauthorizedAccessException"> /// If the function is constant. /// </exception> internal void RemoveFunction(string name, bool force) { RemoveFunction(name, force, CommandOrigin.Internal); } /// <summary> /// Removes a function from the function table /// if the function was imported from the given module. /// /// BUGBUG: This is only used by the implicit remoting functions... /// </summary> /// <param name="name"> /// The name of the function to remove. /// </param> /// <param name="module"> /// Module the function might be imported from. /// </param> /// <exception cref="SessionStateUnauthorizedAccessException"> /// If the function is constant. /// </exception> internal void RemoveFunction(string name, PSModuleInfo module) { Dbg.Assert(module != null, "Caller should verify that module parameter is not null"); FunctionInfo func = GetFunction(name) as FunctionInfo; if (func != null && func.ScriptBlock != null && func.ScriptBlock.File != null && func.ScriptBlock.File.Equals(module.Path, StringComparison.OrdinalIgnoreCase)) { RemoveFunction(name, true); } } #endregion Functions } }