Skapa en cmdlet som ändrar systemet
Ibland måste en cmdlet ändra systemets körningstillstånd, inte bara tillståndet för Windows PowerShell-körningen. I dessa fall bör cmdleten ge användaren en chans att bekräfta om ändringen ska genomföras eller inte.
För att stöda bekräftelse måste en cmdlet göra två saker.
Deklarera att cmdleten stöder bekräftelse när du anger attributet System.Management.Automation.CmdletAttribute genom att ange nyckelordet SupportsShouldProcess till
true
.Anropa System.Management.Automation.Cmdlet.ShouldProcess under körningen av cmdleten (som du ser i följande exempel).
Genom att stödja bekräftelse visar en cmdlet parametrarna Confirm
och WhatIf
som tillhandahålls av Windows PowerShell och som även uppfyller utvecklingsriktlinjerna för cmdletar (Mer information om riktlinjer för cmdlet-utveckling finns i Riktlinjer för cmdlet-utveckling.).
Ändra systemet
Åtgärden att "ändra systemet" refererar till alla cmdletar som potentiellt ändrar systemets tillstånd utanför Windows PowerShell. Att till exempel stoppa en process, aktivera eller inaktivera ett användarkonto eller lägga till en rad i en databastabell är 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 behövs inte heller för åtgärder vars effekt är begränsad till i Windows PowerShell-körningen, till exempel Set-Variable
. Cmdletar som kanske inte gör en beständig ändring bör deklarera SupportsShouldProcess
och anropa System.Management.Automation.Cmdlet.ShouldProcess endast om de är på väg att göra en beständig ändring.
Anmärkning
ShouldProcess-bekräftelse gäller endast för cmdletar. 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, kommer den här typen av bekräftelse inte att vara tillgänglig.
StopProc-cmdleten
Det här avsnittet beskriver en Stop-Proc-cmdlet som försöker stoppa processer som hämtas med hjälp av cmdleten Get-Proc (beskrivs i Skapa din första cmdlet).
Definiera cmdleten
Det första steget när cmdleten skapas är att alltid namnge cmdleten och deklarera .NET-klassen som implementerar cmdleten. Eftersom du skriver en cmdlet för att ändra systemet bör den namnges därefter. Den här cmdleten stoppar systemprocesserna, så verbnamnet som väljs här är "Stop", definierat av System.Management.Automation.VerbsLifecycle-klass, 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 nyckelordet SupportsShouldProcess
attributet System.Management.Automation.CmdletAttribute anges till true
så att cmdleten kan anropa System.Management.Automation.Cmdlet.ShouldProcess och System.Management.Automation.Cmdlet.ShouldContinue.
Utan den här nyckelordsuppsättningen är parametrarna Confirm
och WhatIf
inte tillgängliga för användaren.
Extremt destruktiva åtgärder
Vissa åtgärder är mycket destruktiva, till exempel att formatera om en aktiv hårddiskpartition. I dessa fall bör cmdleten ange ConfirmImpact
= ConfirmImpact.High
när du deklarerar attributet System.Management.Automation.CmdletAttribute. Den här inställningen tvingar cmdleten att begära användarbekräftelse även om användaren inte har angett parametern Confirm
. Cmdlet-utvecklare bör dock undvika att överanvända ConfirmImpact
för åtgärder som bara är potentiellt destruktiva, till exempel att ta bort ett användarkonto. Kom ihåg att om ConfirmImpact
är inställt på System.Management.Automation.ConfirmImpactHigh.
På samma sätt är det osannolikt 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 cmdletar kan ange ConfirmImpact
till System.Management.Automation.ConfirmImpact.Low.
Detta kringgår bekräftelsebegäranden där användaren har bett om att endast bekräfta åtgärder med medelpåverkan 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 Name
i det här exemplet är obligatorisk eftersom cmdleten misslyckas om den inte har någon namngiven process att stoppa.
Med parametern Force
kan användaren åsidosätta anrop till System.Management.Automation.Cmdlet.ShouldContinue.
I själva verket bör alla cmdletar som anropar System.Management.Automation.Cmdlet.ShouldContinue ha en Force
parameter så att cmdleten när Force
anges hoppar över anropet till 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.
Med parametern PassThru
kan användaren ange om cmdleten skickar ett utdataobjekt via pipelinen, i det här fallet efter att en process har stoppats. Tänk på att den här parametern är kopplad till själva cmdleten i stället för till en egenskap för indataobjektet.
Här är parameterdeklarationen för cmdleten 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;
Åsidosätta en indatabearbetningsmetod
Cmdleten måste åsidosätta en indatabearbetningsmetod. Följande kod illustrerar System.Management.Automation.Cmdlet.ProcessRecord åsidosättning som används i exemplet Stop-Proc cmdlet. För varje begärt processnamn ser den här metoden till att processen inte är en speciell process, försöker stoppa processen och skickar sedan ett utdataobjekt om parametern PassThru
anges.
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
Indatabearbetningsmetoden för din cmdlet ska anropa metoden System.Management.Automation.Cmdlet.ShouldProcess för att bekräfta körningen av en åtgärd innan en ändring (till exempel att ta bort filer) görs till systemets körningstillstånd. På så sätt kan Windows PowerShell-körningen ange rätt "WhatIf" och "Confirm"-beteende i gränssnittet.
Anmärkning
Om en cmdlet anger att den stöder bör bearbetas och misslyckas med att göra System.Management.Automation.Cmdlet.ShouldProcess anrop, kan användaren oväntat ändra systemet.
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 eventuella kommandoradsinställningar eller inställningsvariabler för att avgöra 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 exemplet Stop-Proc cmdlet.
if (!ShouldProcess(string.Format("{0} ({1})", processName,
process.Id)))
{
continue;
}
Anropa metoden ShouldContinue
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 true
och om parametern Force
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 ytterligare en kontroll för potentiellt farliga systemändringar eller när du vill ange ja-till-alla och no-to-alla alternativ för användaren.
I följande exempel visas anropet till System.Management.Automation.Cmdlet.ShouldContinue från åsidosättningen av metoden System.Management.Automation.Cmdlet.ProcessRecord i exemplet 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 bearbetning av indata
Indatabearbetningsmetoden för en cmdlet som gör systemändringar måste vara 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 parametern PassThru
ä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 cmdletar 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 med Windows PowerShell via en Windows PowerShell-snapin-modul. Mer information om hur du registrerar cmdletar finns i Så här registrerar du cmdletar, leverantörer 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 cmdleten Stop-Proc. Mer information om hur du använder cmdletar från kommandoraden finns i Komma igång med Windows PowerShell.
Starta Windows PowerShell och använd cmdleten Stop-Proc för att stoppa bearbetningen enligt nedan. Eftersom cmdleten anger parametern
Name
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 "NOTEPAD". Cmdleten ber dig 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 du ser 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 parametern
Force
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