Delen via


Een cmdlet maken om toegang te krijgen tot een gegevensarchief

In deze sectie wordt beschreven hoe u een cmdlet maakt die toegang heeft tot opgeslagen gegevens via een Windows PowerShell-provider. Dit type cmdlet maakt gebruik van de Windows PowerShell-providerinfrastructuur van de Windows PowerShell-runtime. Daarom moet de cmdlet-klasse zijn afgeleid van de basisklasse System.Management.Automation.PSCmdlet.

De Select-Str cmdlet die hier wordt beschreven, kan tekenreeksen in een bestand of object zoeken en selecteren. De patronen die worden gebruikt om de tekenreeks te identificeren, kunnen expliciet worden opgegeven via de parameter Path van de cmdlet of impliciet via de parameter Script.

De cmdlet is ontworpen om elke Windows PowerShell-provider te gebruiken die is afgeleid van System.Management.Automation.Provider.IContentCmdletProvider. De cmdlet kan bijvoorbeeld de bestandssysteemprovider of de variabele provider opgeven die wordt geleverd door Windows PowerShell. Zie Uw Windows PowerShell-provider ontwerpenvoor meer informatie over Windows PowerShell-providers.

De cmdlet-klasse definiëren

De eerste stap bij het maken van de cmdlet is altijd de naamgeving van de cmdlet en het declareren van de .NET-klasse die de cmdlet implementeert. Deze cmdlet detecteert bepaalde tekenreeksen, dus de hier gekozen werkwoordnaam is 'Selecteren', gedefinieerd door de klasse System.Management.Automation.VerbsCom mon. De naam van het zelfstandig naamwoord Str wordt gebruikt omdat de cmdlet op tekenreeksen reageert. In de onderstaande declaratie ziet u dat de naam van het cmdlet-werkwoord en het zelfstandig naamwoord worden weergegeven in de naam van de cmdlet-klasse. Zie Cmdlet Verb Namesvoor meer informatie over goedgekeurde cmdlet-werkwoorden.

De .NET-klasse voor deze cmdlet moet zijn afgeleid van de System.Management.Automation.PSCmdlet-basisklasse, omdat deze de ondersteuning biedt die de Windows PowerShell-runtime nodig heeft om de infrastructuur van de Windows PowerShell-provider beschikbaar te maken. Houd er rekening mee dat deze cmdlet ook gebruikmaakt van de reguliere .NET Framework-expressieklassen, zoals System.Text.RegularExpressions.Regex.

De volgende code is de klassedefinitie voor deze Select-Str cmdlet.

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

Deze cmdlet definieert een standaardparameterset door het trefwoord DefaultParameterSetName kenmerk toe te voegen aan de klassedeclaratie. De standaardparameterset PatternParameterSet wordt gebruikt wanneer de parameter Script niet is opgegeven. Zie de Pattern en Script parameterdiscussie in de volgende sectie voor meer informatie over deze parameterset.

Parameters definiëren voor Data Access

Met deze cmdlet worden verschillende parameters gedefinieerd waarmee de gebruiker toegang kan krijgen tot opgeslagen gegevens en deze kan onderzoeken. Deze parameters bevatten een Path parameter die de locatie van het gegevensarchief aangeeft, een Pattern parameter waarmee het patroon wordt opgegeven dat moet worden gebruikt in de zoekopdracht en verschillende andere parameters die ondersteunen hoe de zoekopdracht wordt uitgevoerd.

Notitie

Zie [Parameters toevoegen die opdrachtregelinvoer verwerken][04] voor meer informatie over de basisbeginselen van het definiëren van parameters.

De padparameter declareren

Als u het gegevensarchief wilt vinden, moet deze cmdlet een Windows PowerShell-pad gebruiken om de Windows PowerShell-provider te identificeren die is ontworpen voor toegang tot het gegevensarchief. Daarom definieert het een Path parameter van het type tekenreeksmatrix om de locatie van de provider aan te geven.

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

Houd er rekening mee dat deze parameter deel uitmaakt van twee verschillende parametersets en dat deze een alias heeft.

Twee System.Management.Automation.ParameterAttribute kenmerken declareren dat de parameter Path behoort tot de ScriptParameterSet en de PatternParameterSet. Zie Parametersets toevoegen aan een cmdlet-voor meer informatie over parametersets.

Het kenmerk System.Management.Automation.AliasAttribute declareert een PSPath alias voor de parameter Path. Het declareren van deze alias wordt sterk aanbevolen voor consistentie met andere cmdlets die toegang hebben tot Windows PowerShell-providers. Zie 'PowerShell-padconcepten voor PowerShell' in Hoe Windows PowerShell werktvoor meer informatie over Windows PowerShell-paden.

De patroonparameter declareren

Als u de te zoeken patronen wilt opgeven, declareert deze cmdlet een Pattern parameter die een matrix met tekenreeksen is. Er wordt een positief resultaat geretourneerd wanneer een van de patronen in het gegevensarchief wordt gevonden. Houd er rekening mee dat deze patronen kunnen worden gecompileerd in een matrix met gecompileerde reguliere expressies of een matrix met jokertekenpatronen die worden gebruikt voor letterlijke zoekopdrachten.

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

Wanneer deze parameter is opgegeven, gebruikt de cmdlet de standaardparameterset PatternParameterSet. In dit geval gebruikt de cmdlet de hier opgegeven patronen om tekenreeksen te selecteren. De parameter Script kan daarentegen ook worden gebruikt om een script op te geven dat de patronen bevat. De parameters Script en Pattern definiëren twee afzonderlijke parametersets, zodat ze elkaar wederzijds uitsluiten.

Ondersteuningsparameters voor zoeken declareren

Deze cmdlet definieert de volgende ondersteuningsparameters die kunnen worden gebruikt om de zoekmogelijkheden van de cmdlet te wijzigen.

De parameter Script geeft een scriptblok op dat kan worden gebruikt om een alternatief zoekmechanisme voor de cmdlet op te geven. Het script moet de patronen bevatten die worden gebruikt voor het vergelijken en retourneren van een System.Management.Automation.PSObject-object. Houd er rekening mee dat deze parameter ook de unieke parameter is die de ScriptParameterSet parameterset identificeert. Wanneer de Windows PowerShell-runtime deze parameter ziet, worden alleen parameters gebruikt die deel uitmaken van de ScriptParameterSet parameterset.

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

De SimpleMatch parameter is een schakelparameter die aangeeft of de cmdlet expliciet overeenkomt met de patronen die worden opgegeven. Wanneer de gebruiker de parameter opgeeft op de opdrachtregel (true), gebruikt de cmdlet de patronen zoals ze worden opgegeven. Als de parameter niet is opgegeven (false), gebruikt de cmdlet reguliere expressies. De standaardwaarde voor deze parameter is false.

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

De parameter CaseSensitive is een schakelparameter die aangeeft of een hoofdlettergevoelige zoekopdracht wordt uitgevoerd. Wanneer de gebruiker de parameter opgeeft op de opdrachtregel (true), controleert de cmdlet op de hoofdletters en kleine letters van tekens bij het vergelijken van patronen. Als de parameter niet is opgegeven (false), maakt de cmdlet geen onderscheid tussen hoofdletters en kleine letters. Bijvoorbeeld 'MyFile' en 'myfile' worden beide geretourneerd als positieve treffers. De standaardwaarde voor deze parameter is false.

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

Met de parameters Exclude en Include worden items geïdentificeerd die expliciet zijn uitgesloten van of zijn opgenomen in de zoekopdracht. Standaard doorzoekt de cmdlet alle items in het gegevensarchief. Als u de zoekopdracht wilt beperken die door de cmdlet wordt uitgevoerd, kunnen deze parameters echter worden gebruikt om expliciet aan te geven dat items moeten worden opgenomen in de zoekopdracht of worden weggelaten.

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

Parametersets declareren

Deze cmdlet maakt gebruik van twee parametersets (ScriptParameterSet en PatternParameterSet, de standaardinstelling) als de namen van twee parametersets die worden gebruikt in gegevenstoegang. PatternParameterSet is de standaardparameterset en wordt gebruikt wanneer de parameter Pattern is opgegeven. ScriptParameterSet wordt gebruikt wanneer de gebruiker een alternatief zoekmechanisme opgeeft via de parameter Script. Zie Parametersets toevoegen aan een cmdlet-voor meer informatie over parametersets.

Invoerverwerkingsmethoden overschrijven

Cmdlets moeten een of meer invoerverwerkingsmethoden voor de System.Management.Automation.PSCmdlet- klasse overschrijven. Zie Uw eerste cmdlet makenvoor meer informatie over de invoerverwerkingsmethoden.

Deze cmdlet overschrijft de methode System.Management.Automation.Cmdlet.BeginProcessing om een matrix met gecompileerde reguliere expressies te maken bij het opstarten. Dit verhoogt de prestaties tijdens zoekopdrachten die geen eenvoudige overeenkomsten gebruiken.

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

Deze cmdlet overschrijft ook de methode System.Management.Automation.Cmdlet.ProcessRecord om de tekenreeksselecties te verwerken die de gebruiker maakt op de opdrachtregel. Hiermee worden de resultaten van tekenreeksselectie in de vorm van een aangepast object geschreven door een persoonlijke MatchString-methode aan te roepen.

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

Toegang tot inhoud

De cmdlet moet de provider openen die wordt aangegeven door het Windows PowerShell-pad, zodat deze toegang heeft tot de gegevens. Het System.Management.Automation.SessionState-object voor de runspace wordt gebruikt voor toegang tot de provider, terwijl de eigenschap System.Management.Automation.PSCmdlet.InvokeProvider* eigenschap van de cmdlet wordt gebruikt om de provider te openen. Toegang tot inhoud wordt geboden door het System.Management.Automation.ProviderIntrinsics-object voor de geopende provider op te halen.

Deze voorbeeld-Select-Str cmdlet maakt gebruik van de eigenschap System.Management.Automation.ProviderIntrinsics.Content* om de inhoud weer te geven die moet worden gescand. Vervolgens kan het System.Management.Automation.ContentCmdletProviderIntrinsics.GetReader* methode aanroepen, waarbij het vereiste Windows PowerShell-pad wordt doorgegeven.

Codevoorbeeld

De volgende code toont de implementatie van deze versie van deze Select-Str cmdlet. Deze code bevat de cmdlet-klasse, persoonlijke methoden die door de cmdlet worden gebruikt en de Windows PowerShell-modulecode die wordt gebruikt om de cmdlet te registreren. Zie De cmdlet bouwenvoor meer informatie over het registreren van de 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;

De cmdlet bouwen

Nadat u een cmdlet hebt geïmplementeerd, moet u deze registreren bij Windows PowerShell via een Windows PowerShell-module. Zie Cmdlets, providers en hosttoepassingen registrerenvoor meer informatie over het registreren van cmdlets.

De cmdlet testen

Wanneer uw cmdlet is geregistreerd bij Windows PowerShell, kunt u deze testen door deze uit te voeren op de opdrachtregel. De volgende procedure kan worden gebruikt om de voorbeeld-Select-Str cmdlet te testen.

  1. Start Windows PowerShell en zoek in het notitiebestand naar exemplaren van regels met de expressie .NET. Houd er rekening mee dat de aanhalingstekens rond de naam van het pad alleen vereist zijn als het pad uit meer dan één woord bestaat.

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

    De volgende uitvoer wordt weergegeven.

    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. Zoek in het notitiebestand naar exemplaren van regels met het woord 'over', gevolgd door andere tekst. De parameter SimpleMatch gebruikt de standaardwaarde van false. De zoekopdracht is niet hoofdlettergevoelig omdat de parameter CaseSensitive is ingesteld op false.

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

    De volgende uitvoer wordt weergegeven.

    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. Doorzoek het notitiebestand met behulp van een reguliere expressie als het patroon. De cmdlet zoekt naar alfabetische tekens en lege spaties tussen haakjes.

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

    De volgende uitvoer wordt weergegeven.

    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. Voer een hoofdlettergevoelige zoekopdracht uit van het notitiebestand voor exemplaren van het woord 'Parameter'.

    Select-Str -Path notes -Pattern Parameter -CaseSensitive
    

    De volgende uitvoer wordt weergegeven.

    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. Zoek de variabeleprovider die is geleverd met Windows PowerShell voor variabelen met numerieke waarden van 0 tot en met 9.

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

    De volgende uitvoer wordt weergegeven.

    IgnoreCase   : True
    LineNumber   : 1
    Line         : 64
    Path         : Variable:\MaximumHistoryCount
    Pattern      : [0-9]
    
  6. Gebruik een scriptblok om het bestand te doorzoeken SelectStrCommandSample.cs voor de tekenreeks 'Pos'. De operator -cmatch voert een niet-hoofdlettergevoelige patroonovereenkomst uit.

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

    De volgende uitvoer wordt weergegeven.

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

Zie ook

Een Windows PowerShell-cmdlet maken

uw eerste cmdlet maken

Een cmdlet maken waarmee het systeem wordt gewijzigd

uw Windows PowerShell-provider ontwerpen

Hoe Windows PowerShell werkt

Cmdlets, providers en hosttoepassingen registreren)

Windows PowerShell SDK