What is the best way to implement a Whatif option into a script?

I would like some suggestions on the best, most efficient, easiest, etc ways to implement a Whatif option into a script?

It will be hard to recommend something meaningful without to know what your script is actually about. Did you know that all Powershell cmdlets potentially able to harm your computer have a parameter -WhatIf? You can read more about this with Get-Help about_common_Paramters.

Thank you for replying. I’m using a series of functions to migrate Exchange 2010 public folders to Exchange online shared mailboxes. Function example below. I would like to have a whatif for the new-mailbox cmdlet. Or optimally when running the script that contains all the functions include a WhatIf that then applies to all the functions within. I was trying to avoid using an If statement and including 2 separate cmdlets for each one in each function.

PF-Migration.ps1 contains the following function:

Function Create-SharedMailbox($List)
{
    Foreach($Item in $List)
    {    
        $SMTP = $Item.PrimarySmtpAddress.local + "-PF" + '@' + $Item.PrimarySmtpAddress.domain
        $Name = "$($Item.DisplayName)-PF"
        $Alias = "$($Item.Alias)-PF"
        New-Mailbox -Shared -Name $Name -DisplayName $Name -Alias $Alias -UserPrincipalName $SMTP  
    }

} # Function Close

Hmmm … that’s what I meant in my first answer. New-Mailbox has the support for -WhatIf built in - you just have to use it. Please read the help completely! :wink:

You may read as well the help for about_Functions_advenced_Parameters.

Sorry, I may not be clear on what I’m looking for, and I’m a hack. I know the new-mailbox cmdlet has a WhatIf parameter built in. I’ve read read up on functions, although I’m not great with them beyond the basics, so I haven’t bothered to go re-read the link. I will if you’re suggesting it can help me figure out a good way to do this. I would like an admin that’s running the script, or the function within the script itself to be able to use a whatIf. So if I run “Create-SharedMailbox $Name -whatif” , then the function will account for it by running new-mailbox with a WhatIf switch. If I run just “Create-SharedMailbox $Name” then it will run new-mailbox without the Whatif and create the mailbox.

I got this. :wink: But you will need to implement this by yourself. There’s no magic trick you can swing your magic wand to make this work. You will need to add a param block with a switch parameter and add a condition to the cmdlet you like.

You should ALWAYS read the complete help including the examples for the cmdlets you’re about to use to learn how to use them. You may consider using the common parameter -Confirm. With this the user gets a confirmation prompt and has to confirm the action. :wink:

You can implement WhatIf to your script/function using [CMDletBinding()]

# new script
[CmdletBinding(SupportShouldProcess=$True)]
Param(
    [string]$Name
)

Stop-Process -ProcessName $Name
# call the abovescript
start-process cmd # a test process to run the script
.\abovescript.ps1 -Name cmd # this should close the cmd process running

start-process cmd # another test process to run the script
.\abovescript.ps1 -Name cmd -WhatIf # magic happens here.

Below article gives you more information on this.

Please never implement a manual `-WhatIf` switch. Common parameters exist for a reason, and should be utilised. Users of a script or function should never have to guess at whether a `-WhatIf` parameter was implemented correctly. The presence of that parameter as a common parameter typically indicates the author knew what they were doing. A manually-added parameter will raise a lot of questions, and you really have no way of knowing if the implementation is in any way adequate.

Also, a manual implementation will not correctly pass along `-WhatIf` values to called cmdlets, whereas use of the common parameter will cause it to be automatically affixed to cmdlets that support it already. If you call the main function with `-WhatIf` and the function calls `Remove-Item`, then the `-WhatIf` value will be passed along to `Remove-Item`.

@kvprasoon’s example is a great place to start.

As a side note, in your example you missed an “s” at the end of “Support” in “SupportShouldProcess”. It should be “SupportsShouldProcess”. It throws the following error when it’s not correct, “Property ‘SupportShouldProcess’ cannot be found for type ‘System.Management.Automation.CmdletBindingAttribute’”.

I tried cmdletbinding, and I get essentially the opposite of what I wanted. For instance, with the Set-PFforwards function below when running “Set-PFforwards -list $list2 -whatif”, the forward is created (Whatiif not used), but the out-file does use the Whatif. The Set-MailPublicFolder cmdlet does have a built in Whatif. Maybe it’s because I’m remoting to Exchange to, and pulling down the cmdlets? So, what I really want is for the Exchange cmdlets to get the Whatif and the out-file not to.

‘What if: Performing the operation “Output to File” on target “C:\PFs\Logs\PF-Migration_2019-12-04_11.36.49.log”.’

Function Set-PFforwards()
{    
    [CmdletBinding(SupportsShouldProcess=$True)]
    param($List)
        
    Foreach($Item in $List)
    {        
        $EXOSMTP = $Item.PrimarySmtpAddress.local + "-PF" + '@' + $Item.PrimarySmtpAddress.domain 

        Set-MailPublicFolder $item.displayname -DeliverToMailboxAndForward $TRUE -ForwardingAddress $EXOSMTP

        "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Set-MailPublicFolder $($item.displayname) -DeliverToMailboxAndForward $TRUE -ForwardingAddress $($EXOSMTP)" | out-file $LogPath -Append
    }

} # Function Close

@MattB depending on exactly what that command is, you may have trouble passing it along automatically. For clarity; -WhatIf options implemented via SupportsShouldProcess will be passed along to cmdlets (that is, compiled commands imported from a DLL module) and functions that belong to the same module as the command implementing SupportsShouldProcess. If you have a script command from a separate module that implements ShouldProcess, there is a long-standing bug that prevents the state being copied across.

If you need to work with those commands, you can manually pass along the current -WhatIf value that is set by ShouldProcess by applying -WhatIf:$WhatIfPreference. That does assume that the command you’re calling actually implements SupportsShouldProcess and is doing the proper checks. If it does not, you can instead use the examples in the blog post that @kvprasoon linked in order to check the current ShouldProcess state before calling the Set-MailPublicFolder command.

And if you need to suppress the WhatIf state from a specific cmdlet call, you can apply -WhatIf:$false on that call.

Here’s a whatif/confirm example from Windows Powershell in Action:

function Stop-ProcessUsingWMI
{
  [CmdletBinding(SupportsShouldProcess=$True)]
  param(
    [parameter(mandatory=$true)] [regex] $pattern
  )
  foreach ($process in Get-WmiObject Win32_Process |
    where { $_.Name -match $pattern })
  {
    if ($PSCmdlet.ShouldProcess(
      "process $($process.Name) " +
       " (id: $($process.ProcessId))" ,
    "  Stop Process"))
    {
      $process.Terminate()
    }
  }
}

notepad

Stop-ProcessUsingWMI notepad -Whatif

What if: Performing operation "Stop Process" on Target
"process notepad.exe (id: 6748)".

Stop-ProcessUsingWMI notepad -Confirm

Confirm
Are you sure you want to perform this action?
Performing operation "Stop Process" on Target
"process notepad.exe (id: 6748)".
[Y] Yes [A] Yes to All [N] No [L] No to All
[S] Suspend[?] Help (default is "Y"): y

Thank you for your help!!! I’m under a time crunch with some things including having a final or workable product for the PF work, so I can’t spend time on this right now. I plan to revisit next week.