创建用于访问数据存储的 Cmdlet
本部分介绍如何创建可通过 Windows PowerShell 提供程序访问存储的数据的 cmdlet。 这种类型的 cmdlet 使用 Windows PowerShell 运行时的 Windows PowerShell 提供程序基础结构,因此,该 cmdlet 类必须派生自PSCmdlet基类。
此处所述的 Select-Str cmdlet 可在文件或对象中查找并选择字符串。 可通过 Path
cmdlet 的参数或通过参数隐式指定用于标识字符串的模式 Script
。
该 cmdlet 旨在使用派生自Icontentcmdletprovider的任何 Windows PowerShell 提供程序。 例如,cmdlet 可以指定由 Windows PowerShell 提供的 FileSystem 提供程序或变量提供程序。 aboutWindows PowerShell 提供程序的详细信息,请参阅设计你的 Windows PowerShell 提供程序。
定义 Cmdlet 类
创建 cmdlet 的第一步是始终命名 cmdlet 并声明实现 cmdlet 的 .NET 类。 此 cmdlet 将检测某些字符串,因此在此处选择的谓词名称为 "Select",由 Verbscommon 类定义。 使用名词 name "Str",因为该 cmdlet 作用于字符串。 请注意,在下面的声明中,cmdlet 谓词和名词名称反映在 cmdlet 类的名称中。 有关批准的 cmdlet 谓词的详细信息,请参阅 Cmdlet 谓词名称。
此 cmdlet 的 .net 类必须派生自PSCmdlet基类,因为它提供 Windows PowerShell 运行时所需的支持,以公开 Windows PowerShell 提供程序基础结构。 请注意,此 cmdlet 还利用 .NET Framework 正则表达式类,如system.text.regularexpressions。
下面的代码是此 Select-Str cmdlet 的类定义。
[Cmdlet(VerbsCommon.Select, "Str", DefaultParameterSetName="PatternParameterSet")]
public class SelectStringCommand : PSCmdlet
此 cmdlet 通过将 DefaultParameterSetName
attribute 关键字添加到类声明来定义默认参数集。 PatternParameterSet
如果未指定参数,则使用默认参数集 Script
。 有关此参数集的详细信息,请参阅 Pattern
Script
下一节中的和参数讨论。
定义用于数据访问的参数
此 cmdlet 定义允许用户访问和检查存储数据的多个参数。 这些参数包括一个 Path
参数,该参数指示数据存储区的位置、一个 Pattern
指定在搜索中使用的模式的参数,以及一些支持搜索执行方式的其他参数。
备注
有关定义参数的基础知识的详细信息,请参阅 添加处理命令行输入的参数。
声明 Path 参数
若要定位数据存储,此 cmdlet 必须使用 Windows PowerShell 路径标识用于访问数据存储区的 Windows PowerShell 提供程序。 因此,它定义了 Path
类型字符串数组的参数,以指示提供程序的位置。
[Parameter(
Position = 0,
ParameterSetName = "ScriptParameterSet",
Mandatory = true)]
[Parameter(
Position = 0,
ParameterSetName = "PatternParameterSet",
ValueFromPipeline = true,
Mandatory = true)]
[Alias("PSPath")]
public string[] Path
{
get { return paths; }
set { paths = value; }
}
private string[] paths;
请注意,此参数属于两个不同的参数集,并且具有别名。
两个 Parameterattribute 特性声明该 Path
参数属于 ScriptParameterSet
和的 PatternParameterSet
。 有关参数集的详细信息,请参阅 将参数集添加到 Cmdlet。
Aliasattribute特性为参数声明一个 PSPath
别名 Path
。) 为了与访问 Windows PowerShell 提供程序的其他 cmdlet 进行一致性,强烈建议声明此别名。 aboutWindows PowerShell 路径的详细信息,请参阅Windows PowerShell 工作方式中的 "powershell 路径概念"。
声明模式参数
若要指定要搜索的模式,此 cmdlet 将声明一个 Pattern
字符串数组参数。 在数据存储区中找到任何模式时,将返回一个正值结果。 请注意,这些模式可编译为已编译的正则表达式的数组或用于文本搜索的通配符模式的数组。
[Parameter(
Position = 1,
ParameterSetName = "PatternParameterSet",
Mandatory = true)]
public string[] Pattern
{
get { return patterns; }
set { patterns = value; }
}
private string[] patterns;
private Regex[] regexPattern;
private WildcardPattern[] wildcardPattern;
如果指定此参数,则 cmdlet 将使用默认参数集 PatternParameterSet
。 在这种情况下,该 cmdlet 使用此处指定的模式来选择字符串。 与此相反, Script
参数还可用于提供包含模式的脚本。 Script
和 Pattern
参数定义两个单独的参数集,因此它们互相排斥。
声明搜索支持参数
此 cmdlet 定义以下支持参数,这些参数可用于修改 cmdlet 的搜索功能。
Script
参数指定可用于为 cmdlet 提供备用搜索机制的脚本块。 脚本必须包含用于匹配的模式,并返回一个 system.web 对象。 请注意,此参数也是用于标识参数集的唯一参数 ScriptParameterSet
。 当 Windows PowerShell 运行时发现此参数时,它仅使用属于 ScriptParameterSet
参数集的参数。
[Parameter(
Position = 1,
ParameterSetName = "ScriptParameterSet",
Mandatory = true)]
public ScriptBlock Script
{
set { script = value; }
get { return script; }
}
ScriptBlock script;
SimpleMatch
参数是一个开关参数,该参数指示 cmdlet 是否在提供时显式匹配模式。 当用户在命令行 () 中指定参数时 true
,该 cmdlet 将在提供时使用模式。 如果未指定 (false
) 参数,则该 cmdlet 将使用正则表达式。 此参数的默认值为 false
。
[Parameter]
public SwitchParameter SimpleMatch
{
get { return simpleMatch; }
set { simpleMatch = value; }
}
private bool simpleMatch;
CaseSensitive
参数是一个开关参数,用于指示是否执行区分大小写的搜索。 当用户在命令行 () 中指定参数时 true
,该 cmdlet 将在比较模式时检查字符的大小写。 如果未指定 (false
) 参数,则 cmdlet 不区分大小写。 例如,"Myfile.txt" 和 "myfile.txt" 都将作为正命中返回。 此参数的默认值为 false
。
[Parameter]
public SwitchParameter CaseSensitive
{
get { return caseSensitive; }
set { caseSensitive = value; }
}
private bool caseSensitive;
Exclude
和 Include
参数标识在搜索中显式排除或包括在搜索中的项。 默认情况下,该 cmdlet 将搜索数据存储区中的所有项。 但是,若要限制 cmdlet 执行的搜索,可以使用这些参数来显式指示要包括在搜索中或省略的项。
[Parameter]
public SwitchParameter CaseSensitive
{
get { return caseSensitive; }
set { caseSensitive = value; }
}
private bool caseSensitive;
[Parameter]
[ValidateNotNullOrEmpty]
public string[] Include
{
get
{
return includeStrings;
}
set
{
includeStrings = value;
this.include = new WildcardPattern[includeStrings.Length];
for (int i = 0; i < includeStrings.Length; i++)
{
this.include[i] = new WildcardPattern(includeStrings[i], WildcardOptions.IgnoreCase);
}
}
}
internal string[] includeStrings = null;
internal WildcardPattern[] include = null;
声明参数集
此 cmdlet 使用两个参数集 (ScriptParameterSet
和 PatternParameterSet
,这是默认的) 作为数据访问中使用的两个参数集的名称。 PatternParameterSet
默认参数集,并且在指定参数时使用 Pattern
。 ScriptParameterSet
当用户通过参数指定替代搜索机制时使用 Script
。 有关参数集的详细信息,请参阅 将参数集添加到 Cmdlet。
重写输入处理方法
Cmdlet 必须重写 PSCmdlet 类的一个或多个输入处理方法。 有关输入处理方法的详细信息,请参阅 创建第一个 Cmdlet。
此 cmdlet 将重写 BeginProcessing 方法,以便在启动时生成已编译的正则表达式的数组。 这会提高不使用简单匹配的搜索过程中的性能。
protected override void BeginProcessing()
{
WriteDebug("Validating patterns.");
if (patterns != null)
{
foreach(string pattern in patterns)
{
if (pattern == null)
ThrowTerminatingError(new ErrorRecord(
new ArgumentNullException(
"Search pattern cannot be null."),
"NullSearchPattern",
ErrorCategory.InvalidArgument,
pattern)
);
}
WriteVerbose("Search pattern(s) are valid.");
// If a simple match is not specified, then
// compile the regular expressions once.
if (!simpleMatch)
{
WriteDebug("Compiling search regular expressions.");
RegexOptions regexOptions = RegexOptions.Compiled;
if (!caseSensitive)
regexOptions |= RegexOptions.Compiled;
regexPattern = new Regex[patterns.Length];
for (int i = 0; i < patterns.Length; i++)
{
try
{
regexPattern[i] = new Regex(patterns[i], regexOptions);
}
catch (ArgumentException ex)
{
ThrowTerminatingError(new ErrorRecord(
ex,
"InvalidRegularExpression",
ErrorCategory.InvalidArgument,
patterns[i]
));
}
} //Loop through patterns to create RegEx objects.
WriteVerbose("Pattern(s) compiled into regular expressions.");
}// If not a simple match.
// If a simple match is specified, then compile the
// wildcard patterns once.
else
{
WriteDebug("Compiling search wildcards.");
WildcardOptions wildcardOptions = WildcardOptions.Compiled;
if (!caseSensitive)
{
wildcardOptions |= WildcardOptions.IgnoreCase;
}
wildcardPattern = new WildcardPattern[patterns.Length];
for (int i = 0; i < patterns.Length; i++)
{
wildcardPattern[i] =
new WildcardPattern(patterns[i], wildcardOptions);
}
WriteVerbose("Pattern(s) compiled into wildcard expressions.");
}// If match is a simple match.
}// If valid patterns are available.
}// End of function BeginProcessing().
此 cmdlet 还将重写 ProcessRecord 方法,以处理用户在命令行上进行的字符串选择。 它通过调用私有 MatchString 方法,以自定义对象的形式写入字符串选择的结果。
protected override void ProcessRecord()
{
UInt64 lineNumber = 0;
MatchInfo result;
ArrayList nonMatches = new ArrayList();
// Walk the list of paths and search the contents for
// any of the specified patterns.
foreach (string psPath in paths)
{
// Once the filepaths are expanded, we may have more than one
// path, so process all referenced paths.
foreach(PathInfo path in
SessionState.Path.GetResolvedPSPathFromPSPath(psPath)
)
{
WriteVerbose("Processing path " + path.Path);
// Check if the path represents one of the items to be
// excluded. If so, continue to next path.
if (!MeetsIncludeExcludeCriteria(path.ProviderPath))
continue;
// Get the content reader for the item(s) at the
// specified path.
Collection<IContentReader> readerCollection = null;
try
{
readerCollection =
this.InvokeProvider.Content.GetReader(path.Path);
}
catch (PSNotSupportedException ex)
{
WriteError(new ErrorRecord(ex,
"ContentAccessNotSupported",
ErrorCategory.NotImplemented,
path.Path)
);
return;
}
foreach(IContentReader reader in readerCollection)
{
// Reset the line number for this path.
lineNumber = 0;
// Read in a single block (line in case of a file)
// from the object.
IList items = reader.Read(1);
// Read and process one block(line) at a time until
// no more blocks(lines) exist.
while (items != null && items.Count == 1)
{
// Increment the line number each time a line is
// processed.
lineNumber++;
String message = String.Format("Testing line {0} : {1}",
lineNumber, items[0]);
WriteDebug(message);
result = SelectString(items[0]);
if (result != null)
{
result.Path = path.Path;
result.LineNumber = lineNumber;
WriteObject(result);
}
else
{
// Add the block(line) that did not match to the
// collection of non matches , which will be stored
// in the SessionState variable $NonMatches
nonMatches.Add(items[0]);
}
// Get the next line from the object.
items = reader.Read(1);
}// While loop for reading one line at a time.
}// Foreach loop for reader collection.
}// Foreach loop for processing referenced paths.
}// Foreach loop for walking of path list.
// Store the list of non-matches in the
// session state variable $NonMatches.
try
{
this.SessionState.PSVariable.Set("NonMatches", nonMatches);
}
catch (SessionStateUnauthorizedAccessException ex)
{
WriteError(new ErrorRecord(ex,
"CannotWriteVariableNonMatches",
ErrorCategory.InvalidOperation,
nonMatches)
);
}
}// End of protected override void ProcessRecord().
访问内容
你的 cmdlet 必须打开 Windows PowerShell 路径指示的提供程序,以便它可以访问数据。 运行空间的 Sessionstate 对象用于访问该提供程序,而该 Cmdlet 的 PSCmdlet. Invokeprovider * 属性用于打开该提供程序时使用的属性。 通过检索打开的提供程序的 Providerintrinsics 对象来提供对内容的访问。
此示例 Select-Str cmdlet 使用 Providerintrinsics * 属性来公开要扫描的内容。 然后,它可以调用Contentcmdletproviderintrinsics. system.diagnostics.symbolstore.isymbolbinder1.getreader *方法,并传递所需的 Windows PowerShell 路径。
代码示例
下面的代码演示此版本 Select-Str cmdlet 的实现。 请注意,此代码包括 cmdlet 类、cmdlet 使用的私有方法和用于注册 cmdlet 的 Windows PowerShell 管理单元代码。 有关注册 cmdlet 的详细信息,请参阅 生成 cmdlet。
//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
using System;
using System.Text.RegularExpressions;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
namespace Microsoft.Samples.PowerShell.Commands
{
#region SelectStringCommand
/// <summary>
/// This cmdlet searches through PSObjects for particular patterns.
/// </summary>
/// <remarks>
/// This cmdlet can be used to search any object, such as a file or a
/// variable, whose provider exposes methods for reading and writing
/// content.
/// </remarks>
[Cmdlet(VerbsCommon.Select, "Str", DefaultParameterSetName="PatternParameterSet")]
public class SelectStringCommand : PSCmdlet
{
#region Parameters
/// <summary>
/// Declare a Path parameter that specifies where the data is stored.
/// This parameter must specify a PowerShell that indicates the
/// PowerShell provider that is used to access the objects to be
/// searched for matching patterns. This parameter should also have
/// a PSPath alias to provide consistency with other cmdlets that use
/// PowerShell providers.
/// </summary>
/// <value>Path of the object(s) to search.</value>
[Parameter(
Position = 0,
ParameterSetName = "ScriptParameterSet",
Mandatory = true)]
[Parameter(
Position = 0,
ParameterSetName = "PatternParameterSet",
ValueFromPipeline = true,
Mandatory = true)]
[Alias("PSPath")]
public string[] Path
{
get { return paths; }
set { paths = value; }
}
private string[] paths;
/// <summary>
/// Declare a Pattern parameter that specifies the pattern(s)
/// used to find matching patterns in the string representation
/// of the objects. A positive result will be returned
/// if any of the patterns are found in the objects.
/// </summary>
/// <remarks>
/// The patterns will be compiled into an array of wildcard
/// patterns for a simple match (literal string matching),
/// or the patterns will be converted into an array of compiled
/// regular expressions.
/// </remarks>
/// <value>Array of patterns to search.</value>
[Parameter(
Position = 1,
ParameterSetName = "PatternParameterSet",
Mandatory = true)]
public string[] Pattern
{
get { return patterns; }
set { patterns = value; }
}
private string[] patterns;
private Regex[] regexPattern;
private WildcardPattern[] wildcardPattern;
/// <summary>
/// Declare a Script parameter that specifies a script block
/// that is called to perform the matching operations
/// instead of the matching performed by the cmdlet.
/// </summary>
/// <value>Script block that will be called for matching</value>
[Parameter(
Position = 1,
ParameterSetName = "ScriptParameterSet",
Mandatory = true)]
public ScriptBlock Script
{
set { script = value; }
get { return script; }
}
ScriptBlock script;
/// <summary>
/// Declare a switch parameter that specifies if the pattern(s) are used
/// literally. If not (default), searching is
/// done using regular expressions.
/// </summary>
/// <value>If True, a literal pattern is used.</value>
[Parameter]
public SwitchParameter SimpleMatch
{
get { return simpleMatch; }
set { simpleMatch = value; }
}
private bool simpleMatch;
/// <summary>
/// Declare a switch parameter that specifies if a case-sensitive
/// search is performed. If not (default), a case-insensitive search
/// is performed.
/// </summary>
/// <value>If True, a case-sensitive search is made.</value>
[Parameter]
public SwitchParameter CaseSensitive
{
get { return caseSensitive; }
set { caseSensitive = value; }
}
private bool caseSensitive;
/// <summary>
/// Declare an Include parameter that species which
/// specific items are searched. When this parameter
/// is used, items that are not listed here are omitted
/// from the search.
/// </summary>
[Parameter]
[ValidateNotNullOrEmpty]
public string[] Include
{
get
{
return includeStrings;
}
set
{
includeStrings = value;
this.include = new WildcardPattern[includeStrings.Length];
for (int i = 0; i < includeStrings.Length; i++)
{
this.include[i] = new WildcardPattern(includeStrings[i], WildcardOptions.IgnoreCase);
}
}
}
internal string[] includeStrings = null;
internal WildcardPattern[] include = null;
/// <summary>
/// Declare an Exclude parameter that species which
/// specific items are omitted from the search.
/// </summary>
///
[Parameter]
[ValidateNotNullOrEmpty]
public string[] Exclude
{
get
{
return excludeStrings;
}
set
{
excludeStrings = value;
this.exclude = new WildcardPattern[excludeStrings.Length];
for (int i = 0; i < excludeStrings.Length; i++)
{
this.exclude[i] = new WildcardPattern(excludeStrings[i], WildcardOptions.IgnoreCase);
}
}
}
internal string[] excludeStrings;
internal WildcardPattern[] exclude;
#endregion Parameters
#region Overrides
/// <summary>
/// If regular expressions are used for pattern matching,
/// then build an array of compiled regular expressions
/// at startup. This increases performance during scanning
/// operations when simple matching is not used.
/// </summary>
protected override void BeginProcessing()
{
WriteDebug("Validating patterns.");
if (patterns != null)
{
foreach(string pattern in patterns)
{
if (pattern == null)
ThrowTerminatingError(new ErrorRecord(
new ArgumentNullException(
"Search pattern cannot be null."),
"NullSearchPattern",
ErrorCategory.InvalidArgument,
pattern)
);
}
WriteVerbose("Search pattern(s) are valid.");
// If a simple match is not specified, then
// compile the regular expressions once.
if (!simpleMatch)
{
WriteDebug("Compiling search regular expressions.");
RegexOptions regexOptions = RegexOptions.Compiled;
if (!caseSensitive)
regexOptions |= RegexOptions.Compiled;
regexPattern = new Regex[patterns.Length];
for (int i = 0; i < patterns.Length; i++)
{
try
{
regexPattern[i] = new Regex(patterns[i], regexOptions);
}
catch (ArgumentException ex)
{
ThrowTerminatingError(new ErrorRecord(
ex,
"InvalidRegularExpression",
ErrorCategory.InvalidArgument,
patterns[i]
));
}
} //Loop through patterns to create RegEx objects.
WriteVerbose("Pattern(s) compiled into regular expressions.");
}// If not a simple match.
// If a simple match is specified, then compile the
// wildcard patterns once.
else
{
WriteDebug("Compiling search wildcards.");
WildcardOptions wildcardOptions = WildcardOptions.Compiled;
if (!caseSensitive)
{
wildcardOptions |= WildcardOptions.IgnoreCase;
}
wildcardPattern = new WildcardPattern[patterns.Length];
for (int i = 0; i < patterns.Length; i++)
{
wildcardPattern[i] =
new WildcardPattern(patterns[i], wildcardOptions);
}
WriteVerbose("Pattern(s) compiled into wildcard expressions.");
}// If match is a simple match.
}// If valid patterns are available.
}// End of function BeginProcessing().
/// <summary>
/// Process the input and search for the specified patterns.
/// </summary>
protected override void ProcessRecord()
{
UInt64 lineNumber = 0;
MatchInfo result;
ArrayList nonMatches = new ArrayList();
// Walk the list of paths and search the contents for
// any of the specified patterns.
foreach (string psPath in paths)
{
// Once the filepaths are expanded, we may have more than one
// path, so process all referenced paths.
foreach(PathInfo path in
SessionState.Path.GetResolvedPSPathFromPSPath(psPath)
)
{
WriteVerbose("Processing path " + path.Path);
// Check if the path represents one of the items to be
// excluded. If so, continue to next path.
if (!MeetsIncludeExcludeCriteria(path.ProviderPath))
continue;
// Get the content reader for the item(s) at the
// specified path.
Collection<IContentReader> readerCollection = null;
try
{
readerCollection =
this.InvokeProvider.Content.GetReader(path.Path);
}
catch (PSNotSupportedException ex)
{
WriteError(new ErrorRecord(ex,
"ContentAccessNotSupported",
ErrorCategory.NotImplemented,
path.Path)
);
return;
}
foreach(IContentReader reader in readerCollection)
{
// Reset the line number for this path.
lineNumber = 0;
// Read in a single block (line in case of a file)
// from the object.
IList items = reader.Read(1);
// Read and process one block(line) at a time until
// no more blocks(lines) exist.
while (items != null && items.Count == 1)
{
// Increment the line number each time a line is
// processed.
lineNumber++;
String message = String.Format("Testing line {0} : {1}",
lineNumber, items[0]);
WriteDebug(message);
result = SelectString(items[0]);
if (result != null)
{
result.Path = path.Path;
result.LineNumber = lineNumber;
WriteObject(result);
}
else
{
// Add the block(line) that did not match to the
// collection of non matches , which will be stored
// in the SessionState variable $NonMatches
nonMatches.Add(items[0]);
}
// Get the next line from the object.
items = reader.Read(1);
}// While loop for reading one line at a time.
}// Foreach loop for reader collection.
}// Foreach loop for processing referenced paths.
}// Foreach loop for walking of path list.
// Store the list of non-matches in the
// session state variable $NonMatches.
try
{
this.SessionState.PSVariable.Set("NonMatches", nonMatches);
}
catch (SessionStateUnauthorizedAccessException ex)
{
WriteError(new ErrorRecord(ex,
"CannotWriteVariableNonMatches",
ErrorCategory.InvalidOperation,
nonMatches)
);
}
}// End of protected override void ProcessRecord().
#endregion Overrides
#region PrivateMethods
/// <summary>
/// Check for a match using the input string and the pattern(s)
/// specified.
/// </summary>
/// <param name="input">The string to test.</param>
/// <returns>MatchInfo object containing information about
/// result of a match</returns>
private MatchInfo SelectString(object input)
{
string line = null;
try
{
// Convert the object to a string type
// safely using language support methods
line = (string)LanguagePrimitives.ConvertTo(
input,
typeof(string)
);
line = line.Trim(' ','\t');
}
catch (PSInvalidCastException ex)
{
WriteError(new ErrorRecord(
ex,
"CannotCastObjectToString",
ErrorCategory.InvalidOperation,
input)
);
return null;
}
MatchInfo result = null;
// If a scriptblock has been specified, call it
// with the path for processing. It will return
// one object.
if (script != null)
{
WriteDebug("Executing script block.");
Collection<PSObject> psObjects =
script.Invoke(
line,
simpleMatch,
caseSensitive
);
foreach (PSObject psObject in psObjects)
{
if (LanguagePrimitives.IsTrue(psObject))
{
result = new MatchInfo();
result.Line = line;
result.IgnoreCase = !caseSensitive;
break;
} //End of If.
} //End ForEach loop.
} // End of If if script exists.
// If script block exists, see if this line matches any
// of the match patterns.
else
{
int patternIndex = 0;
while (patternIndex < patterns.Length)
{
if ((simpleMatch &&
wildcardPattern[patternIndex].IsMatch(line))
|| (regexPattern != null
&& regexPattern[patternIndex].IsMatch(line))
)
{
result = new MatchInfo();
result.IgnoreCase = !caseSensitive;
result.Line = line;
result.Pattern = patterns[patternIndex];
break;
}
patternIndex++;
}// While loop through patterns.
}// Else for no script block specified.
return result;
}// End of SelectString
/// <summary>
/// Check whether the supplied name meets the include/exclude criteria.
/// That is - it's on the include list if the include list was
/// specified, and not on the exclude list if the exclude list was specified.
/// </summary>
/// <param name="path">path to validate</param>
/// <returns>True if the path is acceptable.</returns>
private bool MeetsIncludeExcludeCriteria(string path)
{
bool ok = false;
// See if the file is on the include list.
if (this.include != null)
{
foreach (WildcardPattern patternItem in this.include)
{
if (patternItem.IsMatch(path))
{
ok = true;
break;
}
}
}
else
{
ok = true;
}
if (!ok)
return false;
// See if the file is on the exclude list.
if (this.exclude != null)
{
foreach (WildcardPattern patternItem in this.exclude)
{
if (patternItem.IsMatch(path))
{
ok = false;
break;
}
}
}
return ok;
} //MeetsIncludeExcludeCriteria
#endregion Private Methods
}// class SelectStringCommand
#endregion SelectStringCommand
#region MatchInfo
/// <summary>
/// Class representing the result of a pattern/literal match
/// that is passed through the pipeline by the Select-Str cmdlet.
/// </summary>
public class MatchInfo
{
/// <summary>
/// Indicates if the match was done ignoring case.
/// </summary>
/// <value>True if case was ignored.</value>
public bool IgnoreCase
{
get { return ignoreCase; }
set { ignoreCase = value; }
}
private bool ignoreCase;
/// <summary>
/// Specifies the number of the matching line.
/// </summary>
/// <value>The number of the matching line.</value>
public UInt64 LineNumber
{
get { return lineNumber; }
set { lineNumber = value; }
}
private UInt64 lineNumber;
/// <summary>
/// Specifies the text of the matching line.
/// </summary>
/// <value>The text of the matching line.</value>
public string Line
{
get { return line; }
set { line = value; }
}
private string line;
/// <summary>
/// Specifies the full path of the object(file) containing the
/// matching line.
/// </summary>
/// <remarks>
/// It will be "inputStream" if the object came from the input
/// stream.
/// </remarks>
/// <value>The path name</value>
public string Path
{
get { return path; }
set
{
pathSet = true;
path = value;
}
}
private string path;
private bool pathSet;
/// <summary>
/// Specifies the pattern that was used in the match.
/// </summary>
/// <value>The pattern string</value>
public string Pattern
{
get { return pattern; }
set { pattern = value; }
}
private string pattern;
private const string MatchFormat = "{0}:{1}:{2}";
/// <summary>
/// Returns the string representation of this object. The format
/// depends on whether a path has been set for this object or
/// not.
/// </summary>
/// <remarks>
/// If the path component is set, as would be the case when
/// matching in a file, ToString() returns the path, line
/// number and line text. If path is not set, then just the
/// line text is presented.
/// </remarks>
/// <returns>The string representation of the match object.</returns>
public override string ToString()
{
if (pathSet)
return String.Format(
System.Threading.Thread.CurrentThread.CurrentCulture,
MatchFormat,
this.path,
this.lineNumber,
this.line
);
else
return this.line;
}
}// End class MatchInfo
#endregion
#region PowerShell snap-in
/// <summary>
/// Create a PowerShell snap-in for the Select-Str cmdlet.
/// </summary>
[RunInstaller(true)]
public class SelectStringPSSnapIn : PSSnapIn
{
/// <summary>
/// Create an instance of the SelectStrPSSnapin class.
/// </summary>
public SelectStringPSSnapIn()
: base()
{
}
/// <summary>
/// Specify the name of the PowerShell snap-in.
/// </summary>
public override string Name
{
get
{
return "SelectStrPSSnapIn";
}
}
/// <summary>
/// Specify the vendor of the PowerShell snap-in.
/// </summary>
public override string Vendor
{
get
{
return "Microsoft";
}
}
/// <summary>
/// Specify the localization resource information for the vendor.
/// Use the format: SnapinName,VendorName.
/// </summary>
public override string VendorResource
{
get
{
return "SelectStrSnapIn,Microsoft";
}
}
/// <summary>
/// Specify the description of the PowerShell snap-in.
/// </summary>
public override string Description
{
get
{
return "This is a PowerShell snap-in for the Select-Str cmdlet.";
}
}
/// <summary>
/// Specify the localization resource information for the description.
/// Use the format: SnapinName,Description.
/// </summary>
public override string DescriptionResource
{
get
{
return "SelectStrSnapIn,This is a PowerShell snap-in for the Select-Str cmdlet.";
}
}
}
#endregion PowerShell snap-in
} //namespace Microsoft.Samples.PowerShell.Commands;
构建 Cmdlet
实现 cmdlet 后,必须通过 Windows PowerShell 管理单元将其注册到 Windows PowerShell。 有关注册 cmdlet 的详细信息,请参阅 如何注册 cmdlet、提供程序和主机应用程序。
测试 Cmdlet
在将 cmdlet 注册到 Windows PowerShell 后,可以通过在命令行上运行 cmdlet 来对其进行测试。 以下过程可用于测试 Select-Str cmdlet 的示例。
开始 Windows PowerShell,并在说明文件中搜索表达式为 ".net" 的行。 请注意,仅当路径包含多个单词时,才需要在路径名称两侧加上引号。
select-str -Path "notes" -Pattern ".NET" -SimpleMatch=$false
将显示以下输出。
IgnoreCase : True LineNumber : 8 Line : Because Windows PowerShell works directly with .NET objects, there is often a .NET object Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes Pattern : .NET IgnoreCase : True LineNumber : 21 Line : You should normally define the class for a cmdlet in a .NET namespace Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes Pattern : .NET
在 Notes 文件中搜索单词 "over" 后跟任何其他文本的行。
SimpleMatch
参数使用的默认值false
。 搜索不区分大小写,因为CaseSensitive
参数设置为false
。select-str -Path notes -Pattern "over*" -SimpleMatch -CaseSensitive:$false
将显示以下输出。
IgnoreCase : True LineNumber : 45 Line : Override StopProcessing Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes Pattern : over* IgnoreCase : True LineNumber : 49 Line : overriding the StopProcessing method Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes Pattern : over*
使用正则表达式作为模式搜索说明文件。 Cmdlet 将搜索括在括号中的字母字符和空格。
select-str -Path notes -Pattern "\([A-Za-z:blank:]" -SimpleMatch:$false
将显示以下输出。
IgnoreCase : True LineNumber : 1 Line : Advisory Guidelines (Consider Following) Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes Pattern : \([A-Za-z:blank:] IgnoreCase : True LineNumber : 53 Line : If your cmdlet has objects that are not disposed of (written to the pipeline) Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes Pattern : \([A-Za-z:blank:]
对说明文件执行区分大小写的搜索,查找单词 "Parameter" 的匹配项。
select-str -Path notes -Pattern Parameter -CaseSensitive
将显示以下输出。
IgnoreCase : False LineNumber : 6 Line : Support an InputObject Parameter Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes Pattern : Parameter IgnoreCase : False LineNumber : 30 Line : Support Force Parameter Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes Pattern : Parameter
搜索 Windows PowerShell 附带的变量提供程序,获取数值介于0到9之间的变量。
select-str -Path * -Pattern "[0-9]"
将显示以下输出。
IgnoreCase : True LineNumber : 1 Line : 64 Path : Variable:\MaximumHistoryCount Pattern : [0-9]
使用脚本块搜索字符串 "Pos" 的 SelectStrCommandSample 文件。 脚本的 cmatch 函数执行不区分大小写的模式匹配。
select-str -Path "SelectStrCommandSample.cs" -Script { if ($args[0] -cmatch "Pos"){ return $true } return $false }
将显示以下输出。
IgnoreCase : True LineNumber : 37 Line : Position = 0. Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\SelectStrCommandSample.cs Pattern :
另请参阅
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈