Behind the PowerShell Pipeline logo

Behind the PowerShell Pipeline

Subscribe
Archives
May 16, 2025

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.

Want to read the full issue?
GitHub Bluesky LinkedIn About Jeff
Powered by Buttondown, the easiest way to start and grow your newsletter.