Skapa en cmdlet som ändrar systemet

Ibland måste en cmdlet ändra systemets körningstillstånd, inte bara tillståndet för den Windows PowerShell körningen. I dessa fall bör cmdleten ge användaren möjlighet att bekräfta om ändringen ska göras eller inte.

För att stödja bekräftelse måste en cmdlet göra två saker.

En cmdlet visar parametrarna och som tillhandahålls av Windows PowerShell och uppfyller även utvecklingsriktlinjerna för cmdlet:ar (Mer information om riktlinjer för cmdlet-utveckling finns i Confirm WhatIf Cmdlet Development Guidelines.).

Ändra systemet

Att "ändra systemet" syftar på alla cmdlet:ar som potentiellt ändrar systemets tillstånd utanför Windows PowerShell. Om du till exempel stoppar en process, aktiverar eller inaktiverar ett användarkonto eller lägger till en rad i en databastabell ändras alla ändringar i systemet som ska bekräftas. Åtgärder som läser data eller upprättar tillfälliga anslutningar ändrar däremot inte systemet och kräver vanligtvis ingen bekräftelse. Bekräftelse krävs inte heller för åtgärder vars effekt är begränsad till inuti Windows PowerShell körning, till exempel set-variable . Cmdlets som kanske eller kanske inte gör en beständig ändring bör deklarera och anropa SupportsShouldProcess System.Management.Automation.Cmdlet.ShouldProcess endast om de är på väg att göra en beständig ändring.

Anteckning

ShouldProcess-bekräftelse gäller endast för cmdlets. Om ett kommando eller skript ändrar körningstillståndet för ett system genom att direkt anropa .NET-metoder eller -egenskaper, eller genom att anropa program utanför Windows PowerShell, är den här formen av bekräftelse inte tillgänglig.

StopProc-cmdleten

Det här avsnittet beskriver Stop-Proc cmdlet som försöker stoppa processer som hämtas med hjälp av Get-Proc-cmdleten (beskrivs i Skapa din första cmdlet).

Definiera cmdleten

Det första steget i att skapa cmdleten är att alltid namnge cmdleten och deklarera den .NET-klass som implementerar cmdleten. Eftersom du skriver en cmdlet för att ändra systemet bör den namnges i enlighet med detta. Den här cmdleten stoppar systemprocesser, så verbnamnet som väljs här är "Stop", som definieras av klassen System.Management.Automation.Verbslifecycle, med substantivet "Proc" för att indikera att cmdleten stoppar processer. Mer information om godkända cmdlet-verb finns i Cmdlet-verbnamn.

Följande är klassdefinitionen för den här Stop-Proc cmdleten.

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

Tänk på att attributet i deklarationen System.Management.Automation.CmdletAttribute är inställt på att aktivera cmdleten för att göra anrop till SupportsShouldProcess true System.Management.Automation.Cmdlet.ShouldProcess och System.Management.Automation.Cmdlet.ShouldContinue. Utan den här nyckelordsuppsättningen är parametrarna och Confirm inte tillgängliga för WhatIf användaren.

Extremt destruktiva åtgärder

Vissa åtgärder är mycket destruktiva, till exempel att formatera om en aktiv hårddiskpartition. I dessa fall ska cmdleten anges när ConfirmImpact = ConfirmImpact.High attributet System.Management.Automation.CmdletAttribute deklareras. Den här inställningen tvingar cmdleten att begära användarbekräftelse även om användaren inte har angett Confirm parametern. Cmdlet-utvecklare bör dock undvika att överanvända åtgärder som kan vara ConfirmImpact skadliga, till exempel att ta bort ett användarkonto. Kom ihåg att ConfirmImpact om är inställt på System.Management.Automation.ConfirmImpact High.

På samma sätt är det inte troligt att vissa åtgärder är destruktiva, även om de i teorin ändrar körningstillståndet för ett system utanför Windows PowerShell. Sådana cmdlets kan anges ConfirmImpact till System.Management.Automation.Confirmimpact.Low. Detta kringgår bekräftelsebegäranden där användaren har bett att endast bekräfta åtgärder med medelhög och hög påverkan.

Definiera parametrar för systemändring

I det här avsnittet beskrivs hur du definierar cmdlet-parametrarna, inklusive de som behövs för att stödja systemändring. Se Lägga till parametrar som bearbetar kommandoradsindata om du behöver allmän information om hur du definierar parametrar.

Cmdleten Stop-Proc definierar tre parametrar: Name Force , och PassThru .

Parametern Name motsvarar egenskapen Name för processindataobjektet. Tänk på att parametern i det här exemplet är obligatorisk eftersom cmdleten misslyckas om den inte Name har en namngiven process att stoppa.

Parametern Force gör att användaren kan åsidosätta anrop till System.Management.Automation.Cmdlet.ShouldContinue. I själva verket bör alla cmdlet:ar som anropar System.Management.Automation.Cmdlet.ShouldContinue ha en parameter så att när anges hoppar cmdleten över anropet till Force Force System.Management.Automation.Cmdlet.ShouldContinue och fortsätter med åtgärden. Tänk på att detta inte påverkar anrop till System.Management.Automation.Cmdlet.ShouldProcess.

Parametern gör att användaren kan ange om cmdleten skickar ett utdataobjekt via pipelinen, i det PassThru här fallet efter att en process har stoppats. Tänk på att den här parametern är knuten till själva cmdleten i stället för till en egenskap för indataobjektet.

Här är parameterdeklarationen för 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;

Åsidosätta en metod för indatabearbetning

Cmdleten måste åsidosätta en indatabearbetningsmetod. Följande kod illustrerar åsidosättningen System.Management.Automation.Cmdlet.ProcessRecord som används i Stop-Proc cmdlet. För varje begärt processnamn säkerställer den här metoden att processen inte är en särskild process, försöker stoppa processen och skickar sedan ett utdataobjekt om PassThru parametern har angetts.

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

Anropa Metoden ShouldProcess

Metoden för bearbetning av indata för din cmdlet bör anropa metoden System.Management.Automation.Cmdlet.ShouldProcess för att bekräfta körningen av en åtgärd innan en ändring (till exempel borttagning av filer) görs till systemets körningstillstånd. Detta gör att Windows PowerShell-körningen kan ange rätt "WhatIf"- och "Confirm"-beteende i gränssnittet.

Anteckning

Om en cmdlet säger att den stöder ska bearbeta och misslyckas med att göra anropet System.Management.Automation.Cmdlet.ShouldProcess kan användaren ändra systemet oväntat.

Anropet till System.Management.Automation.Cmdlet.ShouldProcess skickar namnet på resursen som ska ändras till användaren, där Windows PowerShell-körningen tar hänsyn till alla kommandoradsinställningar eller inställningsvariabler för att fastställa vad som ska visas för användaren.

I följande exempel visas anropet till System.Management.Automation.Cmdlet.ShouldProcess från åsidosättningen av metoden System.Management.Automation.Cmdlet.ProcessRecord i Stop-Proc cmdlet.

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

Anropa ShouldContinue-metoden

Anropet till metoden System.Management.Automation.Cmdlet.ShouldContinue skickar ett sekundärt meddelande till användaren. Det här anropet görs efter anropet till System.Management.Automation.Cmdlet.ShouldProcess returnerar och true om Force parametern inte har angetts till true . Användaren kan sedan ge feedback för att säga om åtgärden ska fortsätta. Din cmdlet anropar System.Management.Automation.Cmdlet.ShouldContinue som en ytterligare kontroll för potentiellt farliga systemändringar eller när du vill ge användaren alternativ som är ja-till-alla och inte-till-alla.

I följande exempel visas anropet till System.Management.Automation.Cmdlet.ShouldContinue från åsidosättningen av metoden System.Management.Automation.Cmdlet.ProcessRecord i 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...

Stoppa indatabearbetning

Metoden för bearbetning av indata för en cmdlet som gör systemändringar måste ge ett sätt att stoppa bearbetningen av indata. När det gäller den här Stop-Proc-cmdleten görs ett anrop från metoden System.Management.Automation.Cmdlet.ProcessRecord till metoden System.Diagnostics.Process.Kill*. Eftersom PassThru parametern är inställd på true anropar System.Management.Automation.Cmdlet.ProcessRecord även System.Management.Automation.Cmdlet.WriteObject för att skicka processobjektet till pipelinen.

Kodexempel

Den fullständiga C#-exempelkoden finns i StopProcessSample01 Sample.

Definiera objekttyper och formatering

Windows PowerShell skickar information mellan cmdlets med hjälp av .Net-objekt. Därför kan en cmdlet behöva definiera sin egen typ, eller så kan cmdleten behöva utöka en befintlig typ som tillhandahålls av en annan cmdlet. Mer information om hur du definierar nya typer eller utökar befintliga typer finns i Utöka objekttyper och formatering.

Skapa cmdleten

När du har implementerat en cmdlet måste den registreras Windows PowerShell via en Windows PowerShell snapin-modulen. Mer information om hur du registrerar cmdlets finns i Registrera cmdlets, providers och värdprogram.

Testa cmdleten

När din cmdlet har registrerats med Windows PowerShell kan du testa den genom att köra den på kommandoraden. Här är flera tester som testar Stop-Proc cmdlet. Mer information om hur du använder cmdlets från kommandoraden finns i Komma igång med Windows PowerShell.

  • Börja Windows PowerShell och använd cmdleten Stop-Proc för att stoppa bearbetningen enligt nedan. Eftersom cmdleten anger Name parametern som obligatorisk frågar cmdleten efter parametern.

    PS> stop-proc
    

    Följande utdata visas.

    Cmdlet stop-proc at command pipeline position 1
    Supply values for the following parameters:
    Name[0]:
    
  • Nu ska vi använda cmdleten för att stoppa processen med namnet "ANTECKNINGAR". Cmdleten ber dig att bekräfta åtgärden.

    PS> stop-proc -Name notepad
    

    Följande utdata visas.

    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
    
  • Använd Stop-Proc som visas för att stoppa den kritiska processen med namnet "WINLOGON". Du uppmanas och varnas om att utföra den här åtgärden eftersom det gör att operativsystemet startas om.

    PS> stop-proc -Name Winlogon
    

    Följande utdata visas.

    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
    
  • Nu ska vi försöka stoppa WINLOGON-processen utan att få en varning. Tänk på att den här kommandoposten använder Force parametern för att åsidosätta varningen.

    PS> stop-proc -Name winlogon -Force
    

    Följande utdata visas.

    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
    

Se även

Lägga till parametrar som bearbetar Command-Line indata

Utöka objekttyper och formatering

Registrera cmdlets, providers och värdprogram

Windows PowerShell SDK

Cmdlet-exempel