Begin, process, end…

Few weeks ago I’ve discovered very strange bug in the way ‘process’ works when used in wrong context. Long story short: someone wrote function with process block, but without begin block. It’s usually OK, but he tried to put some code between param and process block and that gave him error, that is misleading at best:

function Test-BadProcess {            
param ()            
            
# begin {            
$SomeVariable = 'Initial Value'            
# }            
            
process {            
    "Will barf on you! Get-Process does not take scripts! ARGH!"            
}            
}

So how it looks like when you run it?

BadProcess

Oops? Get-Process? When did I used that command? It appears that when you use process in other context than it was designed to, it will automagically add ‘Get-‘ verb and surprise you. What is even more surprising – it will do the same with begin and end. But first it has to have something to run so…:

function Get-Begin {            
    "And now for something completely different!"            
}            
            
function Get-End {            
    "This is the end... My only friend, the end..."            
}            
            
$null;begin            
$null;end

But that’s not all, folks. Unless you use something that PowerShell would not like (e.g. keywords that do not change into commands when context changes) or known already as a command (alias, application) you can just type Noun, and Get- will be added for you. How I’ve found out? Trace-Command told me… Puszczam oczko

Get-Foo

The only question that remains open: why process/ begin/ end used in such context follow this rule? And few other keywords too (more on that later).

BTW: in case you want to fix it yourself: my suggestion is to define three functions in your profile:

foreach ($key in 'begin process end'.Split()) {             
    $Function = @{             
        Path = "function:\$key"             
        Value = [scriptblock]::Create(            
            "throw 'Keyword ''$key'' used in wrong context!'"            
        )            
        Force = $true            
    }            
    New-Item @Function | Out-Null            
}            

Any of them should give you errors that are more accurate than what you get by default… You may want to fix also other surprising keywords that change into commands in context, where you might not expect it:

'Begin', 'Break', 'Catch', 'Continue',            
'Data', 'Do', 'Dynamicparam', 'Else',            
'Elseif', 'End', 'Exit', 'Filter',            
'Finally', 'For', 'Foreach', 'From',             
'Function', 'If', 'In', 'Param',             
'Process', 'Return', 'Switch', 'Throw',            
'Trap', 'Try', 'Until', 'While' | ForEach-Object {            
    "$_";"`$null;$_";"} $_"            
} | ForEach-Object {            
    [Management.Automation.PSParser]::Tokenize($_, [ref]$null) |            
    Add-Member -MemberType NoteProperty -Name Line -Value $_ -PassThru            
} | Where-Object { $_.Type -in 'Command', 'Keyword'} |             
    Format-Table Line, Type -AutoSize -GroupBy Content

Here you can see all keywords and how they switch their keyword-ness on and off.

I’m only sad I forgot to mention this to PowerShell Team during Deep Dive and ask why is that so. Smutek Note to self: next time prepare a list of questions before you go to conference like this one, amount of PowerShell goodness my overwhelm you and in the end – you forget what was that you wanted to ask. Puszczam oczko

Advertisement

2 thoughts on “Begin, process, end…

  1. The issue is that a begin , process and end statement must be at the “top” level within a function
    So you can have
    Function name {
    param()
    Begin {}
    Process{}
    End{}
    }

    as soon as you introduce another command these don’t parse as “at the top level” so PowerShell looks for a command named begin, process or end …

  2. You are right James, but IMO you miss whole point of my post… 🙂 It’s NOT about correct syntax, it’s about bad errors and why they happen.
    That’s why my solution is to throw some meaningful errors…
    I’m not trying to fix anything here, just give myself (or anybody else who may walk into this issue) some clue on what is going on. PS Complaining about Get-Process when you do not use it at all in your function is not helpful IMO. 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s