Your own PowerShell functions can have the same sophisticated parameters, parameter types and parameter sets that you know from cmdlets. However, it is not always obvious how to construct the param() block appropriately.
A clever way is to spy on cmdlets and look how they did it. For example, if you wonder how Get-EventLog made its -LogName parameter mandatory, check out its param() block:
PS> $cmd = Get-Command -commandType cmdlet Get-EventLog PS> [System.Management.Automation.ProxyCommand]::GetParamBlock($cmd) [Parameter(ParameterSetName='LogName', Mandatory=$true, Position=0)] [Alias('LN')] [System.String] ${LogName}, [Alias('Cn')] [ValidateNotNullOrEmpty()] [System.String[]] ${ComputerName}, [Parameter(ParameterSetName='LogName')] [ValidateRange(0, 2147483647)] [System.Int32] ${Newest}, (...)
Not only will you discover that the keyword Mandatory=$true made -LogName mandatory. You also see all the hidden parameter aliases as well as validator attributes. The parameter -Newest for example will only accept a range between 0 and 2147483647, and your own parameters could do the same now, too.