Поделиться через


Создание командлета, который изменяет систему

Иногда командлет должен изменять состояние выполнения системы, а не только состояние среды выполнения Windows PowerShell. В таких случаях командлет должен разрешить пользователю подтвердить, следует ли вносить изменения.

Для поддержки подтверждения командлета необходимо выполнить две действия.

При поддержке подтверждения командлет предоставляет параметры Confirm и WhatIf, предоставляемые Windows PowerShell, а также соответствует рекомендациям по разработке командлетов (Дополнительные сведения о рекомендациях по разработке командлетов см. в руководства по разработке командлетов.).

Изменение системы

Действие "изменения системы" относится к любому командлету, который потенциально изменяет состояние системы за пределами Windows PowerShell. Например, остановка процесса, включение или отключение учетной записи пользователя или добавление строки в таблицу базы данных являются все изменения в системе, которая должна быть подтверждена. В отличие от этого, операции, которые считывают данные или устанавливают временные подключения, не изменяют систему и обычно не требуют подтверждения. Подтверждение также не требуется для действий, эффект которых ограничен внутри среды выполнения Windows PowerShell, например Set-Variable. Командлеты, которые могут или не могут вносить постоянные изменения, должны объявлять SupportsShouldProcess и вызывать System.Management.Automation.Cmdlet.ShouldProcess только в том случае, если они собираются внести постоянное изменение.

Примечание.

Подтверждение Должно применяться только к командлетам. Если команда или скрипт изменяет состояние выполнения системы путем прямого вызова методов или свойств .NET или путем вызова приложений за пределами Windows PowerShell, эта форма подтверждения не будет доступна.

Командлет StopProc

В этом разделе описывается командлет Stop-Proc, который пытается остановить процессы, полученные с помощью командлета Get-Proc (описанного в разделе Создание первого командлета).

Определение командлета

Первым шагом в создании командлета является всегда именование командлета и объявление класса .NET, реализующего командлет. Так как вы пишете командлет для изменения системы, оно должно быть названо соответствующим образом. Этот командлет останавливает системные процессы, поэтому имя команды, выбранное здесь, имеет значение Stop, определенное классом System.Management.Automation.VerbsLifecycle с существительным "Proc", чтобы указать, что командлет останавливает процессы. Дополнительные сведения о утвержденных командах командлетов см. в имена командлетов.

Ниже приведено определение класса для этого командлета Stop-Proc.

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

Помните, что в объявлении System.Management.Automation.КомандлетAttribute ключевое слово атрибута SupportsShouldProcess имеет значение true, чтобы разрешить командлету выполнять вызовы к System.Management.Automation.Cmdlet.ShouldProcess и System.Management.Automation.Командлет.ShouldContinue. Без этого набора ключевых слов Confirm и WhatIf параметры не будут доступны пользователю.

Чрезвычайно разрушительные действия

Некоторые операции являются чрезвычайно разрушительными, например переформатирование активной секции жесткого диска. В этих случаях командлет должен задать ConfirmImpact = ConfirmImpact.High при объявлении атрибута System.Management.Automation.КомандлетAttribute. Этот параметр заставляет командлет запрашивать подтверждение пользователя, даже если пользователь не указал параметр Confirm. Однако разработчики командлетов должны избегать чрезмерного использования ConfirmImpact для операций, которые просто потенциально разрушительны, например удаление учетной записи пользователя. Помните, что если ConfirmImpact установлено значение System.Management.Automation.ConfirmImpactHigh.

Аналогичным образом некоторые операции вряд ли будут разрушительными, хотя они делают в теории изменение состояния работы системы за пределами Windows PowerShell. Такие командлеты могут задать ConfirmImpact для System.Management.Automation.ConfirmImpact.Low. Это приведет к обходу запросов на подтверждение, когда пользователь попросил подтвердить только операции среднего влияния и высокого влияния.

Определение параметров для изменения системы

В этом разделе описывается определение параметров командлета, включая те, которые необходимы для поддержки изменения системы. Если вам нужны общие сведения об определении параметров, см. добавление параметров, которые обрабатывают вход ные данные commandLine.

Командлет Stop-Proc определяет три параметра: Name, Forceи PassThru.

Параметр Name соответствует свойству Name входного объекта процесса. Помните, что параметр Name в этом примере является обязательным, так как командлет завершится ошибкой, если он не имеет именованного процесса для остановки.

Параметр Force позволяет пользователю переопределить вызовы System.Management.Automation.Командлет.ShouldContinue. На самом деле любой командлет, вызывающий System.Management.Automation.Командлет.ShouldContinue должен иметь параметр Force, чтобы при указании Force командлет пропускает вызов System.Management.Automation.Командлет.ShouldContinue и выполняет операцию. Помните, что это не влияет на вызовы System.Management.Automation.Командлет.ShouldProcess.

Параметр PassThru позволяет пользователю указать, передает ли командлет выходной объект через конвейер, в данном случае после остановки процесса. Помните, что этот параметр привязан к самому командлету, а не к свойству входного объекта.

Ниже приведено объявление параметров для командлета 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;

Переопределение метода обработки входных данных

Командлет должен переопределить метод обработки входных данных. Следующий код иллюстрирует переопределение System.Management.Automation.Командлет.ProcessRecord, используемое в примере командлета Stop-Proc. Для каждого запрошенного имени процесса этот метод гарантирует, что процесс не является специальным процессом, пытается остановить процесс, а затем отправляет выходной объект, если указан параметр 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

Вызов метода ShouldProcess

Метод обработки входных данных командлета должен вызывать метод System.Management.Automation.Командлет.ShouldProcess для подтверждения выполнения операции перед изменением (например, удаление файлов) в состояние выполнения системы. Это позволяет среде выполнения Windows PowerShell предоставлять правильное поведение WhatIf и Confirm в оболочке.

Примечание.

Если командлет указывает, что он должен обрабатывать и не сможет выполнить вызов System.Management.Automation.Командлет.ShouldProcess, пользователь может неожиданно изменить систему.

Вызов System.Management.Automation.Командлет.ShouldProcess отправляет имя ресурса, который нужно изменить пользователю, при этом среда выполнения Windows PowerShell учитывает все параметры командной строки или переменные предпочтения при определении того, что должно отображаться пользователю.

В следующем примере показан вызов System.Management.Automation.Командлет.ShouldProcess из переопределения метода System.Management.Automation.Cmdlet.ProcessRecord в примере командлета Stop-Proc.

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

Вызов метода ShouldContinue

Вызов метода System.Management.Automation.Командлет.ShouldContinue отправляет пользователю дополнительное сообщение. Этот вызов выполняется после вызова System.Management.Automation.Командлет.ShouldProcess возвращает true и если параметр Force не задан true. Затем пользователь может предоставить отзыв о том, следует ли продолжать операцию. Командлет вызывает System.Management.Automation.Командлет.ShouldContinue в качестве дополнительной проверки потенциально опасных изменений системы или если вы хотите предоставить пользователю варианты "да ко всем" и no-to-all.

В следующем примере показан вызов System.Management.Automation.Командлет.ShouldContinue из переопределения метода System.Management.Automation.Cmdlet.ProcessRecord в примере командлета Stop-Proc.

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-Proc вызов выполняется из метода System.Management.Automation.Командлет.ProcessRecord к методу System.Diagnostics.Process.Kill*. Так как для параметра PassThru задано значение true, System.Management.Automation.Cmdlet.ProcessRecord также вызывает System.Management.Automation.Cmdlet.WriteObject для отправки объекта процесса в конвейер.

Пример кода

Полный пример кода C# см. в разделе StopProcessSample01 sample.

Определение типов объектов и форматирования

Windows PowerShell передает сведения между командлетами с помощью объектов .NET. Следовательно, командлету может потребоваться определить собственный тип, или командлету может потребоваться расширить существующий тип, предоставленный другим командлетом. Дополнительные сведения об определении новых типов или расширении существующих типов см. в расширении типов объектов и форматировании.

Создание командлета

После реализации командлета его необходимо зарегистрировать в Windows PowerShell с помощью оснастки Windows PowerShell. Дополнительные сведения о регистрации командлетов см. в разделе Регистрация командлетов, поставщиков и ведущих приложений.

Тестирование командлета

После регистрации командлета в Windows PowerShell его можно протестировать, выполнив его в командной строке. Ниже приведены несколько тестов, которые тестируют командлет Stop-Proc. Дополнительные сведения об использовании командлетов из командной строки см. в Windows PowerShell.

  • Запустите Windows PowerShell и используйте командлет Stop-Proc, чтобы остановить обработку, как показано ниже. Так как командлет задает параметр Name как обязательный, командлет запрашивает параметр.

    PS> Stop-Proc
    

    Отображаются следующие выходные данные.

    Cmdlet Stop-Proc at command pipeline position 1
    Supply values for the following parameters:
    Name[0]:
    
  • Теперь давайте воспользуемся командлетом, чтобы остановить процесс с именем NOTEPAD. Командлет запрашивает подтверждение действия.

    PS> Stop-Proc -Name notepad
    

    Отображаются следующие выходные данные.

    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
    
  • Используйте Stop-Proc, как показано, чтобы остановить критический процесс с именем WINLOGON. Появится запрос и предупреждение о выполнении этого действия, так как это приведет к перезагрузке операционной системы.

    PS> Stop-Proc -Name Winlogon
    

    Отображаются следующие выходные данные.

    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
    
  • Давайте попробуем остановить процесс WINLOGON без получения предупреждения. Помните, что эта запись команды использует параметр Force для переопределения предупреждения.

    PS> Stop-Proc -Name winlogon -Force
    

    Отображаются следующие выходные данные.

    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
    

См. также

Добавление параметров, которые обрабатывают Command-Line входных

расширения типов объектов и форматирования

Регистрация командлетов, поставщиков и ведущих приложений

пакета SDK для Windows PowerShell

примеры командлетов