Jack
Jack

Reputation: 115

Possible to use -WhatIf and the invocation operator (&)?

Is it possible to use the -WhatIf argument when executing external commands? I want to be able to run a script with -WhatIf and have it print out a full list of all the external commands and arguments it's going to run without actually running them.

I've tried doing stuff like the following:

Function Invoke-Checked
{
    param([ScriptBlock]$s)

    if ($PSCmdlet.ShouldProcess($s.ToString(), "Execute"))
    {
        Invoke-Command $s
    }
}

But that won't expand any variables that are present in the scriptblock - doing something like:

$s = { & dir $test }
Invoke-Checked $s

just prints

Performing the operation "Execute" on target " & dir $test ".

not particularly helpful.

Is there any way to do what I want?

Upvotes: 1

Views: 1416

Answers (2)

js2010
js2010

Reputation: 27491

I'm going to interpret the question to mean, "how do I use -whatif with running external commands?", since that's how I found this question.

# myscript.ps1
[cmdletbinding(SupportsShouldProcess=$True)]
Param($path)  # put Param() if no parameters

if ($pscmdlet.ShouldProcess($Path, 'creating folder')) { # not -whatif
  cmd /c mkdir $path
}
.\myscript foo -whatif
What if: Performing the operation "creating folder" on target "foo".

Upvotes: 0

BartekB
BartekB

Reputation: 8650

First of all - you need to make sure that your 'wrapper' function supports WhatIf. Another thing: you can expand the scriptBlock, but I'm not really convinced that is smart thing to do: e.g. if $test = 'Some path with spaces', it would stop working after expansion.

That being said: here are two options that work for me: using GetNewClosure() method on scriptBlock, and expanding whole thing:

function Invoke-ExpandedChecked {
[CmdletBinding(
    SupportsShouldProcess = $true,
    ConfirmImpact = 'Medium'
)]
    param([ScriptBlock]$ScriptBlock)

    $expanded = $ExecutionContext.InvokeCommand.ExpandString($ScriptBlock)
    $script = [scriptblock]::Create($expanded)
    if ($PSCmdlet.ShouldProcess($script.ToString(), "Execute"))
    {
        & $script
    }
}

function Invoke-Checked {
[CmdletBinding(
    SupportsShouldProcess = $true,
    ConfirmImpact = 'Medium'
)]
    param([ScriptBlock]$ScriptBlock)

    $newClosure = $ScriptBlock.GetNewClosure()
    if ($PSCmdlet.ShouldProcess($newClosure.ToString(), "Execute"))
    {
        & $newClosure
    }
}

$test = '.\DSCDemo.ps_'
$s = { cmd /c dir $test} 

Invoke-Checked $s -WhatIf
Invoke-Checked $s
Invoke-ExpandedChecked $s -WhatIf
Invoke-ExpandedChecked $s

And an example of results for path with spaces:

$test = 'C:\Program Files'
Invoke-Checked $s
Invoke-ExpandedChecked $s

Works fine for one with new enclosure. With expanded:

cmd : File Not Found
At line:1 char:2
+  cmd /c dir C:\Program Files

Upvotes: 2

Related Questions