Tag Archives: Begin block

Skip Process and End Blocks

I started to reply to this recent Tweet on Twitter when I stopped and jumped into a new post here instead. It’s been awhile, but I’ve found a Tweet I couldn’t reply to in the allotted characters allowed by Twitter (these days). This isn’t to say I reply to everything. It does say however, that I’m intrigued by the Twitter, posed question. Here’s that Tweet now. Well, mostly. It was deleted at some point after I started this post, so here’s the text that was that Tweet.

“Is there a fast way to return from Function from within Begin {}
without having to go thru Process/End ? #PowerShell”

— (Name and handle removed) October 16, 2018

My first thought here was, why would Process and End take so long to finish that someone wouldn’t want them to execute? In my world, we put as little code into our functions as possible. I’ve said it multiple times already, but I’d rather have five, 20 line functions, before I had one, 100 line script. This makes troubleshooting so much easier. If I can immediately remove 60, or 80, lines in which to deal with, then I’m all for it. Well, I’m not in charge of everyone’s functions and scripts, so I quickly pushed that thought away. This and that fact that there wasn’t a mention of too much code in the Process and End blocks.

Next, I recalled what I’ve done a few times. In some tooling I’ve written in the past, I’ve created a variable that only when True ($true), would it allow the code to fully enter into the Process/End block. Something like the below example, which uses the same variable to determine whether the blocks, other than the Begin block, are executed.

Here’s how this works: The below Limit-BlockUsageOne function chooses a random number — either 1 or 2 — inside the Begin block. If the numeric value is 1, as stored in $RandomNumber, we will enter the Process and End blocks. If it’s 2, we will only enter the two additional blocks long enough to know we won’t run any additional code from inside those two blocks. We can’t completely avoid them, or skip them, but we can get close.

Clear-Host
Function Limit-BlockUsageOne {
    [CmdletBinding()]
    Param (
    )

    Begin {
        $RandomNumber = Get-Random -Minimum 1 -Maximum 3
    } # End Begin
    Process {
        If ($RandomNumber -eq 1) {
            "Inside the Process block."
        } # End If.
    } # End Process.
    End {
        If ($RandomNumber -eq 1) {
            "Inside the End block."
        } # End If.
    } # End End.
 } # End Function: Limit-BlockUsageOne

1..10 | ForEach-Object {
    "-----Execution # $_-----"
    Limit-BlockUsageOne
}

So again, while we do enter the Process and End blocks, we leave almost instantly when the value stored in the $RandomNumber variable is a 2. Here’s some random results, based on the Get-Random cmdlet, which is used inside the Limit-BlockUsageOne function.

-----Execution # 1-----
-----Execution # 2-----
-----Execution # 3-----
-----Execution # 4-----
Inside the Process block.
Inside the End block.
-----Execution # 5-----
Inside the Process block.
Inside the End block.
-----Execution # 6-----
-----Execution # 7-----
-----Execution # 8-----
Inside the Process block.
Inside the End block.
-----Execution # 9-----
Inside the Process block.
Inside the End block.
-----Execution # 10-----
Inside the Process block.
Inside the End block.

Another thought, because there was at least a couple, was to make use of the break command within the Begin block. Part of me wonders if this option is why the Tweet was deleted — did he figured out the answer to his own question? In this next example, we simply exit the function the moment after we write the “Begin” string. Simple.

Function Limit-BlockUsageTwo {
    Begin {
        'Begin.'
        break
    }
    Process {
        'Process'
    }
    End {
        'End.'
    }
} # End Limit-BlockUsageTwo.

The output of the above function is always going to be the string “Begin”. Because of the break command, we’ll never see the string “Process” or “End” output to the screen. Do keep in mind that we can add some logic to determine whether or not the break command is actually  executed. This, much as we did when we checked for the numeric value of 1 and 2 in the previous example. Do note that this option can in fact completely avoid executing any code inside the Process and End blocks. Based on the Tweet, that’s exactly what the user was after.

While I can’t think of an official way to avoid going through Process or End — you know, like something built in — there’s a couple ways to get there and get close, even if it’s not official.

Creating Multiple Credential Objects

Download the complete function: https://gist.github.com/tommymaynard/98031ccd5de67005bf3063db06a33851

There are times when you made need to use additional credentials, other than those used to begin the Windows PowerShell session. When I need to PSRemote to another domain’s computer, I quickly run a function I have stored in my $PROFILE to create a variable that contains a credential object for the second domain. It’s a bit more specific for my environment, so I won’t bother sharing that exact function. What I will do, however, is share and explain a function I’ve written to create up to 10 credential objects. You’ll soon see where that can be changed (if for some reason someone would want more than that many). Realistically, 10 seems much too high anyway. Moving on.

Now, it might be important to know a bit more about how this started. The unfortunate thing about that function (the one in the link) is that it is maxed out at three credential sets (and it continually used the word ‘domain’). As well, it wasn’t as flexible as it should’ve been and it didn’t have any comment-based help or any verbose statements. So, a couple of days after publishing that post, I copied the function back into the PowerShell ISE and started working on a “1.1” version. That’s what we’ll discuss in this post.

First, we’ll write some basic, structural code for the advanced function.

Function New-TMMultiCred {
    [CmdletBinding()]
    Param ()

    Begin {
    } #End Begin

    Process {
    } #End Begin
} #End Function

Now, let’s add the parameter that will define how many credential objects the function will create. The variable we’ll use is $Set and we’ll cast it as an integer (Set will, therefore, also be the name of the parameter). In addition, we’ll add code to define the -Set parameter as being mandatory (it must be included when the function is run), and make the parameter positional (the value for -Set can be entered without providing the -Set parameter name). In addition, we’ll add the ValidateRange validation attribute that will require that the integer entered, as the value for the -Set parameter, must be 1 through 10. This can be changed if necessary.

Function New-TMMultiCred {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$True,Position=0)]
        [ValidateRange(1,10)]
        [int]$Set
    )

    Begin {
    } #End Begin

    Process {
    } #End Begin
} #End Function

We won’t need to do anything in the Begin block, so we’ll focus on the Process block next. In there, we’ll need to prompt for a user name and password as many times as the value of the parameter -Set indicates. Since we know the number of times we’ll be looping (to prompt for the username and password), I recommend we use a for statement. For statements work this way: set a variable ($i in our case) as a counter variable, add a comparison to determine how many times to loop (while $i is less than or equal to $Set), and finally, include a way to increment the counter variable (that’s what $i++ does), so that we only loop the proper number of times.

Function New-TMMultiCred {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$True,Position=0)]
        [ValidateRange(1,10)]
        [int]$Set
    )

    Begin {
    } #End Begin

    Process {
        For ($i = 1; $i -le $Set; $i++) {

        }
    } #End Begin
} #End Function

The final piece is adding the parts necessary to prompt for usernames and passwords, and creating variables to store each of the credential objects. We’ll do this as part of a try-catch.

Line 15 below, first runs the Get-Credential cmdlet. We know this because it is in parenthesis. These parentheses indicate that this cmdlet needs to run before it’s used as the value of the Set-Variable‘s -Value parameter. If for some reason the user presses Cancel, or presses the X in the top-right corner of the prompt dialog, the try portion of the try-catch will fail, and the catch portion will run. It will indicate that no credential was created for that iteration through the loop.

If the user enters, at minimum a username (because a password can be blank), then it will set a variable called $CredSet# (the hash mark (#) indicates a number). If we indicate we want to create two credential objects when we run the function (New-TMMultiCred 2), then $CredSet1 will be the variable that holds the first credential object, and $CredSet2 will hold the second.

Still on line 15, notice that the -Scope parameter is being used with the Set-Variable cmdlet. If we didn’t include this parameter and its value, Global, then the variables created (or modified, if the variable(s) already existed) by this command would not be available after the function was done executing.

Function New-TMMultiCred {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$True,Position=0)]
        [ValidateRange(1,10)]
        [int]$Set
    )

    Begin {
    } #End Begin

    Process {
        For ($i = 1; $i -le $Set; $i++) {
            try {
                Set-Variable -Name CredSet$($i) -Value (Get-Credential -Credential $null) -Scope Global
                Write-Output -Verbose "SUCCESS: Credential Set $i stored in `$CredSet$($i)"
            } catch {
                Write-Warning -Verbose "No credential object was created for set $($i)."
            }
        }
    } #End Begin
} #End Function

Here’s a look at the function in progress. The first image shows that three credential objects were requested. The first credential object has already been created and is stored in $CredSet1, the second wasn’t created, since the user pressed Cancel on the second prompt, and the third credential object will be created when the user presses OK. The second image shows the end result.

Function for Creating Multiple Credential Objects-01

Function for Creating Multiple Credential Objects-02

Once this is complete, the user can run cmdlets that have an optional -Credential parameter and supply the fitting credential object, as seen in the example below. You can return all the cmdlets and functions that have the -Credential parameter using Get-Command: Get-Command -ParameterName Credential.

PS C:\> Invoke-Command -ComputerName dc01 -ScriptBlock {Get-Date} -Credential $CredSet3

Download the complete function: https://gist.github.com/tommymaynard/98031ccd5de67005bf3063db06a33851