建立 Cmdlet 以存取資料存放區
本節說明如何建立 Cmdlet,以利用 Windows PowerShell 提供者來存取儲存的資料。 這種類型的 Cmdlet 會使用 Windows PowerShell 執行時間的 Windows PowerShell 提供者基礎結構,因此,Cmdlet 類別必須衍生自PSCmdlet基類。
此處所述的 Select-Str Cmdlet 可以在檔案或物件中尋找並選取字串。 用來識別字串的模式可透過 Cmdlet 的參數明確指定, Path
或透過參數隱含地指定 Script
。
此 Cmdlet 是設計來使用任何衍生自IcontentCmdletprovider的 Windows PowerShell 提供者。 例如,此 Cmdlet 可以指定 Windows PowerShell 所提供的 FileSystem 提供者或變數提供者。 如需 aboutWindows PowerShell 提供者的詳細資訊,請參閱設計您的 Windows PowerShell 提供者。
定義 Cmdlet 類別
Cmdlet 建立的第一個步驟,一律會命名 Cmdlet 並宣告可執行 Cmdlet 的 .NET 類別。 此 Cmdlet 會偵測特定的字串,因此在這裡選擇的動詞名稱是 Verbscommon 類別所定義的 "Select"。 使用名詞名稱 "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 會藉由將 attribute 關鍵字加入至類別宣告,來定義預設參數集 DefaultParameterSetName
。 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屬性(attribute)會宣告 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.object 物件。 請注意,此參數也是識別參數集的唯一參數 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 時,您可以在命令列上執行它來進行測試。 您可以使用下列程式來測試範例 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
使用 "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:]
對 Notes 檔案執行區分大小寫的搜尋,以尋找 "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
針對具有數值0到9的變數,搜尋隨附于 Windows PowerShell 的變數提供者。
select-str -Path * -Pattern "[0-9]"
即會出現下列輸出。
IgnoreCase : True LineNumber : 1 Line : 64 Path : Variable:\MaximumHistoryCount Pattern : [0-9]
使用腳本區塊,在 SelectStrCommandSample 檔案中搜尋字串 "Pos"。 腳本的 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 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應