Compartir a través de


Creación de un cmdlet que modifica el sistema

A veces, un cmdlet debe modificar el estado en ejecución del sistema, no solo el estado del entorno de ejecución de Windows PowerShell. En estos casos, el cmdlet debe permitir al usuario confirmar si desea realizar el cambio o no.

Para admitir la confirmación de que un cmdlet debe hacer dos cosas.

Al admitir la confirmación, un cmdlet expone los parámetros de Confirm y WhatIf proporcionados por Windows PowerShell y también cumple las directrices de desarrollo de cmdlets (para obtener más información sobre las directrices de desarrollo de cmdlets, vea Directrices de desarrollo de cmdlets.).

Cambiar el sistema

El acto de "cambiar el sistema" hace referencia a cualquier cmdlet que pueda cambiar el estado del sistema fuera de Windows PowerShell. Por ejemplo, detener un proceso, habilitar o deshabilitar una cuenta de usuario o agregar una fila a una tabla de base de datos son todos los cambios en el sistema que se deben confirmar. Por el contrario, las operaciones que leen datos o establecen conexiones transitorias no cambian el sistema y, por lo general, no requieren confirmación. La confirmación tampoco es necesaria para las acciones cuyo efecto está limitado a dentro del entorno de ejecución de Windows PowerShell, como Set-Variable. Los cmdlets que podrían o no realizar un cambio persistente deben declarar SupportsShouldProcess y llamar a System.Management.Automation.Cmdlet.ShouldProcess solo si están a punto de realizar un cambio persistente.

Nota:

La confirmación shouldProcess solo se aplica a los cmdlets. Si un comando o script modifica el estado en ejecución de un sistema llamando directamente a propiedades o métodos de .NET, o llamando a aplicaciones fuera de Windows PowerShell, esta forma de confirmación no estará disponible.

The StopProc Cmdlet

En este tema se describe un cmdlet de Stop-Proc que intenta detener los procesos que se recuperan mediante el cmdlet Get-Proc (descrito en Creating Your First Cmdlet).

Definición del cmdlet

El primer paso en la creación de cmdlets siempre es asignar un nombre al cmdlet y declarar la clase .NET que implementa el cmdlet. Dado que está escribiendo un cmdlet para cambiar el sistema, debe denominarse en consecuencia. Este cmdlet detiene los procesos del sistema, por lo que el nombre del verbo elegido aquí es "Stop", definido por la clase System.Management.Automation.VerbsLifecycle, con el nombre "Proc" para indicar que el cmdlet detiene los procesos. Para obtener más información sobre los verbos de cmdlet aprobados, consulte Nombres de verbos de cmdlet.

A continuación se muestra la definición de clase para este cmdlet Stop-Proc.

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

Tenga en cuenta que en la declaración de System.Management.Automation.CmdletAttribute, la palabra clave del atributo SupportsShouldProcess se establece en true para permitir que el cmdlet realice llamadas a System.Management.Automation.Cmdlet.ShouldProcess y System.Management.Automation.Cmdlet.ShouldContinue. Sin este conjunto de palabras clave, los parámetros Confirm y WhatIf no estarán disponibles para el usuario.

Acciones extremadamente destructivas

Algunas operaciones son extremadamente destructivas, como volver a formatear una partición de disco duro activa. En estos casos, el cmdlet debe establecer ConfirmImpact = ConfirmImpact.High al declarar el atributo System.Management.Automation.CmdletAttribute. Esta configuración obliga al cmdlet a solicitar confirmación del usuario incluso cuando el usuario no haya especificado el parámetro Confirm. Sin embargo, los desarrolladores de cmdlets deben evitar el uso excesivo de ConfirmImpact para las operaciones que solo son potencialmente destructivas, como eliminar una cuenta de usuario. Recuerde que si ConfirmImpact está establecido en System.Management.Automation.ConfirmImpactHigh.

De forma similar, es poco probable que algunas operaciones sean destructivas, aunque en teoría modifican el estado en ejecución de un sistema fuera de Windows PowerShell. Estos cmdlets pueden establecer ConfirmImpact en System.Management.Automation.ConfirmImpact.Low. Esto omitirá las solicitudes de confirmación en las que el usuario ha pedido que confirme solo las operaciones de impacto medio y alto impacto.

Definición de parámetros para la modificación del sistema

En esta sección se describe cómo definir los parámetros del cmdlet, incluidos los necesarios para admitir la modificación del sistema. Consulte Agregar parámetros que procesan la entrada CommandLine si necesita información general sobre cómo definir parámetros.

El cmdlet Stop-Proc define tres parámetros: Name, Forcey PassThru.

El parámetro Name corresponde a la propiedad Name del objeto de entrada de proceso. Tenga en cuenta que el parámetro Name de este ejemplo es obligatorio, ya que el cmdlet producirá un error si no tiene un proceso con nombre para detenerlo.

El parámetro Force permite al usuario invalidar las llamadas a System.Management.Automation.Cmdlet.ShouldContinue. De hecho, cualquier cmdlet que llame a System.Management.Automation.Cmdlet.ShouldContinue debe tener un parámetro Force para que, cuando se especifique Force, el cmdlet omite la llamada a System.Management.Automation.Cmdlet.ShouldContinue y continúa con la operación. Tenga en cuenta que esto no afecta a las llamadas a System.Management.Automation.Cmdlet.ShouldProcess.

El parámetro PassThru permite al usuario indicar si el cmdlet pasa un objeto de salida a través de la canalización, en este caso, después de detener un proceso. Tenga en cuenta que este parámetro está vinculado al propio cmdlet en lugar de a una propiedad del objeto de entrada.

Esta es la declaración de parámetros del cmdlet Stop-Proc.

[Parameter(
           Position = 0,
           Mandatory = true,
           ValueFromPipeline = true,
           ValueFromPipelineByPropertyName = true
)]
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]
public SwitchParameter PassThru
{
  get { return passThru; }
  set { passThru = value; }
}
private bool passThru;

Invalidación de un método de procesamiento de entrada

El cmdlet debe invalidar un método de procesamiento de entrada. En el código siguiente se muestra la invalidación System.Management.Automation.Cmdlet.ProcessRecord usada en el cmdlet Stop-Proc de ejemplo. Para cada nombre de proceso solicitado, este método garantiza que el proceso no es un proceso especial, intenta detener el proceso y, a continuación, envía un objeto de salida si se especifica el parámetro PassThru.

protected override void ProcessRecord()
{
  foreach (string name in processNames)
  {
    // For every process name passed to the cmdlet, get the associated
    // process(es). For failures, write a non-terminating error
    Process[] processes;

    try
    {
      processes = Process.GetProcessesByName(name);
    }
    catch (InvalidOperationException ioe)
    {
      WriteError(new ErrorRecord(ioe,"Unable to access the target process by name",
                 ErrorCategory.InvalidOperation, name));
      continue;
    }

    // Try to stop the process(es) that have been retrieved for a name
    foreach (Process process in processes)
    {
      string processName;

      try
      {
        processName = process.ProcessName;
      }

      catch (Win32Exception e)
        {
          WriteError(new ErrorRecord(e, "ProcessNameNotFound",
                     ErrorCategory.ReadError, process));
          continue;
        }

        // Call Should Process to confirm the operation first.
        // This is always false if WhatIf is set.
        if (!ShouldProcess(string.Format("{0} ({1})", processName,
                           process.Id)))
        {
          continue;
        }
        // Call ShouldContinue to make sure the user really does want
        // to stop a critical process that could possibly stop the computer.
        bool criticalProcess =
             criticalProcessNames.Contains(processName.ToLower());

        if (criticalProcess &&!force)
        {
          string 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 times
          // when the Name parameter receives objects as input from the
          // pipeline. So to retain YesToAll and NoToAll input that the
          // user may enter across multiple calls to ProcessRecord, this
          // information is stored as private members of the cmdlet.
          if (!ShouldContinue(message, "Warning!",
                              ref yesToAll,
                              ref noToAll))
          {
            continue;
          }
        } // if (criticalProcess...
        // Stop the named process.
        try
        {
          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.
            string message = String.Format("{0} {1} {2}",
                             "Could not stop process \"", processName,
                             "\".");
            WriteError(new ErrorRecord(e, message,
                       ErrorCategory.CloseError, process));
                       continue;
          } // if ((e is...
          else throw;
        } // catch

        // If the PassThru parameter argument is
        // True, pass the terminated process on.
        if (passThru)
        {
          WriteObject(process);
        }
    } // foreach (Process...
  } // foreach (string...
} // ProcessRecord

Llamar al método ShouldProcess

El método de procesamiento de entrada del cmdlet debe llamar al método System.Management.Automation.Cmdlet.ShouldProcess para confirmar la ejecución de una operación antes de que se realice un cambio (por ejemplo, eliminar archivos) al estado en ejecución del sistema. Esto permite que el entorno de ejecución de Windows PowerShell proporcione el comportamiento correcto de "WhatIf" y "Confirmar" dentro del shell.

Nota:

Si un cmdlet indica que admite debe procesarse y no puede realizar la llamada al System.Management.Automation.Cmdlet.ShouldProcess, el usuario podría modificar el sistema de forma inesperada.

La llamada a System.Management.Automation.Cmdlet.ShouldProcess envía el nombre del recurso que se va a cambiar al usuario, con el tiempo de ejecución de Windows PowerShell teniendo en cuenta cualquier configuración de línea de comandos o variables de preferencia para determinar lo que se debe mostrar al usuario.

En el ejemplo siguiente se muestra la llamada a System.Management.Automation.Cmdlet.ShouldProcess de la invalidación del método System.Management.Automation.Cmdlet.ProcessRecord en el cmdlet Stop-Proc de ejemplo.

if (!ShouldProcess(string.Format("{0} ({1})", processName,
                   process.Id)))
{
  continue;
}

Llamar al método ShouldContinue

La llamada al método System.Management.Automation.Cmdlet.ShouldContinue envía un mensaje secundario al usuario. Esta llamada se realiza después de la llamada a System.Management.Automation.Cmdlet.ShouldProcess devuelve true y si el parámetro Force no se estableció en true. A continuación, el usuario puede proporcionar comentarios para indicar si se debe continuar la operación. El cmdlet llama a System.Management.Automation.Cmdlet.ShouldContinue como comprobación adicional de modificaciones potencialmente peligrosas del sistema o cuando quiera proporcionar opciones sí a todos y no-to-all al usuario.

En el ejemplo siguiente se muestra la llamada a System.Management.Automation.Cmdlet.ShouldContinue de la invalidación del método System.Management.Automation.Cmdlet.ProcessRecord en el cmdlet Stop-Proc de ejemplo.

if (criticalProcess &&!force)
{
  string 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 times
  // when the Name parameter receives objects as input from the
  // pipeline. So to retain YesToAll and NoToAll input that the
  // user may enter across multiple calls to ProcessRecord, this
  // information is stored as private members of the cmdlet.
  if (!ShouldContinue(message, "Warning!",
                      ref yesToAll,
                      ref noToAll))
  {
    continue;
  }
} // if (criticalProcess...

Detener el procesamiento de entrada

El método de procesamiento de entrada de un cmdlet que realiza modificaciones del sistema debe proporcionar una manera de detener el procesamiento de la entrada. En el caso de este cmdlet de Stop-Proc, se realiza una llamada desde el método System.Management.Automation.Cmdlet.ProcessRecord al método System.Diagnostics.Process.Kill*. Dado que el parámetro PassThru está establecido en true, System.Management.Automation.Cmdlet.ProcessRecord también llama a system.Management.Automation.Cmdlet.WriteObject para enviar el objeto de proceso a la canalización.

Ejemplo de código

Para obtener el código de ejemplo de C# completo, vea Ejemplo StopProcessSample01.

Definición de tipos de objeto y formato

Windows PowerShell pasa información entre cmdlets mediante objetos .NET. Por lo tanto, es posible que un cmdlet tenga que definir su propio tipo o que el cmdlet tenga que extender un tipo existente proporcionado por otro cmdlet. Para obtener más información sobre cómo definir nuevos tipos o ampliar tipos existentes, vea Extensión de tipos de objeto y formato.

Compilación del cmdlet

Después de implementar un cmdlet, debe registrarse con Windows PowerShell a través de un complemento de Windows PowerShell. Para obtener más información sobre el registro de cmdlets, consulte Registro de cmdlets, proveedores y aplicaciones host.

Prueba del cmdlet

Cuando el cmdlet se haya registrado con Windows PowerShell, puede probarlo ejecutándolo en la línea de comandos. Estas son varias pruebas que prueban el cmdlet Stop-Proc. Para obtener más información sobre el uso de cmdlets desde la línea de comandos, consulte la Introducción a Windows PowerShell.

  • Inicie Windows PowerShell y use el cmdlet Stop-Proc para detener el procesamiento, como se muestra a continuación. Dado que el cmdlet especifica el parámetro Name como obligatorio, el cmdlet consulta el parámetro .

    PS> Stop-Proc
    

    Aparece la salida siguiente.

    Cmdlet Stop-Proc at command pipeline position 1
    Supply values for the following parameters:
    Name[0]:
    
  • Ahora vamos a usar el cmdlet para detener el proceso denominado "NOTEPAD". El cmdlet le pide que confirme la acción.

    PS> Stop-Proc -Name notepad
    

    Aparece la salida siguiente.

    Confirm
    Are you sure you want to perform this action?
    Performing operation "Stop-Proc" on Target "notepad (4996)".
    [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): Y
    
  • Use Stop-Proc como se muestra para detener el proceso crítico denominado "WINLOGON". Se le pide y le advierte sobre cómo realizar esta acción porque hará que el sistema operativo se reinicie.

    PS> Stop-Proc -Name Winlogon
    

    Aparece la salida siguiente.

    Confirm
    Are you sure you want to perform this action?
    Performing operation "Stop-Proc" on Target "winlogon (656)".
    [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): Y
    Warning!
    The process " winlogon " is a critical process and should not be stopped. Are you sure you wish to stop the process?
    [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): N
    
  • Ahora vamos a intentar detener el proceso WINLOGON sin recibir una advertencia. Tenga en cuenta que esta entrada de comando usa el parámetro Force para invalidar la advertencia.

    PS> Stop-Proc -Name winlogon -Force
    

    Aparece la salida siguiente.

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

Véase también

agregar parámetros que procesan Command-Line entrada

extensión de tipos de objeto y formato

Registro de cmdlets, proveedores y aplicaciones host

del SDK de Windows PowerShell

ejemplos de cmdlets de