More PowerShell Parameter Validations
Let's continue our exploration of lesser known PowerShell parameter and validation attributes. I trust most of you are familiar with [ValidateSet()]
, [ValidateRange()]
, and [ValidatePattern()]
. I always to try to use parameter validation to ensure parameter values are correct and increase the likelihood of successful execution.
However, before we jump into the main topic, I have another parameter attribute that I want to make sure you know about. This attribute will be especially useful with your commands that utilize custom objects.
PSTypeName Attribute
Here's a demonstration function that creates a custom object and writes it to the pipeline.
Function Get-TestSample {
[CmdletBinding()]
[OutputType('psTestSample')]
Param([string]$Name = $env:USERNAME)
[PSCustomObject]@{
PSTypeName = 'psTestSample'
Name = $Name
ProcessCount = (Get-Process).Count
Comment = 'This is a test sample'
PSVersion = $PSVersionTable.PSVersion
}
}
Using it is simple enough.
PS C:\> Get-TestSample | Tee -Variable s
Name ProcessCount Comment PSVersion
---- ------------ ------- ---------
Jeff 369 This is a test sample 7.5.1
And I can verify the type name of the object.
PS C:\> $s | Get-Member
TypeName: psTestSample
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Comment NoteProperty string Comment=This is a test sample
Name NoteProperty string Name=Jeff
ProcessCount NoteProperty int ProcessCount=369
PSVersion NoteProperty semver PSVersion=7.5.1
This function might be part of a module with a corresponding Set
command. Following the PowerShell module you would expect to pipe the output of Get-TestSample
to Set-TestSample
.
Function Set-TestSample {
[cmdletbinding()]
[OutputType('psTestSample')]
Param(
[Parameter(Position = 0, Mandatory,ValueFromPipeline)]
[psTestSample]$TestSample,
[string]$Name,
[string]$Comment
)
Process {
if ($Name) {
$TestSample.Name = $Name
}
If ($Comment) {
$TestSample.Comment = $Comment
}
$TestSample.ProcessCount = (Get-Process).Count
$TestSample.PSVersion = $PSVersionTable.PSVersion
$TestSample
}
}
You want to ensure that the object is a psTestSample
object so that your code will run. But there is a problem with this command.
PS C:\> Help Set-TestSample
Get-Help:
Line |
64 | $help = Get-Help @PSBoundParameters
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Unable to find type [psTestSample].
PS C:\> $s | Set-TestSample -name Foo -Comment "Updated"
InvalidOperation:
Line |
6 | [psTestSample]$TestSample,
| ~~~~~~~~~~~~~~
| Unable to find type [psTestSample].
PowerShell doesn't know anything about your custom type. You could write your own validation code in the function, but that's a lot of work. Instead, you can use the PSTypeName
attribute to tell PowerShell about your custom type.
Function Set-TestSample {
[cmdletbinding()]
[OutputType('psTestSample')]
Param(
[Parameter(Position = 0, Mandatory,ValueFromPipeline)]
[PSTypeNameAttribute('psTestSample')]
[PSObject]$TestSample,
[string]$Name,
[string]$Comment
)
Process {
if ($Name) {
$TestSample.Name = $Name
}
If ($Comment) {
$TestSample.Comment = $Comment
}
$TestSample.ProcessCount = (Get-Process).Count
$TestSample.PSVersion = $PSVersionTable.PSVersion
$TestSample
}
}
Set the parameter type to PSObject
and add the PSTypeNameAttribute
attribute. Now PowerShell knows about your custom type.