So my default verbose and debug messages might not really be good looking, so I needed to standardize how I wrote them. I wanted the time, function name and message to be printed and standardized. So I came up with this invoke way.

How do I execute a script block from a variable?

Well first we need to save the standard to a variable and then execute it when needed. Well that is easy in powershell.

$command = {Get-Date}
&$command
That command first will save the script block to be run in the $command variable and then using the invoke operator runs it. If you run the later command again you will notice that the Get-Date is executed now to.

Building it from scratch

But we wanted to add the function name too. So lets look into that. I wrote an article before that talked about good constants in Powershell. These aren’t really constants but Powershell variables that powershell itself populates. Tada if you look in $MyInvocation.MyCommand.Name you will find the current functionname. So lets try that on the commandline:

function Test-VirotFunction {
PS C:\> $MyInvocation.MyCommand.Name
PS C:\>
Well I didn’t get any output.. Well I’m not running in a function am I? So lets build a function and then throw it in.

function Test-VirotFunction {
"This used to be my playground $($MyInvocation.MyCommand.Name)"
}
Test-VirotFunction
Okey so that works. But remember that we will do another invoke later and that will get a new $MyInvocation. So lets add a message instead. That feels just like building a function, add a param and a variablename.
PS C:\> $message = {param($string)"You sent: $string"}

PS C:\> &$message 'Hello'
You sent: Hello

A pot hole

Function Test-VirotMessages{
  [CmdletBinding()]
  Param()
  Process
  {
    $DebugMessage = {Param([string]$Message);"$(get-date -Format 's') [$($MyInvocation.MyCommand.Name)]: $Message"}
    Write-Verbose (&$DebugMessage 'Testing Verbose message')
  }
}
Test-VirotMessages -Verbose
Hey.. why did I not get the correct output? Well you did.. In a way. MyInvocation does provide information about the current invocation, but you are invoking the script block right? So how do we get the MyInvocation from the function. We have to dig a little in powershell scoping. I can access the MyInvocation of the function by calling Get-Variable -Scope 1 MyInvocation -ValueOnly. So what is that scope 1? That tells the cmdlet to walk up 1 level in the invocation stack and get the variable there, in this case the calling function.

Now all at once

Function Test-VirotMessages{
  [CmdletBinding()]
  Param()
  Begin
  {
    $DebugMessage = {Param([string]$Message);"$(get-date -Format 's') [$((Get-Variable -Scope 1 MyInvocation -ValueOnly).MyCommand.Name)]: $Message"}
  }
  Process
  {
    Write-Debug (&$DebugMessage 'Test Debug message')
    Write-Verbose (&$DebugMessage 'Testing Verbose message')
  }
}
Test-VirotMessages -Verbose
By using this method I can get verbose and debug messages that are consistent through the entire functions or library of functions since I could declare the script block before the function too. So this might be more complicated than needed for many persons. But what it offers me is the possibility to change layout of my verbose/debugging messages from a single point. If I rename a function I don’t need to alter every Write-Verbose row. And a small picture how it looked: