Condividi tramite


Creazione di un cmdlet che modifica il sistema

A volte un cmdlet deve modificare lo stato in esecuzione del sistema, non solo lo stato del runtime di Windows PowerShell. In questi casi, il cmdlet deve consentire all'utente di confermare se apportare o meno la modifica.

Per supportare la conferma, un cmdlet deve eseguire due operazioni.

Supportando la conferma, un cmdlet espone i parametri Confirm e WhatIf forniti da Windows PowerShell e soddisfa anche le linee guida di sviluppo per i cmdlet (per altre informazioni sulle linee guida per lo sviluppo di cmdlet, vedere linee guida per lo sviluppo di cmdlet .).

Modifica del sistema

L'atto di "modifica del sistema" si riferisce a qualsiasi cmdlet che potenzialmente modifica lo stato del sistema all'esterno di Windows PowerShell. Ad esempio, l'arresto di un processo, l'abilitazione o la disabilitazione di un account utente o l'aggiunta di una riga a una tabella di database sono tutte modifiche al sistema che devono essere confermate. Al contrario, le operazioni che leggono dati o stabiliscono connessioni temporanee non modificano il sistema e in genere non richiedono la conferma. La conferma non è necessaria anche per le azioni il cui effetto è limitato all'interno del runtime di Windows PowerShell, ad esempio Set-Variable. I cmdlet che potrebbero o meno apportare una modifica permanente devono dichiarare SupportsShouldProcess e chiamare System.Management.Automation.Cmdlet.ShouldProcess solo se stanno per apportare una modifica permanente.

Nota

La conferma di ShouldProcess si applica solo ai cmdlet. Se un comando o uno script modifica lo stato di esecuzione di un sistema chiamando direttamente metodi o proprietà .NET o chiamando applicazioni esterne a Windows PowerShell, questa forma di conferma non sarà disponibile.

The StopProc Cmdlet

In questo argomento viene descritto un cmdlet di Stop-Proc che tenta di arrestare i processi recuperati usando il cmdlet Get-Proc (descritto in Creazione del primo cmdlet).

Definizione del cmdlet

Il primo passaggio della creazione dei cmdlet è sempre la denominazione del cmdlet e la dichiarazione della classe .NET che implementa il cmdlet . Poiché si scrive un cmdlet per modificare il sistema, deve essere denominato di conseguenza. Questo cmdlet arresta i processi di sistema, quindi il nome del verbo scelto qui è "Stop", definito dalla classe System.Management.Automation.VerbsLifecycle, con il sostantivo "Proc" per indicare che il cmdlet arresta i processi. Per altre informazioni sui verbi dei cmdlet approvati, vedere cmdlet Verb Names.

Di seguito è riportata la definizione della classe per questo cmdlet Stop-Proc.

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

Tenere presente che nella dichiarazione System.Management.Automation.CmdletAttribute la parola chiave dell'attributo SupportsShouldProcess è impostata su true per consentire al cmdlet di effettuare chiamate a System.Management.Automation.Cmdlet.ShouldProcess e System.Management.Automation.Cmdlet.ShouldContinue. Senza questo set di parole chiave, i parametri Confirm e WhatIf non saranno disponibili per l'utente.

Azioni estremamente distruttive

Alcune operazioni sono estremamente distruttive, ad esempio la riformattazione di una partizione del disco rigido attiva. In questi casi, il cmdlet deve impostare ConfirmImpact = ConfirmImpact.High quando si dichiara l'attributo System.Management.Automation.CmdletAttribute. Questa impostazione forza il cmdlet a richiedere la conferma dell'utente anche quando l'utente non ha specificato il parametro Confirm. Tuttavia, gli sviluppatori di cmdlet devono evitare di usare ConfirmImpact per le operazioni che sono semplicemente potenzialmente distruttive, ad esempio l'eliminazione di un account utente. Tenere presente che se ConfirmImpact è impostato su System.Management.Automation.ConfirmImpactHigh.

Analogamente, è improbabile che alcune operazioni siano distruttive, anche se in teoria modificano lo stato di esecuzione di un sistema all'esterno di Windows PowerShell. Tali cmdlet possono impostare ConfirmImpact su System.Management.Automation.ConfirmImpact.Low. In questo modo verranno ignorate le richieste di conferma in cui l'utente ha chiesto di confermare solo operazioni a impatto medio e ad alto impatto.

Definizione dei parametri per la modifica del sistema

Questa sezione descrive come definire i parametri del cmdlet, inclusi quelli necessari per supportare la modifica del sistema. Vedere Aggiunta di parametri che elaborano l'input della riga di comando se sono necessarie informazioni generali sulla definizione dei parametri.

Il cmdlet Stop-Proc definisce tre parametri: Name, Forcee PassThru.

Il parametro Name corrisponde alla proprietà Name dell'oggetto di input del processo. Tenere presente che il parametro Name in questo esempio è obbligatorio, perché il cmdlet avrà esito negativo se non è presente un processo denominato da arrestare.

Il parametro Force consente all'utente di eseguire l'override delle chiamate a System.Management.Automation.Cmdlet.ShouldContinue. In effetti, qualsiasi cmdlet che chiama System.Management.Automation.Cmdlet.ShouldContin ue deve avere un parametro Force in modo che, quando viene specificato Force, il cmdlet ignora la chiamata a System.Management.Automation.Cmdlet.ShouldContinue e procede con l'operazione. Tenere presente che questo non influisce sulle chiamate a System.Management.Automation.Cmdlet.ShouldProcess.

Il parametro PassThru consente all'utente di indicare se il cmdlet passa un oggetto di output attraverso la pipeline, in questo caso, dopo l'arresto di un processo. Tenere presente che questo parametro è associato al cmdlet stesso anziché a una proprietà dell'oggetto di input.

Ecco la dichiarazione di parametro per il 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;

Override di un metodo di elaborazione di input

Il cmdlet deve eseguire l'override di un metodo di elaborazione di input. Il codice seguente illustra l'override System.Management.Automation.Cmdlet.ProcessRecord usato nel cmdlet Stop-Proc di esempio. Per ogni nome di processo richiesto, questo metodo garantisce che il processo non sia un processo speciale, tenti di arrestare il processo e quindi invia un oggetto di output se viene specificato il parametro 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

Chiamata del metodo ShouldProcess

Il metodo di elaborazione di input del cmdlet deve chiamare il metodo System.Management.Automation.Cmdlet.ShouldProcess per confermare l'esecuzione di un'operazione prima che venga apportata una modifica (ad esempio, l'eliminazione di file) allo stato di esecuzione del sistema. In questo modo il runtime di Windows PowerShell può fornire il comportamento corretto "WhatIf" e "Confirm" all'interno della shell.

Nota

Se un cmdlet indica che supporta l'elaborazione e non riesce a eseguire la chiamata System.Management.Automation.Cmdlet.ShouldProcess, l'utente potrebbe modificare il sistema in modo imprevisto.

La chiamata a System.Management.Automation.Cmdlet.ShouldProcess invia il nome della risorsa da modificare all'utente, con il runtime di Windows PowerShell tenendo conto di eventuali impostazioni della riga di comando o variabili di preferenza per determinare cosa deve essere visualizzato all'utente.

Nell'esempio seguente viene illustrata la chiamata a metodo System.Management.Automation.Cmdlet.ShouldProcess dall'override del metodo System.Management.Automation.Cmdlet.ProcessRecord nel cmdlet Stop-Proc di esempio.

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

Chiamata al metodo ShouldContinue

La chiamata al metodo System.Management.Automation.Cmdlet.ShouldContinue invia un messaggio secondario all'utente. Questa chiamata viene eseguita dopo la chiamata a System.Management.Automation.Cmdlet.ShouldProcess restituisce true e se il parametro Force non è stato impostato su true. L'utente può quindi fornire commenti e suggerimenti per indicare se l'operazione deve essere continuata. Il cmdlet chiama System.Management.Automation.Cmdlet.ShouldContinue come controllo aggiuntivo per eventuali modifiche di sistema potenzialmente pericolose o quando si desidera fornire sì a tutti e no-to-all opzioni all'utente.

Nell'esempio seguente viene illustrata la chiamata a metodo System.Management.Automation.Cmdlet.ShouldContin ue dall'override del metodo System.Management.Automation.Cmdlet.ProcessRecor d nel cmdlet Stop-Proc di esempio.

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

Arresto dell'elaborazione dell'input

Il metodo di elaborazione di input di un cmdlet che apporta modifiche di sistema deve fornire un modo per arrestare l'elaborazione dell'input. Nel caso di questo cmdlet Stop-Proc, viene effettuata una chiamata dal metodo System.Management.Automation.Cmdlet.ProcessRecord al metodo System.Diagnostics.Process.Kill*. Poiché il parametro PassThru è impostato su true, System.Management.Automation.Cmdlet.ProcessRecord chiama anche System.Management.Automation.Cmdlet.WriteObject per inviare l'oggetto processo alla pipeline.

Codice di esempio

Per il codice di esempio C# completo, vedere esempio StopProcessSample01.

Definizione di tipi di oggetto e formattazione

Windows PowerShell passa informazioni tra i cmdlet usando oggetti .NET. Di conseguenza, un cmdlet potrebbe dover definire il proprio tipo oppure potrebbe essere necessario estendere un tipo esistente fornito da un altro cmdlet. Per altre informazioni sulla definizione di nuovi tipi o sull'estensione dei tipi esistenti, vedere Estensione dei tipi di oggetto e formattazione.

Compilazione del cmdlet

Dopo aver implementato un cmdlet, deve essere registrato con Windows PowerShell tramite uno snap-in di Windows PowerShell. Per altre informazioni sulla registrazione dei cmdlet, vedere Come registrare cmdlet, provider e applicazioni host.

Test del cmdlet

Quando il cmdlet è stato registrato con Windows PowerShell, è possibile testarlo eseguendolo nella riga di comando. Ecco alcuni test che testano il cmdlet Stop-Proc. Per altre informazioni sull'uso dei cmdlet dalla riga di comando, vedere l'Introduzione a Windows PowerShell.

  • Avviare Windows PowerShell e usare il cmdlet Stop-Proc per interrompere l'elaborazione, come illustrato di seguito. Poiché il cmdlet specifica il parametro Name come obbligatorio, il cmdlet esegue una query per il parametro .

    PS> Stop-Proc
    

    Viene visualizzato l'output seguente.

    Cmdlet Stop-Proc at command pipeline position 1
    Supply values for the following parameters:
    Name[0]:
    
  • A questo punto si userà il cmdlet per arrestare il processo denominato "NOTEPAD". Il cmdlet chiede di confermare l'azione.

    PS> Stop-Proc -Name notepad
    

    Viene visualizzato l'output seguente.

    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
    
  • Usare Stop-Proc come illustrato per arrestare il processo critico denominato "WINLOGON". Viene richiesto e avvisato di eseguire questa azione perché causerà il riavvio del sistema operativo.

    PS> Stop-Proc -Name Winlogon
    

    Viene visualizzato l'output seguente.

    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
    
  • Ora proviamo ad arrestare il processo WINLOGON senza ricevere un avviso. Tenere presente che questa voce di comando usa il parametro Force per eseguire l'override dell'avviso.

    PS> Stop-Proc -Name winlogon -Force
    

    Viene visualizzato l'output seguente.

    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
    

Vedere anche

Aggiunta di parametri che elaborano di input Command-Line

l'estensione dei tipi di oggetto e la formattazione

Come registrare cmdlet, provider e applicazioni host

windows PowerShell SDK

esempi di cmdlet