/
githubmirror
/
PowerShell
Обзор
Документация
Войти
/
githubmirror
/
PowerShell
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimQuery.cs
371 строка
16 KB
xtqqczze
Fix `SA1028`: Code should not contain trailing whitespace. Part 1. (#26203)
16 окт 2025, 10:58
Не верифицирован
16 окт 2025, 10:58
a10ff10
Код
Авторство
О чём код?
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Management.Automation; using System.Text; using Microsoft.Management.Infrastructure; using Microsoft.PowerShell.Cim; using Dbg = System.Management.Automation.Diagnostics; namespace Microsoft.PowerShell.Cmdletization.Cim { /// <summary> /// CimQuery supports building of queries against CIM object model. /// </summary> internal sealed class CimQuery : QueryBuilder, ISessionBoundQueryBuilder<CimSession> { private readonly StringBuilder _wqlCondition; private CimInstance _associatedObject; private string _associationName; private string _resultRole; private string _sourceRole; internal readonly Dictionary<string, object> queryOptions = new(StringComparer.OrdinalIgnoreCase); internal ClientSideQuery ClientSideQuery { get; } internal CimQuery() { _wqlCondition = new StringBuilder(); this.ClientSideQuery = new ClientSideQuery(); } #region WQL processing private void AddWqlCondition(string condition) { _wqlCondition.Append(_wqlCondition.Length != 0 ? " AND " : " WHERE "); _wqlCondition.Append('('); _wqlCondition.Append(condition); _wqlCondition.Append(')'); } private static string ObjectToWqlLiteral(object o) { if (LanguagePrimitives.IsNull(o)) { return "null"; // based on an example at https://msdn.microsoft.com/library/aa394054(VS.85).aspx } o = CimValueConverter.ConvertFromDotNetToCim(o); PSObject pso = PSObject.AsPSObject(o); Type type = pso.BaseObject.GetType(); TypeCode typeCode = LanguagePrimitives.GetTypeCode(type); if (typeCode == TypeCode.String) { string s = o.ToString(); s = s.Replace("\\", "\\\\"); s = s.Replace("'", "\\'"); return "'" + s + "'"; } if (typeCode == TypeCode.Char) { return ObjectToWqlLiteral(LanguagePrimitives.ConvertTo(o, typeof(string), CultureInfo.InvariantCulture)); } if (typeCode == TypeCode.DateTime) { var dateTime = (DateTime)LanguagePrimitives.ConvertTo(o, typeof(DateTime), CultureInfo.InvariantCulture); string result = ClrFacade.ToDmtfDateTime(dateTime); return "'" + result + "'"; } if (type == typeof(TimeSpan)) { // WMIv1 does not support using interval literals in a WQL query return null; } if (LanguagePrimitives.IsNumeric(typeCode)) { return (string)LanguagePrimitives.ConvertTo(o, typeof(string), CultureInfo.InvariantCulture); } if (LanguagePrimitives.IsBooleanType(type)) { if ((bool)LanguagePrimitives.ConvertTo(o, typeof(bool), CultureInfo.InvariantCulture)) { return "TRUE"; // based on https://msdn.microsoft.com/library/aa394054(VS.85).aspx } return "FALSE"; // based on https://msdn.microsoft.com/library/aa394054(VS.85).aspx } throw CimValueConverter.GetInvalidCastException( null, /* inner exception */ "InvalidCimQueryCast", o, CmdletizationResources.CimConversion_WqlQuery); } private static string WildcardToWqlLikeOperand(WildcardPattern wildcardPattern, out bool needsClientSideFiltering) { string nakedOperand = WildcardPatternToCimQueryParser.Parse(wildcardPattern, out needsClientSideFiltering); return ObjectToWqlLiteral(nakedOperand); } #endregion private static string GetMatchConditionForEqualityOperator(string propertyName, object propertyValue) { string condition; // comparison of 'char' is case-sensitive in WQL (comparison of 'string' is case-insensitive) if (propertyValue is char) { char c = (char)propertyValue; char lowerCase = char.ToLowerInvariant(c); char upperCase = char.ToUpperInvariant(c); string lowerCaseLiteral = CimQuery.ObjectToWqlLiteral(lowerCase); string upperCaseLiteral = CimQuery.ObjectToWqlLiteral(upperCase); Dbg.Assert(!string.IsNullOrWhiteSpace(lowerCaseLiteral), "All characters are assumed to have valid WQL literals (lower)"); Dbg.Assert(!string.IsNullOrWhiteSpace(upperCaseLiteral), "All characters are assumed to have valid WQL literals (upper)"); condition = string.Format( CultureInfo.InvariantCulture, "(({0} = {1}) OR ({0} = {2}))", propertyName, lowerCaseLiteral, upperCaseLiteral); return condition; } string wqlLiteral = CimQuery.ObjectToWqlLiteral(propertyValue); if (string.IsNullOrWhiteSpace(wqlLiteral)) { return null; } condition = string.Format( CultureInfo.InvariantCulture, "({0} = {1})", propertyName, wqlLiteral); return condition; } private static string GetMatchConditionForLikeOperator(string propertyName, object propertyValue) { var expectedPropertyValueAsString = (string)LanguagePrimitives.ConvertTo(propertyValue, typeof(string), CultureInfo.InvariantCulture); var expectedPropertyValueAsPowerShellWildcard = WildcardPattern.Get(expectedPropertyValueAsString, WildcardOptions.IgnoreCase); bool needsClientSideFiltering; // not used because for simplicity all results go through post-filtering var expectedPropertyValueAsWqlWildcard = CimQuery.WildcardToWqlLikeOperand(expectedPropertyValueAsPowerShellWildcard, out needsClientSideFiltering); string condition = string.Format( CultureInfo.InvariantCulture, "({0} LIKE {1})", propertyName, expectedPropertyValueAsWqlWildcard); return condition; } private static string GetMatchCondition(string propertyName, IEnumerable propertyValues, bool wildcardsEnabled) { List<string> individualConditions = propertyValues .Cast<object>() .Select(propertyValue => wildcardsEnabled ? GetMatchConditionForLikeOperator(propertyName, propertyValue) : GetMatchConditionForEqualityOperator(propertyName, propertyValue)) .Where(static individualCondition => !string.IsNullOrWhiteSpace(individualCondition)) .ToList(); if (individualConditions.Count == 0) { return null; } string result = string.Join(" OR ", individualConditions); return result; } #region Public inputs from cmdletization /// <summary> /// Modifies the query, so that it only returns objects with a given property value. /// </summary> /// <param name="propertyName">Property name to query on.</param> /// <param name="allowedPropertyValues">Property values to accept in the query.</param> /// <param name="wildcardsEnabled"> /// <see langword="true"/> if <paramref name="allowedPropertyValues"/> should be treated as a <see cref="string"/> containing a wildcard pattern; /// <see langword="false"/> otherwise. /// </param> /// <param name="behaviorOnNoMatch"> /// Describes how to handle filters that didn't match any objects /// </param> public override void FilterByProperty(string propertyName, IEnumerable allowedPropertyValues, bool wildcardsEnabled, BehaviorOnNoMatch behaviorOnNoMatch) { this.ClientSideQuery.FilterByProperty(propertyName, allowedPropertyValues, wildcardsEnabled, behaviorOnNoMatch); string matchCondition = CimQuery.GetMatchCondition(propertyName, allowedPropertyValues, wildcardsEnabled); if (!string.IsNullOrWhiteSpace(matchCondition)) { this.AddWqlCondition(matchCondition); } } /// <summary> /// Modifies the query, so that it does not return objects with a given property value. /// </summary> /// <param name="propertyName">Property name to query on.</param> /// <param name="excludedPropertyValues">Property values to reject in the query.</param> /// <param name="wildcardsEnabled"> /// <see langword="true"/> if <paramref name="excludedPropertyValues"/> should be treated as a <see cref="string"/> containing a wildcard pattern; /// <see langword="false"/> otherwise. /// </param> /// <param name="behaviorOnNoMatch"> /// Describes how to handle filters that didn't match any objects /// </param> public override void ExcludeByProperty(string propertyName, IEnumerable excludedPropertyValues, bool wildcardsEnabled, BehaviorOnNoMatch behaviorOnNoMatch) { this.ClientSideQuery.ExcludeByProperty(propertyName, excludedPropertyValues, wildcardsEnabled, behaviorOnNoMatch); string positiveWqlCondition = CimQuery.GetMatchCondition(propertyName, excludedPropertyValues, wildcardsEnabled); if (!string.IsNullOrWhiteSpace(positiveWqlCondition)) { string condition = string.Format( CultureInfo.InvariantCulture, "NOT ({0})", positiveWqlCondition); this.AddWqlCondition(condition); } } /// <summary> /// Modifies the query, so that it returns only objects that have a property value greater than or equal to a <paramref name="minPropertyValue"/> threshold. /// </summary> /// <param name="propertyName">Property name to query on.</param> /// <param name="minPropertyValue">Minimum property value.</param> /// <param name="behaviorOnNoMatch"> /// Describes how to handle filters that didn't match any objects /// </param> public override void FilterByMinPropertyValue(string propertyName, object minPropertyValue, BehaviorOnNoMatch behaviorOnNoMatch) { this.ClientSideQuery.FilterByMinPropertyValue(propertyName, minPropertyValue, behaviorOnNoMatch); string wqlLiteral = CimQuery.ObjectToWqlLiteral(minPropertyValue); if (!string.IsNullOrWhiteSpace(wqlLiteral)) { string condition = string.Format( CultureInfo.InvariantCulture, "{0} >= {1}", propertyName, wqlLiteral); this.AddWqlCondition(condition); } } /// <summary> /// Modifies the query, so that it returns only objects that have a property value less than or equal to a <paramref name="maxPropertyValue"/> threshold. /// </summary> /// <param name="propertyName">Property name to query on.</param> /// <param name="maxPropertyValue">Maximum property value.</param> /// <param name="behaviorOnNoMatch"> /// Describes how to handle filters that didn't match any objects /// </param> public override void FilterByMaxPropertyValue(string propertyName, object maxPropertyValue, BehaviorOnNoMatch behaviorOnNoMatch) { this.ClientSideQuery.FilterByMaxPropertyValue(propertyName, maxPropertyValue, behaviorOnNoMatch); string wqlLiteral = CimQuery.ObjectToWqlLiteral(maxPropertyValue); if (!string.IsNullOrWhiteSpace(wqlLiteral)) { string condition = string.Format( CultureInfo.InvariantCulture, "{0} <= {1}", propertyName, CimQuery.ObjectToWqlLiteral(maxPropertyValue)); this.AddWqlCondition(condition); } } /// <summary> /// Modifies the query, so that it returns only objects associated with <paramref name="associatedInstance"/> /// </summary> /// <param name="associatedInstance">Object that query results have to be associated with.</param> /// <param name="associationName">Name of the association.</param> /// <param name="resultRole">Name of the role that <paramref name="associatedInstance"/> has in the association.</param> /// <param name="sourceRole">Name of the role that query results have in the association.</param> /// <param name="behaviorOnNoMatch"> /// Describes how to handle filters that didn't match any objects /// </param> public override void FilterByAssociatedInstance(object associatedInstance, string associationName, string sourceRole, string resultRole, BehaviorOnNoMatch behaviorOnNoMatch) { this.ClientSideQuery.FilterByAssociatedInstance(associatedInstance, associationName, sourceRole, resultRole, behaviorOnNoMatch); _associatedObject = associatedInstance as CimInstance; _associationName = associationName; _resultRole = resultRole; _sourceRole = sourceRole; } /// <summary> /// Sets a query option. /// </summary> /// <param name="optionName"></param> /// <param name="optionValue"></param> public override void AddQueryOption(string optionName, object optionValue) { ArgumentException.ThrowIfNullOrEmpty(optionName); ArgumentNullException.ThrowIfNull(optionValue); this.queryOptions[optionName] = optionValue; } #endregion Cmdletization inputs #region Outputs for doing the query internal StartableJob GetQueryJob(CimJobContext jobContext) { if (_associationName == null) { return new QueryInstancesJob(jobContext, this, _wqlCondition.ToString()); } else { return new EnumerateAssociatedInstancesJob(jobContext, this, _associatedObject, _associationName, _resultRole, _sourceRole); } } internal bool IsMatchingResult(CimInstance result) { Dbg.Assert(result != null, "Caller should verify result != null"); return this.ClientSideQuery.IsResultMatchingClientSideQuery(result); } internal IEnumerable<ClientSideQuery.NotFoundError> GenerateNotFoundErrors() { return this.ClientSideQuery.GenerateNotFoundErrors(); } #endregion CimSession ISessionBoundQueryBuilder<CimSession>.GetTargetSession() { if (_associatedObject != null) { return CimCmdletAdapter.GetSessionOfOriginFromCimInstance(_associatedObject); } return null; } /// <summary> /// Returns a string that represents the current CIM query. /// </summary> /// <returns>A string that represents the current CIM query.</returns> public override string ToString() { return _wqlCondition.ToString(); } } }