EN
Ce contenu n’est pas disponible dans votre langue. Voici la version anglaise.

Adding Aliases, Wildcard Expansion, and Help to Cmdlet Parameters

This section describes how to add aliases, wildcard expansion, and Help messages to the parameters of the Stop-Proc cmdlet (described in Creating a Cmdlet that Modifies the System).

This Stop-Proc cmdlet attempts to stop processes that are retrieved using the Get-Proc cmdlet (described in Creating a Cmdlet without Parameters).

noteNote:
You can download the C# source file (stopproc03.cs) for this Stop-Proc cmdlet using the Microsoft Windows Software Development Kit for Windows Vista and .NET Framework 3.0 Runtime Components. For download instructions, see How to Install Windows PowerShell.

The downloaded source files are available in the <PowerShell Samples> directory.

Topics in this section include the following:

Defining the Cmdlet

The first step in cmdlet creation is always naming the cmdlet and declaring the .NET class that implements the cmdlet. Because you are writing a cmdlet to change the system, it should be named accordingly. Because this cmdlet stops system processes, it uses the verb "Stop", defined by the VerbsLifeCycle class, with the noun "Proc" to indicate process. For more information about approved cmdlet verbs, see Approved Verbs for Windows PowerShell Commands.

The following code is the class definition for this Stop-Proc cmdlet.

[Cmdlet(VerbsLifecycle.Stop, "proc",
        SupportsShouldProcess = true)]
public class StopProcCommand : Cmdlet

Defining Parameters for System Modification

Your cmdlet needs to define parameters that support system modifications and user feedback. The cmdlet should define a Name parameter or equivalent so that the cmdlet will be able to modify the system by some sort of identifier. In addition, the cmdlet should define the Force and PassThru parameters. For more information about these parameters, see Creating a Cmdlet that Modifies the System.

Defining a Parameter Alias

A parameter alias can be an alternate name or a well-defined 1-letter or 2-letter short name for a cmdlet parameter. In both cases, the goal of using aliases is to simplify user entry from the command line. Windows PowerShell supports parameter aliases through the AliasAttribute attribute, which uses the declaration syntax [Alias()].

The following code shows how an alias is added to the Name parameter.

/// <summary>
/// Specify the mandatory Name parameter used to identify the 
/// processes to be stopped.
/// </summary>
[Parameter(
           Position = 0,
           Mandatory = true,
           ValueFromPipeline = true,
           ValueFromPipelineByPropertyName = true,
           HelpMessage = "The name of one or more processes to stop. Wildcards are permitted."
)]
[Alias("ProcessName")]
public string[] Name
{
  get { return processNames; }
  set { processNames = value; }
}
private string[] processNames;

In addition to using the AliasAttribute attribute, the Windows PowerShell runtime performs partial name matching, even if no aliases are specified. For example, if your cmdlet has a FileName parameter and that is the only parameter that starts with F, the user could enter Filename, Filenam, File, Fi, or F and still recognize the entry as the FileName parameter.

Creating Help for Parameters

Windows PowerShell allows you to create Help for cmdlet parameters. Do this for any parameter used for system modification and user feedback. For each parameter to support Help, you can set the HelpMessage attribute keyword in the ParameterAttribute attribute declaration. This keyword defines the text to display to the user for assistance in using the parameter. You can also set the HelpMessageBaseName keyword to identify the base name of a resource to use for the message. If you set this keyword, you must also set the HelpMessageResourceId keyword to specify the resource identifier.

The following code from this Stop-Proc cmdlet defines the HelpMessage attribute keyword for the Name parameter.

/// <summary>
/// Specify the mandatory Name parameter used to identify the 
/// processes to be stopped.
/// </summary>
[Parameter(
           Position = 0,
           Mandatory = true,
           ValueFromPipeline = true,
           ValueFromPipelineByPropertyName = true,
           HelpMessage = "The name of one or more processes to stop. Wildcards are permitted."
)]

Overriding an Input Processing Method

Your cmdlet must override an input processing method, most often this will be ProcessRecord. When modifying the system, the cmdlet should call the ShouldProcess and ShouldContinue methods to allow the user to provide feedback before a change is made. For more information about these methods, see Creating a Cmdlet that Modifies the System.

Supporting Wildcard Expansion

To allow the selection of multiple objects, your cmdlet can use the WildcardPattern and WildcardOptions classes to provide wildcard expansion support for parameter input. Examples of wildcard patterns are lsa*, *.txt, and [a-c]*. Use the back-quote character (`) as an escape character when the pattern contains a character that should be used literally.

Wildcard expansions of file and path names are examples of common scenarios where the cmdlet may want to allow support for path inputs when the selection of multiple objects is required. A common case is in the file system, where a user wants to see all files residing in the current folder.

You should need a customized wildcard pattern matching implementation only rarely. In this case, your cmdlet should support either the full POSIX 1003.2, 3.13 specification for wildcard expansion or the following simplified subset:

  • Question mark (?). Matches any character at the specified location.

  • Asterisk (*). Matches zero or more characters starting at the specified location.

  • Open bracket ([). Introduces a pattern bracket expression that can contain characters or a range of characters. If a range is required, a hyphen (-) is used to indicate the range.

  • Close bracket (]). Ends a pattern bracket expression.

  • Back-quote escape character (`). Indicates that the next character should be taken literally. Be aware that when specifying the back-quote character from the command line (as opposed to specifying it programmatically), the back-quote escape character must be specified twice.

noteNote:
For more information about wildcard patterns, see Supporting Wildcard Characters in Cmdlet Parameters.

The following code shows how to set wildcard options and define the wildcard pattern used for resolving the Name parameter for this cmdlet.

WildcardOptions options = WildcardOptions.IgnoreCase | 
                          WildcardOptions.Compiled;
WildcardPattern wildcard = new WildcardPattern(name,options);

The following code shows how to test whether the process name matches the defined wildcard pattern. Notice that, in this case, if the process name does not match the pattern, the cmdlet continues on to get the next process name.

if (!wildcard.IsMatch(processName))
{
  continue;
}

Code Sample

The following code shows the implementation of this Stop-Proc cmdlet.

// Copyright (c) 2005 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.Diagnostics;
using System.Collections;
using Win32Exception = System.ComponentModel.Win32Exception;
using System.Management.Automation;             // Windows PowerShell namespace.
using System.ComponentModel;

// This sample introduces parameter aliases, wildcards and help message.
namespace Microsoft.Samples.PowerShell.Commands
{
 
  #region StopProcCommand

  /// <summary>
  /// This class implements the stop-proc cmdlet.
  /// </summary>
  [Cmdlet(VerbsLifecycle.Stop, "proc",
          SupportsShouldProcess = true)]
  public class StopProcCommand : Cmdlet
  {
    #region Parameters

    /// <summary>
    /// Specify the Name, Force, and PassThru parameters 
    /// for the cmdlet.
    /// </summary>
    /// <summary>
    /// Specify the mandatory Name parameter used to identify the 
    /// processes to be stopped.
    /// </summary>
    [Parameter(
               Position = 0,
               Mandatory = true,
               ValueFromPipeline = true,
               ValueFromPipelineByPropertyName = true,
               HelpMessage = "The name of one or more processes to stop. Wildcards are permitted."
    )]
    [Alias("ProcessName")]
    public string[] Name
    {
      get { return processNames; }
      set { processNames = value; }
    }
    private string[] processNames;

    /// <summary>
    /// Specify the Force parameter that allows the user to override 
    /// the ShouldContinue call to force the stop operation. This 
    /// parameter should always be used with caution.
    /// </summary>
    [Parameter]
    public SwitchParameter Force
    {
      get { return force; }
      set { force = value; }
    }
    private bool force;

    /// <summary>
    /// Specify the PassThru parameter that allows the user to specify 
    /// that the cmdlet should pass the process object down the pipeline 
    /// after the process has been stopped.
    /// </summary>
    [Parameter(
               ValueFromPipelineByPropertyName = true,
               HelpMessage = "If set, the process(es) will be passed to the pipeline after stopped."
    )]
    public SwitchParameter PassThru
    {
      get { return passThru; }
      set { passThru = value; }
    }
    private bool passThru;

    #endregion Parameters

    #region Cmdlet Overrides
    /// <summary>
    /// For each of the requested process name, the cmdlet checks
    /// to see if it is not a critical process and then attempts
    /// to stop that process.
    /// If no process is requested, then nothing occurs.
    /// </summary>
    protected override void ProcessRecord()
    {   
      Process[] processes = null;
      
      try 
      { 
        processes = Process.GetProcesses(); 
      }
      
      catch (InvalidOperationException ioe)
      {
        base.ThrowTerminatingError(new ErrorRecord(ioe,
             "Unable to access the machine processes list.",
             ErrorCategory.InvalidOperation,
             null));
      }

      // If a name parameter is passed to the cmdlet, get the associated 
      // process(es). Write a non-terminating error for a failure to 
      // retrieve a process
      foreach (string name in processNames)
      {
        // Write a user-level message to the pipeline. These messages are 
        // intended to give the user detailed information on the 
        // operations performed by the cmdlet. These messages will
        // appear with the -Verbose option.
        string message =
               String.Format("Attempting to stop process \" {0} \".", name);
               WriteVerbose(message);

        // Use the process name to perform wildcard expansion.  
        // If the process name does not contain a wildcard pattern then it is
        // used as it is.
        WildcardOptions options = WildcardOptions.IgnoreCase | 
                                  WildcardOptions.Compiled;
        WildcardPattern wildcard = new WildcardPattern(name,options);
        foreach (Process process in processes)
        {
          string processName;
          
          try
          {
            processName = process.ProcessName;
          }
          
          catch (Win32Exception)
          {
            WriteError(new ErrorRecord(
                           new Exception("Process not found."),
                       "ProcessNameNotFound",
                       ErrorCategory.ObjectNotFound,
                       process)
            );
            continue;
          }

          // Write a debug message to the host which will be helpful
          // in troubleshooting a problem. All debug messages
          // will appear with the -Debug option
          message =
                  String.Format("Acquired name for pid {0} : \"{1}\"",
                                process.Id, processName);
          WriteDebug(message);

          // Does the process name match the current process name pattern?  
          // Skip this process if not.
          if (!wildcard.IsMatch(processName))
          {
            continue;
          }
          // Stop the process.
          SafeStopProcess(process);
        } // foreach (Process...
      } // foreach (string...
    } // ProcessRecord

    #endregion Cmdlet Overrides

    #region Helper Methods

    /// <summary>
    /// Safely stops a named process.  Used as standalone function
    /// to declutter ProcessRecord method.
    /// </summary>
    /// <param name="process">The process to stop.</param>
    private void SafeStopProcess(Process process)
    {
      string processName = null;
      try
      {
        processName = process.ProcessName;
      }
      catch (Win32Exception e)
      {
        WriteError(new ErrorRecord(e, "ProcessNameNotFound",
                   ErrorCategory.ReadError, process));
        return;               
      }

      string message = null;

      // Confirm the operation first.
      // This is always false if WhatIf is set.
      if (!ShouldProcess(string.Format("{0} ({1})", processName, process.Id)))
      {
        return;
      }

      // Make sure the user really wants to stop a critical
      // process and possibly stop the machine.
      bool criticalProcess = criticalProcessNames.Contains(processName.ToLower());
      
      if (criticalProcess && !force)
      {
        message = String.Format
               ("The process \"{0}\" is a critical process and should not be stopped. Are you sure you wish to stop the process?",
               processName);

        // It is possible that ProcessRecord is called multiple 
        // when objects are received as inputs from a pipeline.
        // So, to retain YesToAll and NoToAll input that the 
        // user may enter across mutilple calls to this 
        // function, they are stored as private members of the 
        // cmdlet.
        if (!ShouldContinue(message, "Warning!",
                         ref yesToAll, ref noToAll))
        {
          return;
        }
      } // if (criticalProcess...
    
      // Display a warning information if stopping a critical 
      // process
      if (criticalProcess)
      {
        message =
              String.Format("Stopping the critical process \" {0} \".",
                            processName);
        WriteWarning(message);
      } // if (criticalProcess...

      try
      {
        // Stop the process.
        process.Kill();
      }
    
      catch (Exception e)
      {
        if ((e is Win32Exception) || (e is SystemException) ||
            (e is InvalidOperationException))
        {
          // This process could not be stopped so write
          // a non-terminating error.
          message = String.Format("{0} {1} {2}",
                                "Could not stop process \"",
                                processName, "\".");
          WriteError(new ErrorRecord(e, message,
                       ErrorCategory.CloseError,
                       process)
          );
          return;
        } // if ((e is...
        else throw;
      } // catch 

      message = String.Format("Stopped process \"{0}\", pid {1}.",
                            processName, process.Id);

      WriteVerbose(message);

      // If the -PassThru command line argument is
      // specified, pass the terminated process on.
      if (passThru)
      {
        message =
            String.Format("Writing process \"{0}\" to pipeline",
                         processName);
        WriteDebug(message);
        WriteObject(process);
      } // if (passThru...
    } // SafeStopProcess

    #endregion Helper Methods

    #region Private Data

    private bool yesToAll, noToAll;
        
    /// <summary>
    /// Partial list of critical processes that should not be 
    /// stopped.  Lower case is used for case insensitive matching.
    /// </summary>
    private ArrayList criticalProcessNames = new ArrayList(
          new string[] { "system", "winlogon", "spoolsv" }
    );
  
    #endregion Private Data

  } // StopProcCommand
  #endregion StopProcCommand

  #region SnapIn

  /// <summary>
  /// Create the PowerShell snap-in used to register the 
  /// Stop-Proc cmdlet. Declaring the PSSnapIn class identifies
  /// this .cs file as a PowerShell snap-in.
  /// </summary>
  [RunInstaller(true)]
  public class StopProcPSSnapIn03 : PSSnapIn
  {
    /// <summary>
    /// Create an instance of StopProcPSSnapIn03 class.
    /// </summary>
    public StopProcPSSnapIn03()
           : base()
    {
    }

    /// <summary>
    /// Specify the name of the PowerShell snap-in.
    /// </summary>
    public override string Name
    {
      get
      {
        return "StopProcPSSnapIn03";
      }
    }

    /// <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 "StopProcPSSnapIn03,Microsoft";
      }
    }

    /// <summary>
    /// Specify a description of the PowerShell snap-in.
    /// </summary>
    public override string Description
    {
      get
      {
        return "This is a PowerShell snap-in that registers the stop-proc cmdlet.";
      }
    }

    /// <summary>
    /// Specify the localization resource information for the description. 
    /// Use the format: SnapInName,Description.
    /// </summary>
    public override string DescriptionResource
    {
      get
      {
        return "StopProcPSSnapIn03,This snap-in registers the stop-proc cmdlet.";
      }
    }
  }
  #endregion SnapIn
}

Define Object Types and Formatting

Windows PowerShell passes information between cmdlets using .Net objects. Consequently, a cmdlet may need to define its own type, or the cmdlet may need to extend an existing type provided by another cmdlet. For more information about defining new types or extending existing types, see Extending Object Types and Formatting.

Building the Cmdlet

After implementing a cmdlet, it must be registered with Windows PowerShell through a Windows PowerShell snap-in. For more information about registering cmdlets, see Registering a Program Module with Windows PowerShell.

Testing the Cmdlet

When your cmdlet has been registered with Windows PowerShell, you can test it by running it on the command line. Let's test the sample Stop-Proc cmdlet. For more information about using cmdlets from the command line, see the Getting Started with Windows PowerShell.

  • Start Windows PowerShell and use Stop-Proc to stop a process using the ProcessName alias for the Name parameter.

    PS> stop-proc -ProcessName notepad
    
    The following output appears.

    Confirm
    Are you sure you want to perform this action?
    Performing operation "stop-proc" on Target "notepad (3496)".
    [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): Y
    
  • Make the following entry on the command line. Because the Name parameter is mandatory, you are prompted for it. Entering "!?" brings up the help text associated with the parameter.

    PS> stop-proc
    
    The following output appears.

    Cmdlet stop-proc at command pipeline position 1
    Supply values for the following parameters:
    (Type !? for Help.)
    Name[0]: !?
    The name of one or more processes to stop. Wildcards are permitted.
    Name[0]: notepad
    
  • Now make the following entry to stop all processes that match the wildcard pattern "*note*". You are prompted before stopping each process that matches the pattern.

    PS> stop-proc -Name *note*
    
    The following output appears.

    Confirm
    Are you sure you want to perform this action?
    Performing operation "stop-proc" on Target "notepad (1112)".
    [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): Y
    
    The following output appears.

    Confirm
    Are you sure you want to perform this action?
    Performing operation "stop-proc" on Target "ONENOTEM (3712)".
    [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): N
    
    The following output appears.

    Confirm
    Are you sure you want to perform this action?
    Performing operation "stop-proc" on Target "ONENOTE (3592)".
    [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): N
    

See Also



Ajouts de la communauté

AJOUTER
Afficher:
© 2014 Microsoft