Compartilhar via


Criar um cmdlet que modifica o sistema

Às vezes, um cmdlet deve modificar o estado em execução do sistema, não apenas o estado do runtime do Windows PowerShell. Nesses casos, o cmdlet deve permitir que o usuário confirme se deseja ou não fazer a alteração.

Para dar suporte à confirmação, um cmdlet deve fazer duas coisas.

Ao dar suporte à confirmação, um cmdlet expõe os parâmetros Confirm e WhatIf fornecidos pelo Windows PowerShell e também atende às diretrizes de desenvolvimento para cmdlets (Para obter mais informações sobre diretrizes de desenvolvimento de cmdlet, consulte Diretrizes de Desenvolvimento de Cmdlet.).

Alterando o sistema

O ato de "alterar o sistema" refere-se a qualquer cmdlet que potencialmente altera o estado do sistema fora do Windows PowerShell. Por exemplo, interromper um processo, habilitar ou desabilitar uma conta de usuário ou adicionar uma linha a uma tabela de banco de dados são todas alterações no sistema que devem ser confirmadas. Por outro lado, as operações que leem dados ou estabelecem conexões transitórias não alteram o sistema e geralmente não exigem confirmação. A confirmação também não é necessária para ações cujo efeito está limitado a dentro do runtime do Windows PowerShell, como Set-Variable. Cmdlets que podem ou não fazer uma alteração persistente devem declarar SupportsShouldProcess e chamar System.Management.Automation.Cmdlet.ShouldProcess somente se estiverem prestes a fazer uma alteração persistente.

Observação

A confirmação de ShouldProcess se aplica somente a cmdlets. Se um comando ou script modificar o estado em execução de um sistema chamando diretamente métodos ou propriedades do .NET ou chamando aplicativos fora do Windows PowerShell, essa forma de confirmação não estará disponível.

O cmdlet StopProc

Este tópico descreve um cmdlet Stop-Proc que tenta interromper processos recuperados usando o cmdlet Get-Proc (descrito em Criando seu primeiro cmdlet).

Definindo o cmdlet

A primeira etapa na criação do cmdlet é sempre nomear o cmdlet e declarar a classe .NET que implementa o cmdlet. Como você está escrevendo um cmdlet para alterar o sistema, ele deve ser nomeado adequadamente. Esse cmdlet interrompe os processos do sistema, portanto, o nome do verbo escolhido aqui é "Parar", definido pela classe System.Management.Automation.VerbsLifecycle, com o substantivo "Proc" para indicar que o cmdlet interrompe os processos. Para obter mais informações sobre verbos de cmdlet aprovados, consulte Nomes de Verbo do Cmdlet.

Veja a seguir a definição de classe para este cmdlet Stop-Proc.

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

Lembre-se de que, na declaração System.Management.Automation.CmdletAttribute, a palavra-chave de atributo SupportsShouldProcess é definida como true para permitir que o cmdlet faça chamadas para System.Management.Automation.Cmdlet.ShouldProcess e System.Management.Automation.Cmdlet.ShouldContinue. Sem esse conjunto de palavras-chave, os parâmetros Confirm e WhatIf não estarão disponíveis para o usuário.

Ações extremamente destrutivas

Algumas operações são extremamente destrutivas, como reformatar uma partição de disco rígido ativa. Nesses casos, o cmdlet deve definir ConfirmImpact = ConfirmImpact.High ao declarar o atributo System.Management.Automation.CmdletAttribute. Essa configuração força o cmdlet a solicitar a confirmação do usuário mesmo quando o usuário não tiver especificado o parâmetro Confirm. No entanto, os desenvolvedores de cmdlet devem evitar o uso excessivo de ConfirmImpact para operações que são potencialmente destrutivas, como excluir uma conta de usuário. Lembre-se de que se ConfirmImpact estiver definido como System.Management.Automation.ConfirmImpactHigh.

Da mesma forma, é improvável que algumas operações sejam destrutivas, embora, em teoria, modifiquem o estado de execução de um sistema fora do Windows PowerShell. Esses cmdlets podem definir ConfirmImpact como System.Management.Automation.ConfirmImpact.Low. Isso ignorará as solicitações de confirmação em que o usuário pediu para confirmar apenas operações de impacto médio e de alto impacto.

Definindo parâmetros para modificação do sistema

Esta seção descreve como definir os parâmetros de cmdlet, incluindo aqueles necessários para dar suporte à modificação do sistema. Consulte Adicionando parâmetros que processam a entrada commandline se você precisar de informações gerais sobre como definir parâmetros.

O cmdlet Stop-Proc define três parâmetros: Name, Forcee PassThru.

O parâmetro Name corresponde à propriedade Name do objeto de entrada do processo. Lembre-se de que o parâmetro Name neste exemplo é obrigatório, pois o cmdlet falhará se ele não tiver um processo nomeado para parar.

O parâmetro Force permite que o usuário substitua chamadas para System.Management.Automation.Cmdlet.ShouldContinue. Na verdade, qualquer cmdlet que chame System.Management.Automation.Cmdlet.ShouldContinue deve ter um parâmetro Force para que, quando Force for especificado, o cmdlet ignore a chamada para System.Management.Automation.Cmdlet.ShouldContinue e prossiga com a operação. Lembre-se de que isso não afeta as chamadas para System.Management.Automation.Cmdlet.ShouldProcess.

O parâmetro PassThru permite que o usuário indique se o cmdlet passa um objeto de saída pelo pipeline, nesse caso, depois que um processo é interrompido. Lembre-se de que esse parâmetro está vinculado ao cmdlet em si, em vez de a uma propriedade do objeto de entrada.

Esta é a declaração de parâmetro para o 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;

Substituindo um método de processamento de entrada

O cmdlet deve substituir um método de processamento de entrada. O código a seguir ilustra a substituição System.Management.Automation.Cmdlet.ProcessRecord usada no cmdlet Stop-Proc de exemplo. Para cada nome de processo solicitado, esse método garante que o processo não seja um processo especial, tenta interromper o processo e envia um objeto de saída se o parâmetro PassThru for especificado.

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

Chamando o método ShouldProcess

O método de processamento de entrada do cmdlet deve chamar o método System.Management.Automation.Cmdlet.ShouldProcess para confirmar a execução de uma operação antes que uma alteração (por exemplo, excluir arquivos) seja feita no estado em execução do sistema. Isso permite que o runtime do Windows PowerShell forneça o comportamento correto de "WhatIf" e "Confirmar" dentro do shell.

Observação

Se um cmdlet indicar que ele dá suporte deve processar e não fizer a chamada System.Management.Automation.Cmdlet.ShouldProcess, o usuário poderá modificar o sistema inesperadamente.

A chamada para System.Management.Automation.Cmdlet.ShouldProcess envia o nome do recurso a ser alterado para o usuário, com o runtime do Windows PowerShell levando em conta as configurações de linha de comando ou variáveis de preferência na determinação do que deve ser exibido para o usuário.

O exemplo a seguir mostra a chamada para método System.Management.Automation.Cmdlet.ShouldProcess da substituição do método System.Management.Automation.Cmdlet.ProcessRecord no cmdlet Stop-Proc de exemplo.

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

Chamando o método ShouldContinue

A chamada para o método System.Management.Automation.Cmdlet.ShouldContinue envia uma mensagem secundária ao usuário. Essa chamada é feita após a chamada para System.Management.Automation.Cmdlet.ShouldProcess retorna true e se o parâmetro Force não foi definido como true. Em seguida, o usuário pode fornecer comentários para dizer se a operação deve continuar. Seu cmdlet chama System.Management.Automation.Cmdlet.ShouldContinue como uma verificação adicional para modificações potencialmente perigosas do sistema ou quando você deseja fornecer opções sim a todos e no-to-todas ao usuário.

O exemplo a seguir mostra a chamada para método System.Management.Automation.Cmdlet.ShouldContinue da substituição do método System.Management.Automation.Cmdlet.ProcessRecord no cmdlet Stop-Proc de exemplo.

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

Interrompendo o processamento de entrada

O método de processamento de entrada de um cmdlet que faz modificações no sistema deve fornecer uma maneira de interromper o processamento de entrada. No caso desse cmdlet Stop-Proc, uma chamada é feita do método System.Management.Automation.Cmdlet.ProcessRecord para o método System.Diagnostics.Process.Kill*. Como o parâmetro PassThru é definido como true, System.Management.Automation.Cmdlet.ProcessRecord também chama System.Management.Automation.Cmdlet.WriteObject para enviar o objeto de processo para o pipeline.

Exemplo de código

Para obter o código de exemplo C# completo, consulte de exemplo StopProcessSample01.

Definindo tipos de objeto e formatação

O Windows PowerShell passa informações entre cmdlets usando objetos .NET. Consequentemente, um cmdlet pode precisar definir seu próprio tipo ou o cmdlet pode precisar estender um tipo existente fornecido por outro cmdlet. Para obter mais informações sobre como definir novos tipos ou estender tipos existentes, consulte Estendendo tipos de objeto e formatação.

Compilando o cmdlet

Depois de implementar um cmdlet, ele deve ser registrado no Windows PowerShell por meio de um snap-in do Windows PowerShell. Para obter mais informações sobre como registrar cmdlets, consulte Como registrar cmdlets, provedores e aplicativos host.

Testando o cmdlet

Quando o cmdlet tiver sido registrado no Windows PowerShell, você poderá testá-lo executando-o na linha de comando. Aqui estão vários testes que testam o cmdlet Stop-Proc. Para obter mais informações sobre como usar cmdlets da linha de comando, consulte o Introdução ao Windows PowerShell.

  • Inicie o Windows PowerShell e use o cmdlet Stop-Proc para interromper o processamento, conforme mostrado abaixo. Como o cmdlet especifica o parâmetro Name como obrigatório, o cmdlet consulta o parâmetro.

    PS> Stop-Proc
    

    A saída a seguir é exibida.

    Cmdlet Stop-Proc at command pipeline position 1
    Supply values for the following parameters:
    Name[0]:
    
  • Agora vamos usar o cmdlet para interromper o processo chamado "NOTEPAD". O cmdlet pede que você confirme a ação.

    PS> Stop-Proc -Name notepad
    

    A saída a seguir é exibida.

    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 conforme mostrado para interromper o processo crítico chamado "WINLOGON". Você é solicitado e avisado sobre a execução dessa ação porque isso fará com que o sistema operacional seja reinicializado.

    PS> Stop-Proc -Name Winlogon
    

    A saída a seguir é exibida.

    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
    
  • Agora vamos tentar interromper o processo WINLOGON sem receber um aviso. Lembre-se de que essa entrada de comando usa o parâmetro Force para substituir o aviso.

    PS> Stop-Proc -Name winlogon -Force
    

    A saída a seguir é exibida.

    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
    

Consulte Também

adicionando parâmetros que processam de entrada de Command-Line

estendendo tipos de objeto e formatação

como registrar cmdlets, provedores e aplicativos host

do SDK do Windows PowerShell

exemplos de cmdlet