Alles, was Sie schon immer über ShouldProcess wissen wolltenEverything you wanted to know about ShouldProcess

PowerShell-Funktionen verfügen über mehrere Features, die die Interaktion der Benutzer mit ihnen erheblich verbessern.PowerShell functions have several features that greatly improve the way users interact with them. Ein wichtiges Feature, das oft übersehen wird, ist die Unterstützung von -WhatIf und -Confirm – diese lässt sich ganz einfach zu Ihren Funktionen hingefügen.One important feature that is often overlooked is -WhatIf and -Confirm support and it's easy to add to your functions. In diesem Artikel möchte ich Ihnen ausführlich erläutern, wie Sie dieses Feature implementieren.In this article, we dive deep into how to implement this feature.

Hinweis

Die Originalversion dieses Artikels ist im Blog von @KevinMarquette erschienen.The original version of this article appeared on the blog written by @KevinMarquette. Das PowerShell-Team dankt Kevin Marquette dafür, dass er diesen Inhalt mit uns teilt.The PowerShell team thanks Kevin for sharing this content with us. Weitere Informationen finden Sie in seinem Blog auf PowerShellExplained.com.Please check out his blog at PowerShellExplained.com.

Dies ist ein einfaches Feature, das Sie in Ihren Funktionen aktivieren können, um ein Sicherheitsnetz für die Benutzer bereitzustellen, die es benötigen.This is a simple feature you can enable in your functions to provide a safety net for the users that need it. Es kann schon sehr beängstigend sein, zum ersten Mal einen Befehl auszuführen, von dem Sie wissen, dass er gefährlich sein kann.There's nothing scarier than running a command that you know can be dangerous for the first time. Die Option, ihn mit -WhatIf auszuführen, kann da einen großen Unterschied ausmachen.The option to run it with -WhatIf can make a big difference.

CommonParametersCommonParameters

Bevor wir uns mit der Implementierung dieser Allgemeine Parameter befassen, möchte ich kurz darauf eingehen, wie diese verwendet werden.Before we look at implementing these common parameters, I want to take a quick look at how they're used.

Verwenden: -WhatIfUsing -WhatIf

Wenn ein Befehl den -WhatIf-Parameter unterstützt, können Sie sehen, was der Befehl getan hätte, anstatt die Änderungen direkt vorzunehmen.When a command supports the -WhatIf parameter, it allows you to see what the command would have done instead of making changes. Das ist eine gute Möglichkeit, die Auswirkungen eines Befehls zu testen, vor allem, bevor Sie etwas tun, das zerstörerische Folgen haben könnte.it's a good way to test out the impact of a command, especially before you do something destructive.

PS C:\temp> Remove-Item -Path .\myfile1.txt -WhatIf
What if: Performing the operation "Remove File" on target "C:\Temp\myfile1.txt".

Wenn der Befehl ShouldProcess ordnungsgemäß implementiert, sollte er Ihnen alle Änderungen zeigen, die er vorgenommen hätte.If the command correctly implements ShouldProcess, it should show you all the changes that it would have made. Im Folgenden sehen Sie ein Beispiel für die Verwendung eines Platzhalters zum Löschen mehrerer Dateien.Here is an example using a wildcard to delete multiple files.

PS C:\temp> Remove-Item -Path * -WhatIf
What if: Performing the operation "Remove File" on target "C:\Temp\myfile1.txt".
What if: Performing the operation "Remove File" on target "C:\Temp\myfile2.txt".
What if: Performing the operation "Remove File" on target "C:\Temp\importantfile.txt".

Verwenden: -ConfirmUsing -Confirm

Befehle, die -WhatIf unterstützen, unterstützen auch -Confirm.Commands that support -WhatIf also support -Confirm. Dadurch haben Sie die Möglichkeit, eine Aktion zu bestätigen, bevor Sie sie ausführen.This gives you a chance confirm an action before performing it.

PS C:\temp> Remove-Item .\myfile1.txt -Confirm

Confirm
Are you sure you want to perform this action?
Performing the operation "Remove File" on target "C:\Temp\myfile1.txt".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"):

In diesem Fall haben Sie mehrere Optionen, mit denen Sie das Skript fortsetzen, eine Änderung überspringen oder das Skript anhalten können.In this case, you have multiple options that allow you to continue, skip a change, or stop the script. In der Hilfeanzeige werden die einzelnen Optionen beschrieben.The help prompt describes each of those options like this.

Y - Continue with only the next step of the operation.
A - Continue with all the steps of the operation.
N - Skip this operation and proceed with the next operation.
L - Skip this operation and all subsequent operations.
S - Pause the current pipeline and return to the command prompt. Type "exit" to resume the pipeline.
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"):

LokalisierungLocalization

Diese Eingabeaufforderung ist in PowerShell lokalisiert, sodass sich die Sprache basierend auf der Sprache Ihres Betriebssystems ändert.This prompt is localized in PowerShell so the language changes based on the language of your operating system. Dies ist ein weiterer Aspekt, den PowerShell für Sie übernimmt.This is one more thing that PowerShell manages for you.

Switch-ParameterSwitch parameters

Schauen wir uns kurz an, wie Sie einen Wert an einen Switch-Parameter übergeben.Let's take quick moment to look at ways to pass a value to a switch parameter. Ich spreche diesen Aspekt hauptsächlich deswegen an, weil es häufig vorkommen wird, dass Sie Parameterwerte an die Funktionen übergeben möchten, die Sie aufrufen.The main reason I call this out is that you often want to pass parameter values to functions you call.

Der erste Ansatz ist eine spezifische Parametersyntax, die sich zwar für alle Parameter eignet, aber meistens für Switch-Parameter eingesetzt wird.The first approach is a specific parameter syntax that can be used for all parameters but you mostly see it used for switch parameters. Um einen Wert an den Parameter anzufügen, geben Sie einen Doppelpunkt an.You specify a colon to attach a value to the parameter.

Remove-Item -Path:* -WhatIf:$true

Dasselbe können Sie mit einer Variablen machen.You can do the same with a variable.

$DoWhatIf = $true
Remove-Item -Path * -WhatIf:$DoWhatIf

Der zweite Ansatz besteht darin, eine Hashtabelle zum Splatten des Werts zu verwenden.The second approach is to use a hashtable to splat the value.

$RemoveSplat = @{
    Path = '*'
    WhatIf = $true
}
Remove-Item @RemoveSplat

Wenn Sie noch nicht mit Hashtabellen oder dem Splatting vertraut sind, lesen Sie den Artikel Alles, was Sie schon immer über Hashtabellen wissen wollten.If you're new to hashtables or splatting, I have another article on that covers everything you wanted to know about hashtables.

SupportsShouldProcessSupportsShouldProcess

Der erste Schritt beim Aktivieren der Unterstützung für -WhatIf und -Confirm besteht darin, SupportsShouldProcess in der CmdletBinding der Funktion anzugeben.The first step to enable -WhatIf and -Confirm support is to specify SupportsShouldProcess in the CmdletBinding of your function.

function Test-ShouldProcess {
    [CmdletBinding(SupportsShouldProcess)]
    param()
    Remove-Item .\myfile1.txt
}

Wenn wir SupportsShouldProcess auf diese Weise angeben, können wir die Funktion mit -WhatIf (oder -Confirm) aufrufen.By specifying SupportsShouldProcess in this way, we can now call our function with -WhatIf (or -Confirm).

PS> Test-ShouldProcess -WhatIf
What if: Performing the operation "Remove File" on target "C:\Temp\myfile1.txt".

Beachten Sie, dass ich keinen Parameter namens -WhatIf erstellt habe.Notice that I did not create a parameter called -WhatIf. Durch die Angabe von SupportsShouldProcess wird dieser automatisch für uns erstellt.Specifying SupportsShouldProcess automatically creates it for us. Wenn wir den -WhatIf-Parameter in Test-ShouldProcess angeben, führen einige Funktionen, die wir aufrufen, auch eine -WhatIf-Verarbeitung aus.When we specify the -WhatIf parameter on Test-ShouldProcess, some things we call also perform -WhatIf processing.

Vertrauen ist gut – Kontrolle ist besserTrust but verify

Hier lauert eine gewisse Gefahr, wenn Sie blind darauf vertrauen, dass jeder Befehl, der aufgerufen wird, -WhatIf-Werte erbt.There's some danger here trusting that everything you call inherits -WhatIf values. Bei den weiteren Beispielen gehe ich davon aus, dass dies nicht funktioniert, und werde bei Aufrufen anderer Befehle sehr explizit sein.For the rest of the examples, I'm going to assume that it doesn't work and be very explicit when making calls to other commands. Ich empfehle Ihnen, genauso vorzugehen.I recommend that you do the same.

function Test-ShouldProcess {
    [CmdletBinding(SupportsShouldProcess)]
    param()
    Remove-Item .\myfile1.txt -WhatIf:$WhatIfPreference
}

Ich werde auf die Besonderheiten später noch einmal zurückkommen, wenn Sie alle Puzzleteile kennen.I will revisit the nuances much later once you have a better understanding of all the pieces in play.

$PSCmdlet.ShouldProcess$PSCmdlet.ShouldProcess

Zum Implementieren von SupportsShouldProcess benötigen Sie die Methode $PSCmdlet.ShouldProcess.The method that allows you to implement SupportsShouldProcess is $PSCmdlet.ShouldProcess. Sie rufen $PSCmdlet.ShouldProcess(...) auf, um festzustellen, ob Logik verarbeitet werden muss – um den Rest kümmert sich PowerShell.You call $PSCmdlet.ShouldProcess(...) to see if you should process some logic and PowerShell takes care of the rest. Beginnen wir mit einem Beispiel:Let's start with an example:

function Test-ShouldProcess {
    [CmdletBinding(SupportsShouldProcess)]
    param()

    $file = Get-ChildItem './myfile1.txt'
    if($PSCmdlet.ShouldProcess($file.Name)){
        $file.Delete()
    }
}

Der Aufruf von $PSCmdlet.ShouldProcess($file.name) überprüft, ob der Parameter -WhatIf (und der Parameter -Confirm) vorhanden ist, und verarbeitet ihn dann entsprechend.The call to $PSCmdlet.ShouldProcess($file.name) checks for the -WhatIf (and -Confirm parameter) then handles it accordingly. Durch -WhatIf gibt ShouldProcess eine Beschreibung der Änderung aus und gibt $false zurück:The -WhatIf causes ShouldProcess to output a description of the change and return $false:

PS> Test-ShouldProcess -WhatIf
What if: Performing the operation "Test-ShouldProcess" on target "myfile1.txt".

Ein Aufruf mit -Confirm hält das Skript an und fordert den Benutzer zum Fortfahren auf.A call using -Confirm pauses the script and prompts the user with the option to continue. Wenn der Benutzer Y ausgewählt hat, wird $true zurückgegeben.It returns $true if the user selected Y.

PS> Test-ShouldProcess -Confirm
Confirm
Are you sure you want to perform this action?
Performing the operation "Test-ShouldProcess" on target "myfile1.txt".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"):

Ein tolles Feature von $PSCmdlet.ShouldProcess ist, dass es auch eine ausführliche Ausgabe bietet.An awesome feature of $PSCmdlet.ShouldProcess is that it doubles as verbose output. Das benötige ich beim Implementieren von ShouldProcess häufig.I depend on this often when implementing ShouldProcess.

PS> Test-ShouldProcess -Verbose
VERBOSE: Performing the operation "Test-ShouldProcess" on target "myfile1.txt".

ÜberladungenOverloads

Es gibt verschiedene Überladungen für $PSCmdlet.ShouldProcess mit unterschiedlichen Parametern zum Anpassen des Messaging.There are a few different overloads for $PSCmdlet.ShouldProcess with different parameters for customizing the messaging. Die erste findet sich bereits im Beispiel oben.We already saw the first one in the example above. Sehen wir uns das einmal genauer an.Let's take a closer look at it.

function Test-ShouldProcess {
    [CmdletBinding(SupportsShouldProcess)]
    param()

    if($PSCmdlet.ShouldProcess('TARGET')){
        # ...
    }
}

Die Ausgabe dieses Beispiels enthält sowohl den Funktionsnamen als auch das Ziel (den Wert des Parameters).This produces output that includes both the function name and the target (value of the parameter).

What if: Performing the operation "Test-ShouldProcess" on target "TARGET".

Jetzt geben wir einen zweiten Parameter an, da der Vorgang den Vorgangswert statt des Funktionsnamens in der Meldung verwendet.Specifying a second parameter as the operation uses the operation value instead of the function name in the message.

## $PSCmdlet.ShouldProcess('TARGET','OPERATION')
What if: Performing the operation "OPERATION" on target "TARGET".

Die nächste Option besteht darin, drei Parameter anzugeben, um die Meldung vollständig anzupassen.The next option is to specify three parameters to fully customize the message. Wenn drei Parameter verwendet werden, ist der erste die gesamte Meldung.When three parameters are used, the first one is the entire message. Die nächsten beiden Parameter werden weiterhin in der Meldungsausgabe von -Confirm verwendet.The second two parameters are still used in the -Confirm message output.

## $PSCmdlet.ShouldProcess('MESSAGE','TARGET','OPERATION')
What if: MESSAGE

Kurze ParameterreferenzQuick parameter reference

Wenn Sie diesen Artikel nur lesen, um herauszufinden, welche Parameter Sie verwenden sollten, finden Sie hier eine kurze Referenz, die zeigt, wie die Parameter die Meldung in den verschiedenen -WhatIf-Szenarien verändern.Just in case you came here only to figure out what parameters you should use, here is a quick reference showing how the parameters change the message in the different -WhatIf scenarios.

## $PSCmdlet.ShouldProcess('TARGET')
What if: Performing the operation "FUNCTION_NAME" on target "TARGET".

## $PSCmdlet.ShouldProcess('TARGET','OPERATION')
What if: Performing the operation "OPERATION" on target "TARGET".

## $PSCmdlet.ShouldProcess('MESSAGE','TARGET','OPERATION')
What if: MESSAGE

Ich verwende in der Regel die Variante mit zwei Parametern.I tend to use the one with two parameters.

ShouldProcessReasonShouldProcessReason

Es gibt noch eine vierte Überladung, die ausgereifter ist als die anderen.We have a fourth overload that's more advanced than the others. Mit dieser können Sie den Grund für die Ausführung von ShouldProcess abrufen.It allows you to get the reason ShouldProcess was executed. Ich führe dies hier nur der Vollständigkeit halber an, weil wir einfach prüfen können, ob $WhatIfPreference stattdessen $true ist.I'm only adding this here for completeness because we can just check if $WhatIfPreference is $true instead.

$reason = ''
if($PSCmdlet.ShouldProcess('MESSAGE','TARGET','OPERATION',[ref]$reason)){
    Write-Output "Some Action"
}
$reason

Wir müssen die $reason-Variable als Verweisvariable mit [ref] an den vierten Parameter übergeben.We have to pass the $reason variable into the fourth parameter as a reference variable with [ref]. ShouldProcess füllt $reason mit dem Wert None oder WhatIf auf.ShouldProcess populates $reason with the value None or WhatIf. Ich behaupte nicht, dass dies nützlich ist, und es gab für mich bisher auch noch keinen Grund, das so zu verwenden.I didn't say this was useful and I have had no reason to ever use it.

Die richtige PositionWhere to place it

Mit ShouldProcess können Sie Ihre Skripts sicherer machen.You use ShouldProcess to make your scripts safer. Verwenden Sie das Feature also dann, wenn Ihre Skripts Änderungen vornehmen.So you use it when your scripts are making changes. Ich füge den $PSCmdlet.ShouldProcess-Aufruf gern so nah wie möglich an der Änderung ein.I like to place the $PSCmdlet.ShouldProcess call as close to the change as possible.

## general logic and variable work
if ($PSCmdlet.ShouldProcess('TARGET','OPERATION')){
    # Change goes here
}

Wenn ich eine Auflistung von Elementen verarbeite, rufe ich das Feature für jedes Element auf.If I'm processing a collection of items, I call it for each item. Der Aufruf wird also in der ForEach-Schleife eingefügt.So the call gets placed inside the foreach loop.

foreach ($node in $collection){
    # general logic and variable work
    if ($PSCmdlet.ShouldProcess($node,'OPERATION')){
        # Change goes here
    }
}

Ich platziere ShouldProcess um die Änderung, weil ich möchte, dass so viel Code wie möglich ausgeführt wird, wenn -WhatIf angegeben wird.The reason why I place ShouldProcess tightly around the change, is that I want as much code to execute as possible when -WhatIf is specified. Die Setup- und Validierungsprozesse sollen nach Möglichkeit ausgeführt werden, damit der Benutzer diese Fehler sehen kann.I want the setup and validation to run if possible so the user gets to see those errors.

Ich verwende das auch gern in meinen Pester-Tests, mit denen meine Projekte validiert werden.I also like to use this in my Pester tests that validate my projects. Wenn ich mit Logik arbeite, die in Pester schwer zu simulieren ist, kann ich sie häufig in ShouldProcess umschließen und mit -WhatIf in meinen Tests aufzurufen.If I have a piece of logic that is hard to mock in pester, I can often wrap it in ShouldProcess and call it with -WhatIf in my tests. Es ist immer noch besser, einen Teil Ihres Codes zu testen als gar keinen.It's better to test some of your code than none of it.

$WhatIfPreference$WhatIfPreference

Unsere erste Einstellungsvariable ist $WhatIfPreference.The first preference variable we have is $WhatIfPreference. Diese ist standardmäßig auf $false festgelegt.This is $false by default. Wenn Sie sie auf $true festlegen, wird die Funktion so ausgeführt, als ob Sie -WhatIf angegeben haben.If you set it to $true then your function executes as if you specified -WhatIf. Wenn Sie dies in Ihrer Sitzung festlegen, werden alle Befehle mit -WhatIf ausgeführt.If you set this in your session, all commands perform -WhatIf execution.

Wenn Sie eine Funktion mit -WhatIf aufrufen, wird der Wert von $WhatIfPreference innerhalb des Gültigkeitsbereichs der Funktion auf $true festgelegt.When you call a function with -WhatIf, the value of $WhatIfPreference gets set to $true inside the scope of your function.

ConfirmImpactConfirmImpact

Die meisten meiner Beispiele beziehen sich auf -WhatIf, sie funktionieren aber auch mit -Confirm, um dem Benutzer eine Eingabeaufforderung anzuzeigen.Most of my examples are for -WhatIf but everything so far also works with -Confirm to prompt the user. Sie können den ConfirmImpact-Parameter der Funktion auf „High“ festlegen, und der Benutzer wird zu einer Eingabe aufgefordert, so als ob der Aufruf mit -Confirm erfolgt wäre.You can set the ConfirmImpact of the function to high and it prompts the user as if it was called with -Confirm.

function Test-ShouldProcess {
    [CmdletBinding(
        SupportsShouldProcess,
        ConfirmImpact = 'High'
    )]
    param()

    if ($PSCmdlet.ShouldProcess('TARGET')){
        Write-Output "Some Action"
    }
}

Da High festgelegt wurde, führt dieser Aufruf von Test-ShouldProcess die -Confirm-Aktion aus.This call to Test-ShouldProcess is performing the -Confirm action because of the High impact.

PS> Test-ShouldProcess

Confirm
Are you sure you want to perform this action?
Performing the operation "Test-ShouldProcess" on target "TARGET".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): y
Some Action

Das offensichtliche Problem besteht darin, dass es jetzt schwieriger ist, das Ganze in anderen Skripten zu verwenden, ohne eine Eingabeaufforderung für den Benutzer anzuzeigen.The obvious issue is that now it's harder to use in other scripts without prompting the user. In diesem Fall können wir $false an -Confirm übergeben, um die Eingabeaufforderung zu unterdrücken.In this case, we can pass a $false to -Confirm to suppress the prompt.

PS> Test-ShouldProcess -Confirm:$false
Some Action

In einem späteren Abschnitt werde ich erläutern, wie die -Force-Unterstützung hinzugefügt wird.I'll cover how to add -Force support in a later section.

$ConfirmPreference$ConfirmPreference

$ConfirmPreference ist eine automatische Variable, die steuert, wann ConfirmImpact Sie zur Bestätigung der Ausführung auffordert.$ConfirmPreference is an automatic variable that controls when ConfirmImpact asks you to confirm execution. Hier sind die möglichen Werte sowohl für $ConfirmPreference als auch für ConfirmImpact.Here are the possible values for both $ConfirmPreference and ConfirmImpact.

  • High
  • Medium
  • Low
  • None

Mit diesen Werten können Sie für jede Funktion unterschiedliche Auswirkungsstufen angeben.With these values, you can specify different levels of impact for each function. Wenn Sie $ConfirmPreference auf einen höheren Wert als ConfirmImpact festgelegt haben, werden Sie nicht aufgefordert, die Ausführung zu bestätigen.If you have $ConfirmPreference set to a value higher than ConfirmImpact, then you aren't prompted to confirm execution.

Standardmäßig ist $ConfirmPreference auf High und ConfirmImpact auf Medium festgelegt.By default, $ConfirmPreference is set to High and ConfirmImpact is Medium. Wenn Sie möchten, dass die Funktion dem Benutzer automatisch eine Eingabeaufforderung anzeigt, legen Sie ConfirmImpact auf High fest.If you want your function to automatically prompt the user, set your ConfirmImpact to High. Legen Sie andernfalls den Wert Medium fest, wenn die Funktion destruktiv ist, und verwenden Sie Low, wenn der Befehl in der Produktion immer sicher ausgeführt werden kann.Otherwise set it to Medium if its destructive and use Low if the command is always safe run in production. Wenn Sie diesen Wert auf none festlegen, wird auch dann keine Eingabeaufforderung angezeigt, wenn -Confirm angegeben wurde (-WhatIf wird jedoch weiter unterstützt).If you set it to none, it doesn't prompt even if -Confirm was specified (but it still gives you -WhatIf support).

Wenn Sie eine Funktion mit -Confirm aufzurufen, wird der Wert von $ConfirmPreference innerhalb des Gültigkeitsbereichs der Funktion auf Low festgelegt.When calling a function with -Confirm, the value of $ConfirmPreference gets set to Low inside the scope of your function.

Unterdrücken von geschachtelten BestätigungsaufforderungenSuppressing nested confirm prompts

$ConfirmPreference kann von Funktionen übernommen werden, die Sie aufzurufen.The $ConfirmPreference can get picked up by functions that you call. Dadurch können Szenarien entstehen, in denen Sie eine Bestätigungsaufforderung hinzufügen und die von Ihnen aufgerufene Funktion den Benutzer ebenfalls auffordert.This can create scenarios where you add a confirm prompt and the function you call also prompts the user.

Ich gebe in der Regel -Confirm:$false bei den Befehlen an, die ich aufrufe, wenn ich die Eingabeaufforderung bereits verarbeitet habe.What I tend to do is specify -Confirm:$false on the commands that I call when I have already handled the prompting.

function Test-ShouldProcess {
    [CmdletBinding(SupportsShouldProcess)]
    param()

    $file = Get-ChildItem './myfile1.txt'
    if($PSCmdlet.ShouldProcess($file.Name)){
        Remove-Item -Path $file.FullName -Confirm:$false
    }
}

Damit kommen wir zurück zu einer früheren Warnung: Es gibt einige feine Unterschiede, wann -WhatIf nicht an eine Funktion übergeben wird und wann -Confirm an eine Funktion übergeben wird.This brings us back to an earlier warning: There are nuances as to when -WhatIf is not passed to a function and when -Confirm passes to a function. Ich werde später noch einmal darauf zurückkommen, versprochen.I promise I'll get back to this later.

$PSCmdlet.ShouldContinue$PSCmdlet.ShouldContinue

Wenn Sie mehr Kontrolle benötigen, als ShouldProcess Ihnen ermöglicht, können Sie die Eingabeaufforderung direkt mit ShouldContinue auslösen.If you need more control than ShouldProcess provides, you can trigger the prompt directly with ShouldContinue. ShouldContinue ignoriert $ConfirmPreference, ConfirmImpact, -Confirm, $WhatIfPreference und -WhatIf, da bei jeder Ausführung eine Eingabeaufforderung angezeigt wird.ShouldContinue ignores $ConfirmPreference, ConfirmImpact, -Confirm, $WhatIfPreference, and -WhatIf because it prompts every time it's executed.

Auf den ersten Blick können ShouldProcess und ShouldContinue leicht verwechselt werden.At a quick glance, it's easy to confuse ShouldProcess and ShouldContinue. Ich erinnere mich meist deswegen an die Verwendung von ShouldProcess, weil der Parameter in CmdletBinding als SupportsShouldProcess bezeichnet wird.I tend to remember to use ShouldProcess because the parameter is called SupportsShouldProcess in the CmdletBinding. Sie sollten ShouldProcess in so ziemlich jedem Szenario verwenden.You should use ShouldProcess in almost every scenario. Aus diesem Grund habe ich diese Methode zuerst erläutert.That is why I covered that method first.

Sehen wir uns ShouldContinue in Aktion an.Let's take a look at ShouldContinue in action.

function Test-ShouldContinue {
    [CmdletBinding()]
    param()

    if($PSCmdlet.ShouldContinue('TARGET','OPERATION')){
        Write-Output "Some Action"
    }
}

So erhalten wir eine vereinfachte Eingabeaufforderung mit weniger Optionen.This provides us a simpler prompt with fewer options.

Test-ShouldContinue

Second
TARGET
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"):

Das größte Problem bei ShouldContinue besteht darin, dass die Ausführung durch den Benutzer interaktiv erfolgen muss, weil der Benutzer immer eine Eingabeaufforderung erhält.The biggest issue with ShouldContinue is that it requires the user to run it interactively because it always prompts the user. Sie sollten immer Tools erstellen, die von anderen Skripts verwendet werden können.You should always be building tools that can be used by other scripts. Zu diesem Zweck implementieren Sie -Force.The way you do this is by implementing -Force. Ich komme auf diesen Punkt später noch einmal zurück.I'll revisit this idea later.

Ja zu allemYes to all

Dies wird mit ShouldProcess automatisch verarbeitet, aber für ShouldContinue müssen wir etwas mehr Arbeit investieren.This is automatically handled with ShouldProcess but we have to do a little more work for ShouldContinue. Es gibt eine zweite Methodenüberladung, bei der wir per Verweis einige Werte übergeben müssen, um die Logik zu steuern.There's a second method overload where we have to pass in a few values by reference to control the logic.

function Test-ShouldContinue {
    [CmdletBinding()]
    param()

    $collection = 1..5
    $yesToAll = $false
    $noToAll = $false

    foreach($target in $collection) {

        $continue = $PSCmdlet.ShouldContinue(
                "TARGET_$target",
                'OPERATION',
                [ref]$yesToAll,
                [ref]$noToAll
            )

        if ($continue){
            Write-Output "Some Action [$target]"
        }
    }
}

Ich habe eine foreach-Schleife und eine Auflistung hinzugefügt, um das Ganze in Aktion anzuzeigen.I added a foreach loop and a collection to show it in action. Ich habe den ShouldContinue-Befehl aus der if-Anweisung herausgezogen, um die Lesbarkeit zu verbessern.I pulled the ShouldContinue call out of the if statement to make it easier to read. Der Aufruf einer Methode mit vier Parametern wird langsam etwas unschön, aber ich habe versucht, es so übersichtlich wie möglich zu gestalten.Calling a method with four parameters starts to get a little ugly, but I tried to make it look as clean as I could.

Implementieren: -ForceImplementing -Force

ShouldProcess und ShouldContinue müssen -Force unterschiedlich implementieren.ShouldProcess and ShouldContinue need to implement -Force in different ways. Der Trick bei diesen Implementierungen ist, dass ShouldProcess immer ausgeführt werden sollte, ShouldContinue aber nicht ausgeführt werden sollte, wenn -Force angegeben ist.The trick to these implementations is that ShouldProcess should always get executed, but ShouldContinue should not get executed if -Force is specified.

ShouldProcess: -ForceShouldProcess -Force

Wenn Sie ConfirmImpact auf high festlegen, wird der Benutzer zunächst versuchen, das mit -Force zu unterdrücken.If you set your ConfirmImpact to high, the first thing your users are going to try is to suppress it with -Force. Das ist sowieso das erste, was ich mache.That's the first thing I do anyway.

Test-ShouldProcess -Force
Error: Test-ShouldProcess: A parameter cannot be found that matches parameter name 'force'.

Wie Sie aus dem Abschnitt ConfirmImpact wissen, müssen Sie ihn wie folgt bezeichnen:If you recall from the ConfirmImpact section, they actually need to call it like this:

Test-ShouldProcess -Confirm:$false

Nicht allen ist klar, dass das notwendig ist, und -Force nicht ShouldContinue unterdrückt.Not everyone realizes they need to do that and -Force doesn't suppress ShouldContinue. Daher sollten wir -Force für die Benutzerfreundlichkeit implementieren.So we should implement -Force for the sanity of our users. Schauen wir uns hier dieses vollständige Beispiel an:Take a look at this full example here:

function Test-ShouldProcess {
    [CmdletBinding(
        SupportsShouldProcess,
        ConfirmImpact = 'High'
    )]
    param(
        [Switch]$Force
    )

    if ($Force){
        $ConfirmPreference = 'None'
    }

    if ($PSCmdlet.ShouldProcess('TARGET')){
        Write-Output "Some Action"
    }
}

Wir fügen unseren Switch -Force als Parameter hinzu.We add our own -Force switch as a parameter. Der Parameter -Confirm wird automatisch hinzugefügt, wenn SupportsShouldProcess in CmdletBinding verwendet wird.The -Confirm parameter is automatically added when using SupportsShouldProcess in the CmdletBinding.

[CmdletBinding(
    SupportsShouldProcess,
    ConfirmImpact = 'High'
)]
param(
    [Switch]$Force
)

Hier konzentrieren wir uns auf die -Force-Logik:Focusing in on the -Force logic here:

if ($Force){
    $ConfirmPreference = 'None'
}

Wenn der Benutzer -Force angibt, möchten wir die Bestätigungsaufforderung unterdrücken, es sei denn, es wird auch -Confirm angegeben.If the user specifies -Force, we want to suppress the confirm prompt unless they also specify -Confirm. Dadurch kann ein Benutzer eine Änderung erzwingen, diese aber dennoch bestätigen.This allows a user to force a change but still confirm the change. Dann legen wir $ConfirmPreference im lokalen Geltungsbereich fest.Then we set $ConfirmPreference in the local scope. Durch Verwenden des Parameters -Force wird der Parameter $ConfirmPreference vorübergehend auf „none“ festgelegt, wodurch die Bestätigungsaufforderung deaktiviert wird.Now, using the -Force parameter temporarily sets the $ConfirmPreference to none, disabling prompt for confirmation.

if ($Force -or $PSCmdlet.ShouldProcess('TARGET')){
        Write-Output "Some Action"
    }

Wenn sowohl -Force als auch -WhatIf angegeben werden, muss -WhatIf Priorität haben.If someone specifies both -Force and -WhatIf, then -WhatIf needs to take priority. Dieser Ansatz behält die -WhatIf-Verarbeitung bei, weil ShouldProcess immer ausgeführt wird.This approach preserves -WhatIf processing because ShouldProcess always gets executed.

Fügen Sie in der if-Anweisung mit ShouldProcess keine Überprüfung auf den$Force-Wert hinzu.Do not add a check for the $Force value inside the if statement with the ShouldProcess. Es ist ein Antimuster für dieses spezifische Szenario, auch wenn ich Ihnen genau das im nächsten Abschnitt für ShouldContinue zeige.That is an anti-pattern for this specific scenario even though that's what I show you in the next section for ShouldContinue.

ShouldContinue: -ForceShouldContinue -Force

Im Folgenden sehen Sie die richtige Vorgehensweise zum Implementieren von -Force mit ShouldContinue.This is the correct way to implement -Force with ShouldContinue.

function Test-ShouldContinue {
    [CmdletBinding()]
    param(
        [Switch]$Force
    )

    if($Force -or $PSCmdlet.ShouldContinue('TARGET','OPERATION')){
        Write-Output "Some Action"
    }
}

Durch Platzierung links vom -or-Operator wird $Force zuerst ausgewertet.By placing the $Force to the left of the -or operator, it gets evaluated first. Auf diese Weise wird die Ausführung der if-Anweisung umgangen.Writing it this way short circuits the execution of the if statement. Wenn $force den Wert $true aufweist, wird ShouldContinue nicht ausgeführt.If $force is $true, then the ShouldContinue is not executed.

PS> Test-ShouldContinue -Force
Some Action

Wir müssen uns in diesem Szenario nicht um -Confirm oder -WhatIf kümmern, da sie von ShouldContinue nicht unterstützt werden.We don't have to worry about -Confirm or -WhatIf in this scenario because they're not supported by ShouldContinue. Aus diesem Grund muss die Verarbeitung anders erfolgen als bei ShouldProcess.This is why it needs to be handled differently than ShouldProcess.

Probleme mit dem GültigkeitsbereichScope issues

Die Verwendung -WhatIf und -Confirm sollte für alle Aspekte in Ihren Funktionen sowie für alle Elemente gelten, die von Ihren Funktionen aufgerufen werden.Using -WhatIf and -Confirm are supposed to apply to everything inside your functions and everything they call. Dazu legen sie im lokalen Gültigkeitsbereich der Funktion $WhatIfPreference auf $true oder $ConfirmPreference auf Low fest.They do this by setting $WhatIfPreference to $true or setting $ConfirmPreference to Low in the local scope of the function. Wenn Sie eine andere Funktion aufrufen, werden diese Werte in Aufrufen von ShouldProcess verwendet.When you call another function, calls to ShouldProcess use those values.

Dies funktioniert in den meisten Fällen ordnungsgemäß.This actually works correctly most of the time. Es funktioniert jedes Mal, wenn Sie ein integriertes Cmdlet oder eine Funktion im selben Gültigkeitsbereich aufrufen.Anytime you call built-in cmdlet or a function in your same scope, it works. Es funktioniert auch, wenn Sie ein Skript oder eine Funktion in einem Skriptmodul über die Konsole aufzurufen.It also works when you call a script or a function in a script module from the console.

Es gibt nur eine Situation, in der das Ganze nicht funktioniert: Wenn ein Skript oder ein Skriptmodul eine Funktion in einem anderen Skriptmodul aufruft.The one specific place where it doesn't work is when a script or a script module calls a function in another script module. Das klingt vielleicht nicht besonders problematisch, aber die meisten Module, die Sie erstellen oder aus der PSGallery abrufen, sind Skriptmodule.This may not sound like a big problem, but most of the modules you create or pull from the PSGallery are script modules.

Das Hauptproblem ist, dass Skriptmodule die Werte für $WhatIfPreference oder $ConfirmPreference (und einige andere) nicht erben, wenn sie von Funktionen in anderen Skriptmodulen aufgerufen werden.The core issue is that script modules do not inherit the values for $WhatIfPreference or $ConfirmPreference (and several others) when called from functions in other script modules.

Eine allgemeine Regel lässt sich vielleicht so formulieren: Das Ganze funktioniert ordnungsgemäß für binäre Module, aber vertrauen Sie nie darauf, dass es auch für Skriptmodule funktioniert.The best way to summarize this as a general rule is that this works correctly for binary modules and never trust it to work for script modules. Wenn Sie sich nicht sicher sind, sollten Sie es entweder testen, oder einfach annehmen, dass es nicht richtig funktioniert.If you aren't sure, either test it or just assume it doesn't work correctly.

Ich persönlich sehe ein großes Risiko, weil dadurch Szenarien entstehen, in denen Sie -WhatIf-Unterstützung zu mehreren Modulen hinzufügen, die isoliert korrekt funktionieren, dies aber nicht mehr tun, wenn sie sich gegenseitig aufrufen.I personally feel this is very dangerous because it creates scenarios where you add -WhatIf support to multiple modules that work correctly in isolation, but fail to work correctly when they call each other.

Wir arbeiten an einem GitHub-RFC, um dieses Problem zu beheben.We do have a GitHub RFC working to get this issue fixed. Weitere Informationen finden Sie unter Propagate execution preferences beyond script module scope (Weitergeben von Ausführungseinstellungen über den Gültigkeitsbereich des Skriptmoduls hinaus).See Propagate execution preferences beyond script module scope for more details.

AbschlussIn closing

Ich muss jedes Mal nachschlagen, wie ich ShouldProcess verwende.I have to look up how to use ShouldProcess every time I need to use it. Ich habe lange gebraucht, um ShouldProcess von ShouldContinue zu unterscheiden.It took me a long time to distinguish ShouldProcess from ShouldContinue. Ich muss fast immer nachschlagen, welche Parameter ich verwenden darf.I almost always need to look up what parameters to use. Machen Sie sich also keine Sorgen, wenn Sie gelegentlich noch etwas verwirrt sind.So don't worry if you still get confused from time to time. Sie können diesen Artikel bei Bedarf jederzeit hier lesen.This article will be here when you need it. Ich bin mir sicher, dass ich ihn selbst häufig zu Rate ziehen werde.I'm sure I will reference it often myself.

Wenn Ihnen dieser Beitrag gefallen hat, können Sie mir Ihre Meinung auf Twitter über den untenstehenden Link mitteilen.If you liked this post, please share your thoughts with me on Twitter using the link below. Ich höre immer gerne von Menschen, für die meine Inhalte hilfreich sind.I always like hearing from people that get value from my content.