Creating Functions from Syntax

Start your PowerShell function with a syntax, then have ISESteroids turn your syntax into a function!

Start with some code

Whether you are working on an existing script and suddenly realize you better wrap a part of it into a separate function, or whether you want to create a new function from scratch: define its syntax first, and leave the implementation to ISESteroids.

Use a Formal Syntax

Here is a sample syntax that follows the same rules you see in PowerShell Help for any function or cmdlet:

Connect-Server [-ComputerName] <string> [-Credential <PSCredential>]

It starts with the command name. Then, you define one or more parameters:

  • First specify the parameter name: don’t forget to start it with a “-“, for example -ComputerName.

  • Add the desired type in angle brackets, for example <string> or <int>.

  • Use brackets to enclose optional parts.

In the example syntax above, the user can omit the parameter -ComputerName but must specify a string value. The parameter -Credential is completely optional, but if the user specifies it, both the parameter name and the credential need to be specified.

Use a Ad-Hoc Syntax

You can also pretend your command already exists, and compose a sample call:

Connect-Server -ComputerName "cl-03" -Credential (Get-Credential)

ISESteroids tries and figures out the appropriate parameter data type from your values.

Converting Syntax to Function

To turn your syntax into a function, select it in the editor pane of ISESteroids. Right-click the selection, and choose Selection/Convert Syntax to Function in the context menu.

If the command Convert Syntax to Function is unavailable in the Selection context menu, please check that you have selected the entire syntax, and that the syntax is formally correct. The command only appears when the selected code is a valid syntax.

ISESteroids analyzes your syntax and derives a new function definition from it who’s syntax exactly matches your requested syntax. The new function opens in a new editor tab.

Converting Formal Syntax

When you convert the formal syntax from above, the result looks like this:

function Connect-Server
{
  [CmdletBinding()]
  param
  (
    [Parameter(Position=0, Mandatory=$true)]
    [string]
    $ComputerName,
    
    [Parameter(Mandatory=$false)]
    [pscredential]
    [System.Management.Automation.Credential()]
    $Credential
  )
  
  
  # TODO: place your function code here
  # this code gets executed when the function is called
  # and all parameters have been processed
  
  
}

All you need to do now is replace the TODO comment with some meaningful code.

The wizard has correctly applied Parameter attributes to your parameters. It added a Conversion attribute [System.Management.Automation.Credential()] to the parameter of type PSCredential to string input is automatically converted into a PSCredential, so your new function is ready to go. Press F5 to run it!

Verifying Syntax in PowerShell Help

Once you run your new function at least once via F5, place the cursor on the function name Connect-Server (do not select anything) and press F1. PowerShell Help opens and shows exactly the syntax you started with:

Synopsis
    
    Connect-Server [-ComputerName] <string> [-Credential <pscredential>] [<CommonParameters>]
    

Parameters
    -ComputerName <string>

        Required?                    true
        Position?                    0
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  

    -Credential <pscredential>

        Required?                    false
        Position?                    Named
        Default value                
        Accept pipeline input?       false
        Accept wildcard characters?  



Syntax
    Connect-Server [-ComputerName] <string> [-Credential <pscredential>] [<CommonParameters>]

Converting Ad-Hoc Syntax

When you convert your ad-hoc syntax from above, the result is slightly different and needs fine-tuning:

function Connect-Server
{
  [CmdletBinding()]
  param
  (
    [Parameter(ParameterSetName='ParameterSet1', Mandatory=$true)]
    [ValidateSet("cl-03")]
    [string]
    $ComputerName,
    
    [Parameter(ParameterSetName='ParameterSet1', Mandatory=$true)]
    [object]
    $Credential
  )
  
  
  # TODO: place your function code here
  # this code gets executed when the function is called
  # and all parameters have been processed
  
  
}

Since ISESteroids was forced to determine the actual parameter type from what you assigned to them, these are the results:

  • The parameter -ComputerName is correctly identified as [string] type. It also received a ValidateSet attribute to allow only the string “cl-03” that you assigned to this parameter in the syntax. Most likely, that’s too strict of a limitation, so either you want to remove the ValidateSet attribute altogether and allow all string types, or add more choices to the ValidateSet attribute as a comma-separated list of individually quoted strings.
  • The parameter -Credential couldn’t be automatically typed, so the wizard fell back to the type [object] which can be anything. You may want to replace [object] by a more specific type manually.

Working With Multiple ParameterSets

ISESteroids supports multiple ParameterSets so the wizard can create very sophisticated parameter blocks for you. Let’s try this syntax:

Connect-Server [[-ComputerName] <string>]
Connect-Server [-ComputerName] <string> -Credential <PSCredential>

This syntax defines two ParameterSets, and depending on which parameters a user specified, PowerShell picks one of the two command signatures. So a user can now call the function in a variety of ways:

  • Call Connect-Server without parameters (i.e. to connect to the local server)
  • Call Connect-Server just with -ComputerName (i.e. to authenticate as self)
  • Call Connect-Server with both -ComputerName and -Credential (i.e. to authenticate as someone else)

The PowerShell Parameter Binder is smart enough to enforce all this, so if a user just specifies -Credential and forgets to specify -ComputerName, PowerShell makes -ComputerName mandatory and prompts the user.

Have a try, and select both lines of the syntax. Next, right-click the selection, and choose Selection/Convert Syntax to Function again. ISESteroids generates this code for you:

function Connect-Server
{
  [CmdletBinding(DefaultParameterSetName='ParameterSet1')]
  param
  (
    [Parameter(ParameterSetName='ParameterSet1', Position=0, Mandatory=$false)]
    [Parameter(ParameterSetName='ParameterSet2', Position=0, Mandatory=$true)]
    [string]
    $ComputerName,
    
    [Parameter(ParameterSetName='ParameterSet2', Mandatory=$true)]
    [pscredential]
    [System.Management.Automation.Credential()]
    $Credential
  )
  
  
  # TODO: place your function code here
  # this code gets executed when the function is called
  # and all parameters have been processed
  $chosenParameterSet = $PSCmdlet.ParameterSetName
  switch($chosenParameterSet)
  {
    'ParameterSet1'    { 'User has chosen ParameterSet1' } 
    'ParameterSet2'    { 'User has chosen ParameterSet2' } 
  }
  
  
  
}

You can see how ISESteroids assigned the parameters to different ParameterSets. The parameter -ComputerName can be optional or mandatory, based on whether the user also specified -Credential. All the validation comes for free and requires no extra coding on your end.

$PSCmdlet: Infos about Selected ParameterSet

In the bottom part of the generated code, a switch statement is inserted that evaluates the selected ParameterSet returned by the automatic variable $PSCmdlet.

By default, the wizard calls each ParameterSet “ParameterSetX” where “X” is an incrementing number. To assign more meaningful names to your ParameterSets, do this next:

  1. Inside the switch block, place the cursor on the string ‘ParameterSet1’ but do not select anything.
  2. Press F2 to rename the string. ISESteroids automatically selects all other instances, and when you assign a new name to the ParameterSet, it is applied to the appropriate parameter as well.
  3. Do the same for the other ParameterSet. Your function body is done. Press F5 to run it.
  4. Call your function body in PowerShell. If you specify nothing, PowerShell returns the name of ParameterSet1.
  5. If you specify -Credential, you are automatically prompted for -ComputerName as well, and PowerShell returns the name of ParameterSet2.

Now you just need to replace the TODO comment inside your function. Here is an example of a fully functional new command that returns information about the operating system locally and remotely:

function Get-OSInfo
{
  [CmdletBinding(DefaultParameterSetName='withoutCredential')]
  param
  (
    [Parameter(ParameterSetName='withoutCredential', Position=0, Mandatory=$false)]
    [Parameter(ParameterSetName='withCredential', Position=0, Mandatory=$true)]
    [string]
    $ComputerName,
    
    [Parameter(ParameterSetName='withCredential', Mandatory=$true)]
    [pscredential]
    [System.Management.Automation.Credential()]
    $Credential
  )
  
  
  Get-CimInstance -ClassName Win32_OperatingSystem @PSBoundParameters
}

Get-OSInfo - Automatic Parameter Validation…

The new function Get-OSInfo makes sure the user is forced to enter all required information:

  • If no parameters are specified, the local computer is queried
  • If -ComputerName is specified, the remote computer is queried, and the user is transparently logged on
  • If -ComputerName and -Credential are specified, the user is logged on with the submitted credential
  • If just -Credential is specified, the user is forced to also enter -ComputerName because new logons are allowed by the Windows operating system generally only when connecting to a remote computer.

…and Splatting

The actual work is then performed by Get-CimInstance. The parameters submitted by the user are automatically forwarded to Get-CimInstance using splatting and @PSBoundParameters.