Sdílet prostřednictvím


Vytvoření rutiny pro přístup k úložišti dat

Tato část popisuje, jak vytvořit rutinu, která přistupuje k uloženým datům prostřednictvím zprostředkovatele Windows PowerShellu. Tento typ rutiny používá infrastrukturu zprostředkovatele Prostředí Windows PowerShell modulu runtime prostředí Windows PowerShell, a proto musí třída rutiny odvozovat ze třídy System.Management.Automation.PSCmdlet základní třídy.

Zde popsaná rutina Select-Str může vyhledat a vybrat řetězce v souboru nebo objektu. Vzory používané k identifikaci řetězce je možné explicitně zadat prostřednictvím parametru Path rutiny nebo implicitně prostřednictvím parametru Script.

Rutina je navržená tak, aby používala libovolného zprostředkovatele Prostředí Windows PowerShell, který je odvozený z System.Management.Automation.Provider.IContentCmdletProvider. Rutina může například zadat zprostředkovatele FileSystem nebo zprostředkovatele proměnných, které poskytuje Prostředí Windows PowerShell. Další informace o zprostředkovatelích Prostředí PowerShell proWindows najdete v tématu Návrh zprostředkovatele Prostředí Windows PowerShell.

Definování třídy rutiny

Prvním krokem při vytváření rutin je vždy pojmenování rutiny a deklarování třídy .NET, která tuto rutinu implementuje. Tato rutina detekuje určité řetězce, takže zde zvolený název příkazu je Select definovaný System.Management.Automation.VerbsCommon třídy. Název podstatného jména "Str" se používá, protože rutina funguje s řetězci. V následující deklaraci si všimněte, že příkaz rutiny a název podstatného jména se odráží v názvu třídy rutiny. Další informace o schválených rutinách naleznete v tématu Názvy příkazů rutin.

Třída .NET pro tuto rutinu musí být odvozena od třídy System.Management.Automation.PSCmdlet základní třídy, protože poskytuje podporu potřebnou modulem runtime Prostředí Windows PowerShell ke zveřejnění infrastruktury zprostředkovatele Prostředí Windows PowerShell. Všimněte si, že tato rutina také používá třídy regulárních výrazů rozhraní .NET Framework, například System.Text.RegularExpressions.Regex.

Následující kód je definice třídy pro tuto rutinu Select-Str.

[Cmdlet(VerbsCommon.Select, "Str", DefaultParameterSetName="PatternParameterSet")]
public class SelectStringCommand : PSCmdlet

Tato rutina definuje výchozí sadu parametrů přidáním klíčového slova atributu DefaultParameterSetName do deklarace třídy. Výchozí sada parametrů PatternParameterSet se používá, pokud není zadaný parametr Script. Další informace o této sadě parametrů najdete v diskuzi o parametrech Pattern a Script v následující části.

Definování parametrů pro přístup k datům

Tato rutina definuje několik parametrů, které uživateli umožňují přístup k uloženým datům a jejich zkoumání. Mezi tyto parametry patří parametr Path, který označuje umístění úložiště dat, parametr Pattern, který určuje vzor, který se má použít při hledání, a několik dalších parametrů, které podporují způsob provedení hledání.

Poznámka:

Další informace o základech definování parametrů najdete v tématu [Přidání parametrů, které zpracovávají vstup příkazového řádku][04].

Deklarování parametru cesty

K vyhledání úložiště dat musí tato rutina použít cestu prostředí Windows PowerShell k identifikaci zprostředkovatele Prostředí Windows PowerShell, který je navržený pro přístup k úložišti dat. Proto definuje Path parametr pole typu řetězec označující umístění zprostředkovatele.

[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;

Všimněte si, že tento parametr patří do dvou různých sad parametrů a že má alias.

Dva atributy System.Management.Automation.ParameterAttribute deklarují, že Path parametr patří do ScriptParameterSet a PatternParameterSet. Další informace o sadách parametrů najdete v tématu Přidání sad parametrů do rutiny.

Atribut System.Management.Automation.AliasAttribute deklaruje PSPath alias pro parametr Path. Deklarování tohoto aliasu důrazně doporučujeme pro konzistenci s jinými rutinami, které přistupují k poskytovatelům Windows PowerShellu. Další informace o cestách Prostředí PowerShell Pro Windows naleznete v tématu Koncepty cesty Prostředí PowerShell v Jak Windows PowerShell funguje.

Deklarování parametru vzoru

Chcete-li určit vzory, které se mají hledat, tato rutina deklaruje parametr Pattern, který je polem řetězců. Pokud se v úložišti dat najde některý ze vzorů, vrátí se kladný výsledek. Všimněte si, že tyto vzory lze zkompilovat do pole zkompilovaných regulárních výrazů nebo pole vzorů se zástupnými znamény používanými pro hledání literálů.

[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;

Při zadání tohoto parametru použije rutina výchozí sadu parametrů PatternParameterSet. V tomto případě rutina používá k výběru řetězců vzory uvedené zde. Naproti tomu parametr Script lze použít také k zadání skriptu, který obsahuje vzory. Parametry Script a Pattern definují dvě samostatné sady parametrů, takže se vzájemně vylučují.

Deklarace parametrů podpory vyhledávání

Tato rutina definuje následující parametry podpory, které lze použít k úpravě možností vyhledávání rutiny.

Parametr Script určuje blok skriptu, který lze použít k poskytnutí alternativního mechanismu vyhledávání rutiny. Skript musí obsahovat vzory použité ke shodě a vrátit System.Management.Automation.PSObject objektu. Všimněte si, že tento parametr je také jedinečný parametr, který identifikuje sadu parametrů ScriptParameterSet. Pokud modul runtime Windows PowerShellu zobrazí tento parametr, používá pouze parametry, které patří do sady parametrů ScriptParameterSet.

[Parameter(
           Position = 1,
           ParameterSetName = "ScriptParameterSet",
           Mandatory = true)]
public ScriptBlock Script
{
  set { script = value; }
  get { return script; }
}
ScriptBlock script;

Parametr SimpleMatch je parametr přepínače, který označuje, jestli se má rutina explicitně shodovat se vzory při jejich poskytnutí. Když uživatel zadá parametr na příkazovém řádku (true), rutina použije vzory při jejich zadání. Pokud parametr není zadaný (false), rutina používá regulární výrazy. Výchozí hodnota pro tento parametr je false.

[Parameter]
public SwitchParameter SimpleMatch
{
  get { return simpleMatch; }
  set { simpleMatch = value; }
}
private bool simpleMatch;

Parametr CaseSensitive je parametr přepínače, který označuje, jestli se provádí vyhledávání s rozlišováním velkých a malých písmen. Když uživatel zadá parametr na příkazovém řádku (true), rutina při porovnávání vzorů zkontroluje velká a malá písmena znaků. Pokud parametr není zadaný (false), rutina nerozlišuje velká a malá písmena. Například "MyFile" a "myfile" by se oba vrátily jako kladné výsledky. Výchozí hodnota pro tento parametr je false.

[Parameter]
public SwitchParameter CaseSensitive
{
  get { return caseSensitive; }
  set { caseSensitive = value; }
}
private bool caseSensitive;

Parametry Exclude a Include identifikují položky, které jsou explicitně vyloučeny nebo zahrnuty do vyhledávání. Ve výchozím nastavení bude rutina prohledávat všechny položky v úložišti dat. Pokud ale chcete omezit vyhledávání prováděné rutinou, můžete tyto parametry použít k explicitnímu označení položek, které mají být zahrnuty do vyhledávání nebo vynechány.

[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;

Deklarace sad parametrů

Tato rutina používá dvě sady parametrů (ScriptParameterSet a PatternParameterSet, což je výchozí) jako názvy dvou sad parametrů používaných v přístupu k datům. PatternParameterSet je výchozí sada parametrů a používá se při zadání parametru Pattern. ScriptParameterSet se používá, když uživatel určuje alternativní vyhledávací mechanismus prostřednictvím parametru Script. Další informace o sadách parametrů najdete v tématu Přidání sad parametrů do rutiny.

Přepsání metod zpracování vstupu

Rutiny musí přepsat jednu nebo více metod zpracování vstupu pro System.Management.Automation.PSCmdlet třída. Další informace o metodách zpracování vstupu naleznete v tématu Vytvoření první rutiny.

Tato rutina přepíše metodu System.Management.Automation.Cmdlet.BeginProcessing k sestavení pole kompilovaných regulárních výrazů při spuštění. Tím se zvýší výkon při hledání, která nepoužívají jednoduché porovnávání.

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().

Tato rutina také přepíše System.Management.Automation.Cmdlet.ProcessRecord metodu zpracování výběrů řetězců, které uživatel provede na příkazovém řádku. Zapíše výsledky výběru řetězce ve formě vlastního objektu voláním privátní MatchString metoda.

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().

Přístup k obsahu

Rutina musí otevřít zprostředkovatele označené cestou prostředí Windows PowerShell, aby měl přístup k datům. System.Management.Automation.SessionState objekt pro runspace se používá pro přístup k zprostředkovateli, zatímco System.Management.Automation.PSCmdlet.InvokeProvider* vlastnost rutiny slouží k otevření zprostředkovatele. Přístup k obsahu je poskytován načtením objektu System.Management.Automation.ProviderIntrinsics objektu otevřeného poskytovatelem.

Tato ukázková rutina Select-Str používá vlastnost System.Management.Automation.ProviderIntrinsics.Content* k vystavení obsahu ke kontrole. Potom může volat metodu System.Management.Automation.ContentCmdletProviderIntrinsics.GetReader* a předat požadovanou cestu prostředí Windows PowerShell.

Ukázka kódu

Následující kód ukazuje implementaci této verze této Select-Str rutiny. Všimněte si, že tento kód zahrnuje třídu rutiny, privátní metody používané rutinou a kód modulu snap-in Prostředí Windows PowerShell použitý k registraci rutiny. Další informace o registraci rutiny najdete v tématu Sestavenírutiny .

//
// 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;

Sestavení rutiny

Po implementaci rutiny ji musíte zaregistrovat ve Windows PowerShellu prostřednictvím modulu snap-in Prostředí Windows PowerShell. Další informace o registraci rutin naleznete v tématu Postup registrace rutin, poskytovatelů a hostitelských aplikací.

Testování rutiny

Když je vaše rutina zaregistrovaná ve Windows PowerShellu, můžete ji otestovat spuštěním na příkazovém řádku. Následující postup lze použít k otestování ukázkové rutiny Select-Str.

  1. Spusťte Windows PowerShell a v souboru Poznámek vyhledejte výskyty řádků pomocí výrazu ".NET". Všimněte si, že uvozovky kolem názvu cesty jsou vyžadovány pouze v případě, že se cesta skládá z více slov.

    Select-Str -Path "notes" -Pattern ".NET" -SimpleMatch=$false
    

    Zobrazí se následující výstup.

    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
    
  2. V souboru Poznámek vyhledejte výskyty řádků se slovem "over", za kterým následuje jakýkoli jiný text. Parametr SimpleMatch používá výchozí hodnotu false. Vyhledávání nerozlišuje malá a velká písmena, protože parametr CaseSensitive je nastaven na false.

    Select-Str -Path notes -Pattern "over*" -SimpleMatch -CaseSensitive:$false
    

    Zobrazí se následující výstup.

    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*
    
  3. Prohledejte soubor Poznámek pomocí regulárního výrazu jako vzor. Rutina vyhledá abecední znaky a prázdné mezery uzavřené v závorkách.

    Select-Str -Path notes -Pattern "\([A-Za-z:blank:]" -SimpleMatch:$false
    

    Zobrazí se následující výstup.

    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:]
    
  4. Proveďte vyhledávání s rozlišováním malých a velkých písmen v souboru Poznámek pro výskyty slova "Parameter".

    Select-Str -Path notes -Pattern Parameter -CaseSensitive
    

    Zobrazí se následující výstup.

    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
    
  5. Vyhledejte zprostředkovatele proměnných dodávanou ve Windows PowerShellu pro proměnné, které mají číselné hodnoty od 0 do 9.

    Select-Str -Path * -Pattern "[0-9]"
    

    Zobrazí se následující výstup.

    IgnoreCase   : True
    LineNumber   : 1
    Line         : 64
    Path         : Variable:\MaximumHistoryCount
    Pattern      : [0-9]
    
  6. Pomocí bloku skriptu vyhledejte v souboru SelectStrCommandSample.cs řetězec "Pos". Operátor -cmatch provádí shodu vzorů bez rozlišování velkých a malých písmen.

    Select-Str -Path "SelectStrCommandSample.cs" -Script {
        if ($args[0] -cmatch "Pos"){ return $true }
        return $false
    }
    

    Zobrazí se následující výstup.

    IgnoreCase   : True
    LineNumber   : 37
    Line         :    Position = 0.
    Path         : C:\PowerShell-Progs\workspace\Samples\SelectStr\SelectStrCommandSample.cs
    Pattern      :
    

Viz také

Vytvoření rutin prostředí Windows PowerShell

vytvoření prvního rutiny

Vytvoření rutiny, která upraví systémovou

navrhnout poskytovatele Windows PowerShellu

jak funguje windows PowerShell

Registrace rutin, poskytovatelů a hostitelských aplikací)

windows PowerShell SDK