3

I want to write a wrapper around New-AzResourceGroupDeployment in PowerShell. So lets assume the following script:

New-AzResourceGroupDeployment `
    -Name 'test' `
    -ResourceGroupName 'rg-test' `
    -TemplateFile .\main.bicep `
    -TemplateParameterFile .\parameters\parameters.json `
    -Verbose `
    -WhatIf

This will output something like this:

VERBOSE: Using Bicep v0.4.1008
...
What if: Performing the operation "Creating Deployment" on target "rg-test".

So the problem here is that I won't get any results from the WhatIf. I guess its because WhatIf runs a different process in the background.

So is there a way to capture the output of the WhatIf?

Alexander Schmidt
  • 5,631
  • 4
  • 39
  • 79
  • I don't think you can, `-WhatIf` doesn't go to any of the PowerShell [output Streams](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_output_streams?view=powershell-7.2#:~:text=PowerShell%20provides%20multiple%20output%20streams,the%20associated%20cmdlet%20or%20redirection.&text=PowerShell%20supports%20the%20following%20output%20streams.) similar to `$testVar = [console]::WriteLine('hello') *>&1` cannot be captured either. – Santiago Squarzon Dec 05 '21 at 17:42
  • `Start-Transcript` can capture it actually but I don't think that's your intent, you want it on a variable right? – Santiago Squarzon Dec 05 '21 at 17:46
  • 1
    @SantiagoSquarzon thx for the suggestions. I think i can‘t do it in a clean way. But good to know some workarounds ;) – Alexander Schmidt Dec 05 '21 at 18:43

1 Answers1

4

The output produced by using the common -WhatIf parameter can unfortunately not be captured in-session - it prints directly to the console (host).

The only workaround is to use PowerShell's CLI (powershell.exe for Windows PowerShell, pwsh for PowerShell (Core) 7+)

$whatIfAndVerboseOutput = powershell.exe -c @'
  New-AzResourceGroupDeployment `
    -Name 'test' `
    -ResourceGroupName 'rg-test' `
    -TemplateFile .\main.bicep `
    -TemplateParameterFile .\parameters\parameters.json `
    -Verbose `
    -WhatIf
'@

Not the use of a verbatim here-string (@'<newline>...<newline>'@) to avoid the need for escaping the embedded quote characters.

Caveats:

  • Such a call is expensive.

  • Since a new, independent session that runs in a child process is created, it knows nothing about the state of the caller (except that it inherits environment variables).

    • Assuming the argument data types are simple enough, you can use an expandable string ("...") to embed values from the caller in the command text.

      • Note: As of PowerShell 7.2, PowerShell's CLI, when a command string is passed to -c (-Command) - which is the only option when calling from outside PowerShell - not only sends direct-to-console output to stdout, but all of its output streams there as well - including error - which is problematic: see the bottom section of this answer for details; here, this means that the -Verbose output is captured as well.
    • Alternatively, for better - but not complete - type fidelity, pass a script block ({ ... }) to -c (-Command) instead of a string, to which you can pass values from the caller with -args. Note that using a script block is only an option when also calling from Powershell and that doing so will insert an empty line after each what-if output message.

      • Note: The script-block approach limits the output that is mapped to the caller's success stream (via stdout) to direct-to-console output (such as from -WhatIf) and the command's success-stream output. Output to any of the other streams is mapped to the corresponding streams of the caller, though you can use redirections inside the script block to merge streams into the success output stream.
        In the case at hand, the -Verbose output would be passed through to the caller's verbose stream by default and would therefore not be captured in a variable capturing the command output. However, placing 4>&1 inside the script block would include it.
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • I‘ll mark this as the answer although it does not soöve it for me. Still good to know whats possible. Thx! – Alexander Schmidt Dec 05 '21 at 18:40
  • Thanks, @AlexanderSchmidt. In what way does it not solve your problem? – mklement0 Dec 05 '21 at 18:55
  • I want to use it in a powershell module. The problem is that users will not accept the caveats you mention and that I‘m pretty sure that running this under Linux will freak out the system. Its too shaky I think. – Alexander Schmidt Dec 05 '21 at 18:59
  • 1
    @AlexanderSchmidt, the host OS shouldn't make a difference; the call is robust, as long as you know that the command being submitted has all necessary inputs and can auto-load modules it depends on in the new session. When it comes to regular, _non_-`WhatIf` _success_ output, however, you'll lose type fidelity - but you can limit the CLI call to the `-WhatIf` scenario. But, of course, if a CLI call is too expensive, this solution isn't an option. Out of curiosity: how would your module expose this functionality, and why does the module itself need to capture `-WhatIf` output? – mklement0 Dec 05 '21 at 19:09
  • 2
    Thx. I want this for 2 reasons: 1) the user should get at least the same output as withbthe normal command 2) i wanted to parse the output to enable my module to warn on creations and delegions optionally. Maybe i‘ll give it a try. Inwill post my experiences as an answer here. – Alexander Schmidt Dec 05 '21 at 19:29
  • @AlexanderSchmidt Did you already do your experiences? I would be interested in the results. – stackprotector Mar 22 '22 at 11:04