Single Run Functions


Welcome to the 294th post on tommymaynard.com. It’s countdown to 300!


Up until yesterday, this was potentially the longest I’d gone without writing. Here’s what happened. Life. No really, it was a combination of wrapping up my part in The PowerShell Conference Book, which, if I might add, has done really well. Thus far it’s funded two scholarships — that’s impressive!

The other half of this combination, is that I started two posts that I just haven’t gotten back to work on. They’re fairly involved. That, and a few projects at work, have taken it out of me in the last couple weeks. You know the nights; you don’t dare turn on a computer. But, as I was writing what you’re read so far this evening, I did think of something to share.

At times you may find yourself only needing, or wanting, certain functions in a module to be executed once. Say you’re building out a new Active Directory Domain; there’s likely tasks that should only be completed a single time. But, how does one handle that?

There’s a couple different ways I can think of off the top of my head. We’ll assume we’re on Windows, and for this post, we’ll take advantage of the Windows Registry. While we can check to see if the thing(s) the functions set out to change, were actually changed, or potentially execute a Pester test, for this post, we’re going to cheat. This may not be the best idea, but here we are, a touch desperate for some new content.

Let’s say the below function, Show-String, is a part of the StringModule. Its only purpose is to write a string to the PowerShell host program — the screen. While this isn’t something you’d likely only want to run once, it will suffice for this demonstration. The Begin block will create a Registry Key called StringModule inside HKLM:\SOFTWARE if it doesn’t already exist.

If it does exist, it’ll check for a value named after the function. If the value “Show-String” exists and holds the Data value of “Complete,” it will exit the function and indicate to the user that the function cannot be run more than once. If “Show-String” exists and holds a Data value other than “Complete,” it’ll exit the function as well; however, it’ll indicate to the user that this function may have been run before. This is based on the Name being correct, but that the Data value being incorrect. That shouldn’t happen, but, why not make this quick check and verification.

Function Show-String {
    Param (
        [Parameter()]
        [string]$String
    )

    Begin {
        $CmdName = "$($MyInvocation.MyCommand.Name)"
        $RegistryPath = 'HKLM:\SOFTWARE\StringModule'

        If (-Not(Get-Item -Path $RegistryPath -ErrorAction SilentlyContinue)) {
            New-Item -Path $RegistryPath | Out-Null

        } Else {
            If ([System.Boolean](Get-ItemProperty -Path $RegistryPath)) {

                If ((Get-ItemProperty -Path $RegistryPath).$CmdName -eq 'Complete') {
                    Write-Warning -Message "The $CmdName function has already been run (Name and Data verified)."
                    break

                } ElseIf ((Get-ItemProperty -Path $RegistryPath).$CmdName -ne 'Complete') {
                    Write-Warning -Message "The $CmdName function may have already been run (Name correct but Data incorrect)."
                    break

                } # End If-ElseIf.
            } # End If.
        } # End If-Else
    } # End Begin.

    Process {
        $String
    } # End Process.

    End {
        New-ItemProperty -Path $RegistryPath -Name $CmdName -Value 'Complete' | Out-Null
        If (-Not(Get-ItemProperty -Path $RegistryPath).$CmdName) {
            Write-Warning -Message "Unable to correctly set Registry so function isn't run more than once."
            return
        } # End If.
    } # End End.
} # End Function: Show-String.

Below we have three different runs of the above function, one right after the next. In the first run, the string is displayed. Additionally, although we don’t see it ourselves, our Registry Key is created, as is the Show-String value containing the string data of “Complete.” In the second run, we receive a warning that indicates this function has already been run. Again, it’s checking the Registry. It knows this at 100%, because the value contains the “Show-String” Name and string data of “Complete.” Just before the third run, I edited the value in Data, so that it was something other than Complete.

PS C:\> Show-String -String 'testing 123'
testing 123

PS C:\> Show-String -String 'testing 123'
WARNING: The Show-String function has already been run (Name and Data verified).

PS C:\> # Edited the data in the Registry value to something other than "Complete"

PS C:\> Show-String -String 'testing 123'
WARNING: The Show-String function may have already been run (Name correct but Data incorrect).

And in closing, what else do you think this needs? I know. A function that will clean up those Registry entries when you really have a need to rerun your function. I did that for my project, because I know there’s going to be those times during testing.

Finally, I do want to mention that this function is interacting with HKEY_LOCAL_MACHINE. This area of the Registry requires administrative permissions. You may need to alter this code to use HKEY_CURRENT_USER. If you choose to do that, every HKLM in the above script would need to be, you guessed it, changed to HKCU.

Leave a Reply

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