A Function for my Functions

I’m in the process of working on a new advanced function template for work. It’ll be the 2.0 version of this: http://tommymaynard.com/function-logging-via-write-verbose-2016. The problem I have with the current version of the template is that I could never only log to a file, without writing to the host program, too. In the end, I want a way to do one of four different things when I run a function written using the template. They are (1) not log anything, (2) log to the screen only, (3) log to a file only (this is the addition I’m after), or (4) log to both the screen and a file simultaneously. This is nearing completion, but one of the downsides to a well thought out and robust advanced function template is that it’s getting, really long. I honestly believe I’m at over 100 lines now (the 1.x versions are in the 70ish line territory).

So, I’m sitting around and thinking of a way to disguise the template, or add my code to it when it’s done, and so I wrote the following pieces of PowerShell. No saying that I’ll ever use this, but it seemed worthy enough to share here. I’m out to automatically add my code to the template, so I don’t have to code around the template’s standard code that allows for the logging.

This first example begins the process of creating a new function named New-FunctionFromTemplate. It’s set to accept three parameters: Begin, Process, and End. For those writing advanced functions, this should be easily recognizable as to why. It’s going to stuff whatever values are supplied to these parameters into these respective sections in the function template, that it displays when it’s done executing. You write the code, and it’ll place that codeĀ into the function template, via the New-FunctionFromTemplate function.

Function New-FunctionFromTemplate {
    Param(
        [string]$Begin,
        [string]$Process,
        [string]$End
    )
...
}

Next, I’ve included the remainder of this function. It’s a here-string that includes the function template design and layout, with a place for each variable within it. These variables will be replaced with whatever we send into the New-FunctionFromTemplate function when it’s invoked.

Function New-FunctionFromTemplate {
    Param(
        [string]$Begin,
        [string]$Process,
        [string]$End
    )   

    @"
Function ___-________ {
    [CmdletBinding()]
    Param (
    )

    Begin {
        $Begin
    } # End Begin.

    Process {
        $Process
    } # End Process.

    End {
        $End
    } # End End.
} # End Function: ___-________.
"@
}

Now that we’ve defined our function, let’s use it. As a bit of a shortcut, and as a way to make things a bit more readable, we’ll create a parameter hash table and splat it to the New-FunctionFromTemplate function. The below example could’ve been written as New-FunctionFromTemplate -Begin ‘This is in the Begin block.’ -Process ‘This is in the Process block.’ … etc., but I’m opted to not to that, to make things a bit easier to read and comprehend.

$Params1 = @{
    Begin = 'This is in the Begin block.'
    Process = 'This is in the Process block.'
    End = 'This is in the End block.'
}
New-FunctionFromTemplate @Params1

Below is the output the above commands create.

Function ___-________ {
    [CmdletBinding()]
    Param (
    )

    Begin {
        This is in the Begin block.
    } # End Begin.

    Process {
        This is in the Process block.
    } # End Process.

    End {
        This is in the End block.
    } # End End.
} # End Function ___-________.

This thing is, someone’s not typically only going to add a single string — a single sentence, if you will — inside a Begin, Process, or End block. They’re much more likely to add various language constructs and logic, and comments. Here’s a second example to help show how we would go about adding more than just a single string, using a here-string for two of the three blocks.

$Params2 = @{
    Begin = @'
If ($true) {
            'It is true.'
        } Else {
            'It is false.'
        }
'@
    Process = @'
'This is in the Process block.'
'@
    End = @'
If ($false) {
            'It is true.'
        } Else {
            'It is false.'
        }
'@
}
New-FunctionFromTemplate @Params2

When the above code is run, it produces the below output. It includes both our template structure, as well as, the code we want inside each of the blocks. In case you didn’t catch it right away, there’s a bit of a caveat. The first line is right up against the left margin. Even though, it’ll drop everything into it’s proper place — a single tab to the right of the beginning of each block. After that first line, you have to be the one to monitor your code placement, so that when it’s combined with the template, all the indentations line as expected.

Function ___-________ {
    [CmdletBinding()]
    Param (
    )

    Begin {
        If ($true) {
            'It is true.'
        } Else {
            'It is false.'
        }
    } # End Begin.

    Process {
        'This is in the Process block.'
    } # End Process.

    End {
        If ($false) {
            'It is true.'
        } Else {
            'It is false.'
        }
    } # End End.
} # End Function: ___-________.

And, that’s it. While I put this together, I’ve yet to implement it and truly code separately from my current template. We’ll see what the future holds for me, but at least I know I have this option, if I decide it’s really time to use it. Enjoy your Thursday!

Leave a Reply

Your email address will not be published. Required fields are marked *