Creating a Cmdlet that Modifies the System (Criar um Cmdlet que Modifica o Sistema)

Às vezes, um cmdlet deve modificar o estado de funcionamento do sistema, e não apenas o estado do tempo de execução Windows PowerShell. Nestes casos, o cmdlet deve permitir ao utilizador confirmar se deve ou não então a alteração.

Para apoiar a confirmação, um cmdlet deve fazer duas coisas.

Ao apoiar a confirmação, um cmdlet expõe os Confirm parâmetros e WhatIf parâmetros fornecidos pela Windows PowerShell, e também cumpre as orientações de desenvolvimento para os cmdlets (Para mais informações sobre as orientações de desenvolvimento do CMDLET, consulte as Orientações de Desenvolvimento do Cmdlet.).

Mudar o Sistema

O ato de "mudar o sistema" refere-se a qualquer cmdlet que potencialmente altera o estado do sistema fora Windows PowerShell. Por exemplo, parar um processo, ativar ou desativar uma conta de utilizador, ou adicionar uma linha a uma tabela de bases de dados são todas alterações ao sistema que devem ser confirmadas. Em contrapartida, as operações que lêem dados ou estabelecem ligações transitórias não alteram o sistema e geralmente não requerem confirmação. A confirmação também não é necessária para ações cujo efeito se limite ao tempo de execução Windows PowerShell, tais como set-variable . Os cmdlets que podem ou não fazer uma alteração persistente devem declarar SupportsShouldProcess e ligar para o System.Management.Automation.Cmdlet.ShouldProcess.ShouldProcess apenas se estiverem prestes a fazer uma alteração persistente.

Nota

Caso a confirmação do Processo se aplique apenas aos cmdlets. Se um comando ou script modificar o estado de funcionamento de um sistema, chamando diretamente métodos ou propriedades .NET, ou chamando aplicações fora de Windows PowerShell, esta forma de confirmação não estará disponível.

O Cmdlet StopProc

Este tópico descreve um Stop-Proc cmdlet que tenta parar os processos que são recuperados usando o cmdlet Get-Proc (descrito em Criar o Seu Primeiro Comandante).

Definição do Cmdlet

O primeiro passo na criação de cmdlet é sempre nomear o cmdlet e declarar a classe .NET que implementa o cmdlet. Como está a escrever um cmdlet para mudar o sistema, deve ser nomeado em conformidade. Este cmdlet para os processos do sistema, pelo que o nome do verbo aqui escolhido é "Stop", definido pela classe System.Management.Automation.Verbslifecycle, com o substantivo "Proc" a indicar que o cmdlet para os processos. Para obter mais informações sobre verbos de cmdlet aprovados, consulte o Cmdlet Verb Names.

Segue-se a definição de classe para este Stop-Proc cmdlet.

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

Esteja ciente de que na declaração System.Management.Automation.CmdletAttribute, a SupportsShouldProcess palavra-chave do atributo está definida true para permitir ao cmdlet fazer chamadas para System.Management.Automation.Cmdlet.ShouldProcess and System.Management.Automation.Cmdlet.ShouldContinue. Sem este conjunto de palavras-chave, os Confirm parâmetros e WhatIf parâmetros não estarão disponíveis para o utilizador.

Ações extremamente destrutivas

Algumas operações são extremamente destrutivas, como reformar uma partição de disco rígido ativo. Nestes casos, o cmdlet deve ser definido ConfirmImpact = ConfirmImpact.High ao declarar o atributo System.Management.Automation.CmdletAttribute. Esta definição obriga o cmdlet a solicitar a confirmação do utilizador mesmo quando o utilizador não tenha especificado o Confirm parâmetro. No entanto, os desenvolvedores de cmdlet devem evitar o excesso de utilização ConfirmImpact para operações que são potencialmente destrutivas, como a eliminação de uma conta de utilizador. Lembre-se que se ConfirmImpact estiver definido para System.Management.Automation.ConfirmImpact High.

Da mesma forma, é pouco provável que algumas operações sejam destrutivas, embora em teoria modifiquem o estado de funcionamento de um sistema fora Windows PowerShell. Estes cmdlets podem ser definidos ConfirmImpact para System.Management.Automation.Confirmimpact.Low. Isto irá contornar os pedidos de confirmação onde o utilizador solicitou para confirmar apenas operações de médio impacto e de alto impacto.

Definição de parâmetros para modificação do sistema

Esta secção descreve como definir os parâmetros do cmdlet, incluindo os necessários para suportar a modificação do sistema. Consulte a adição de parâmetros que processam a entrada do comando se precisar de informações gerais sobre a definição de parâmetros.

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

O Name parâmetro corresponde à propriedade do objeto de entrada do Name processo. Esteja ciente de que o Name parâmetro desta amostra é obrigatório, uma vez que o cmdlet falhará se não tiver um processo nomeado para parar.

O Force parâmetro permite ao utilizador substituir as chamadas para System.Management.Automation.Cmdlet.ShouldContinue. De facto, qualquer cmdlet que ligue para System.Management.Automation.Cmdlet.ShouldContinue deve ter um Force parâmetro para que, quando Force especificado, o cmdlet ignore a chamada para System.Management.Automation.Cmdlet.ShouldContinue e prossiga com a operação. Esteja ciente de que isto não afeta as chamadas para System.Management.Automation.Cmdlet.ShouldProcess.

O PassThru parâmetro permite ao utilizador indicar se o cmdlet passa um objeto de saída através do pipeline, neste caso, após o fim de um processo. Esteja ciente de que este parâmetro está ligado ao próprio cmdlet em vez de uma propriedade do objeto de entrada.

Aqui está a declaração de parâmetro para o Stop-Proc cmdlet.

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

Sobrevam um método de processamento de entrada

O cmdlet deve sobrepor-se a um método de processamento de entrada. O código que se segue ilustra o sobrepõe do System.Management.Automation.Cmdlet.ProcessRecord utilizado na amostra Stop-Proc cmdlet. Para cada nome de processo solicitado, este método garante que o processo não é um processo especial, tenta parar o processo e, em seguida, envia um objeto de saída se o PassThru parâmetro 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 deve processar

O método de processamento de entradas do seu cmdlet deve ligar para o método System.Management.Automation.Cmdlet.ShouldProcess para confirmar a execução de uma operação antes de uma alteração (por exemplo, eliminação de ficheiros) para o estado de funcionamento do sistema. Isto permite que o Windows PowerShell tempo de execução forneça o comportamento correto "WhatIf" e "Confirme" dentro da concha.

Nota

Se um cmdlet afirmar que suporta o processo e não faz a chamada System.Management.Automation.Cmdlet.ShouldProcess, o utilizador poderá modificar o sistema inesperadamente.

A chamada para System.Management.Automation.Cmdlet.ShouldProcess envia o nome do recurso a ser alterado para o utilizador, com o Windows PowerShell tempo de funcionamento tendo em conta quaisquer definições de linha de comando ou variáveis preferenciais na determinação do que deve ser apresentado ao utilizador.

O exemplo a seguir mostra a chamada para System.Management.Automation.Cmdlet.ShouldProcess a partir da sobreposição do método System.Management.Automation.Cmdlet.ProcessRecord na amostra Stop-Proc cmdlet.

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

Chamando o Método DeveContinue

A chamada para o sistema.Management.Automation.Cmdlet.ShouldContinue o método envia uma mensagem secundária ao utilizador. Esta chamada é feita após a chamada para System.Management.Automation.Cmdlet.ShouldProcess true e se o parâmetro não foi definido para Force true . O utilizador pode então fornecer feedback para dizer se a operação deve ser continuada. O seu cmdlet chama System.Management.Automation.Cmdlet.ShouldContinue como uma verificação adicional de modificações potencialmente perigosas do sistema ou quando pretender fornecer opções sim-a-tudo e não-a-todos ao utilizador.

O exemplo a seguir mostra a chamada para System.Management.Automation.Cmdlet.ShouldContinue a partir da sobreposição do método System.Management.Automation.Cmdlet.ProcessRecord na amostra Stop-Proc cmdlet.

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

Parar o processamento de entradas

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

Amostra de código

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

Definição de tipos de objetos e formatação

Windows PowerShell transmite informações entre cmdlets utilizando objetos .Net. Consequentemente, um cmdlet pode ter de definir o seu próprio tipo, ou o cmdlet pode ter de estender um tipo existente fornecido por outro cmdlet. Para obter mais informações sobre a definição de novos tipos ou a extensão dos tipos existentes, consulte a extensão dos tipos de objetos e a formatação.

Construção do Comandante

Após a implementação de um cmdlet, deve ser registado com Windows PowerShell através de um encaixe Windows PowerShell. Para obter mais informações sobre o registo de cmdlets, consulte Como Registar Cmdlets, Fornecedores e Aplicações de Anfitrião.

Testar o Cmdlet

Quando o seu cmdlet estiver registado com Windows PowerShell, pode testá-lo executando-o na linha de comando. Aqui estão vários testes que testam o Stop-Proc cmdlet. Para obter mais informações sobre a utilização de cmdlets da linha de comando, consulte o Início com Windows PowerShell.

  • Comece Windows PowerShell e use o Stop-Proc cmdlet para parar o processamento como mostrado abaixo. Como o cmdlet especifica o Name parâmetro como obrigatório, as consultas de cmdlet para o parâmetro.

    PS> stop-proc
    

    Aparece a seguinte saída.

    Cmdlet stop-proc at command pipeline position 1
    Supply values for the following parameters:
    Name[0]:
    
  • Agora vamos usar o cmdlet para parar o processo chamado "NOTEPAD". O comandante pede-lhe que confirme a ação.

    PS> stop-proc -Name notepad
    

    Aparece a seguinte saída.

    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
    
  • Utilize Stop-Proc como mostrado para parar o processo crítico denominado "WINLOGON". É solicitado e avisado sobre a realização desta ação porque fará com que o sistema operativo reinicie.

    PS> stop-proc -Name Winlogon
    

    Aparece a seguinte saída.

    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
    
  • Vamos agora tentar parar o processo WINLOGON sem receber um aviso. Tenha em atenção que esta entrada de comando utiliza o Force parâmetro para anular o aviso.

    PS> stop-proc -Name winlogon -Force
    

    Aparece a seguinte saída.

    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

Adicionar parâmetros que processam Command-Line entrada

Ampliação de tipos de objetos e formatação

Como registar cmdlets, fornecedores e aplicações de anfitrião

Windows PowerShell SDK (SDK do Windows PowerShell)

Cmdlet Samples (Exemplos de Cmdlets)