Add PsTypeName post #14
@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
title: 'Parameter validation with PSTypeName'
|
title: 'Parameter Validation with PSTypeName'
|
||||||
date: 2022-03-16T09:24:56+01:00
|
date: 2022-03-16T09:24:56+01:00
|
||||||
draft: true
|
#draft: true
|
||||||
|
|
||||||
categories: ['PowerShell']
|
categories: ['PowerShell']
|
||||||
tags: ['parameter validation']
|
tags: ['parameter', 'validation']
|
||||||
# lastmod: 2022-03-16T09:24:56+01:00
|
# lastmod: 2022-03-16T09:24:56+01:00
|
||||||
# showDateUpdated: true
|
# showDateUpdated: true
|
||||||
|
|
||||||
@ -19,10 +19,14 @@ tags: ['parameter validation']
|
|||||||
# sharingLinks: [null]
|
# sharingLinks: [null]
|
||||||
---
|
---
|
||||||
|
|
||||||
If you're using `PSCustomObject`s with customized _TypeNames_ you could validate them with additional parameter
|
![ship](ship.jpg 'Photo by [Rod Long](https://unsplash.com/@rodlong) on [Unsplash](https://unsplash.com)')
|
||||||
attributes.
|
|
||||||
|
|
||||||
## Well-Known Workflow
|
## 🖼️ Intro
|
||||||
|
|
||||||
|
`PSCustomObject`s with customized _TypeNames_ can be validated with the parameter
|
||||||
|
attribute `[PSTypeName()]`.
|
||||||
|
|
||||||
|
## 🗑️ Well-Known Workflow
|
||||||
|
|
||||||
So let's start with a common object definition how it is used with a function:
|
So let's start with a common object definition how it is used with a function:
|
||||||
|
|
||||||
@ -33,7 +37,8 @@ $Rocinante = [PSCustomObject]@{
|
|||||||
Class = 'Corvette'
|
Class = 'Corvette'
|
||||||
Registry = 'ECF-270'
|
Registry = 'ECF-270'
|
||||||
HullNumber = '158'
|
HullNumber = '158'
|
||||||
Length = '46'
|
LengthInMeter = 46
|
||||||
|
Name = 'Rocinante'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -44,18 +49,19 @@ As you can see, a `PSCustomObject` has still the the same class type and just di
|
|||||||
|
|
||||||
TypeName: System.Management.Automation.PSCustomObject
|
TypeName: System.Management.Automation.PSCustomObject
|
||||||
|
|
||||||
Name MemberType Definition
|
Name MemberType Definition
|
||||||
---- ---------- ----------
|
---- ---------- ----------
|
||||||
Equals Method bool Equals(System.Object obj)
|
Equals Method bool Equals(System.Object obj)
|
||||||
GetHashCode Method int GetHashCode()
|
GetHashCode Method int GetHashCode()
|
||||||
GetType Method type GetType()
|
GetType Method type GetType()
|
||||||
ToString Method string ToString()
|
ToString Method string ToString()
|
||||||
Class NoteProperty string Class=Corvette
|
Class NoteProperty string Class=Corvette
|
||||||
HullNumber NoteProperty string HullNumber=158
|
HullNumber NoteProperty string HullNumber=158
|
||||||
Length NoteProperty string Length=46
|
LengthInMeter NoteProperty int LengthInMeter=46
|
||||||
Owner NoteProperty string Owner=Martian Congressional Republic Navy
|
Name NoteProperty string Name=Rocinante
|
||||||
Registry NoteProperty string Registry=ECF-270
|
Owner NoteProperty string Owner=Martian Congressional Republic Navy
|
||||||
Type NoteProperty string Type=Light Frigate
|
Registry NoteProperty string Registry=ECF-270
|
||||||
|
Type NoteProperty string Type=Light Frigate
|
||||||
|
|
||||||
> $Rocinante.PSObject.TypeNames
|
> $Rocinante.PSObject.TypeNames
|
||||||
System.Management.Automation.PSCustomObject
|
System.Management.Automation.PSCustomObject
|
||||||
@ -79,8 +85,8 @@ function Invoke-Launch {
|
|||||||
# Manual input validation for $Ship
|
# Manual input validation for $Ship
|
||||||
# test if all needed properties are present.
|
# test if all needed properties are present.
|
||||||
|
|
||||||
$DockLength = '50'
|
$DockLength = 50
|
||||||
if ($Ship.Length > $DockLength) {
|
if ($Ship.LengthInMeter -gt $DockLength) {
|
||||||
Write-Error -Message "Ship doesn't fit in the docking station." -ErrorAction 'Stop'
|
Write-Error -Message "Ship doesn't fit in the docking station." -ErrorAction 'Stop'
|
||||||
}
|
}
|
||||||
# ...
|
# ...
|
||||||
@ -91,7 +97,7 @@ function Invoke-Launch {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This common pattern could fail whenever someone changes your object properties. If the _Length_ property is missing you ran into an error. E.g.:
|
This common pattern could fail whenever someone changes your object properties. If the _LengthInMeter_ property is missing you ran into an error. E.g.:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
> $Rocinante = [PSCustomObject]@{ foo = 'bar' }
|
> $Rocinante = [PSCustomObject]@{ foo = 'bar' }
|
||||||
@ -104,7 +110,7 @@ Keep in mind - Because we are using here custom objects and not class instances,
|
|||||||
|
|
||||||
To fix this we can use the `[PSTypeName()]` parameter attribute, to ensure an object with the correct type name is used. This doesn't verify your parameters but minimize the risk for using invalid parameter objects.
|
To fix this we can use the `[PSTypeName()]` parameter attribute, to ensure an object with the correct type name is used. This doesn't verify your parameters but minimize the risk for using invalid parameter objects.
|
||||||
|
|
||||||
## PSTypeName Usage
|
## 🛡️ PSTypeName Usage
|
||||||
|
|
||||||
Let's first modify the object creation and use a custom type name.
|
Let's first modify the object creation and use a custom type name.
|
||||||
|
|
||||||
@ -112,38 +118,40 @@ Let's first modify the object creation and use a custom type name.
|
|||||||
$Rocinante = [PSCustomObject]@{
|
$Rocinante = [PSCustomObject]@{
|
||||||
# You can use special property 'PSTypeName'
|
# You can use special property 'PSTypeName'
|
||||||
# to set it implicit within the creation.
|
# to set it implicit within the creation.
|
||||||
PSTypeName = 'Rocinante'
|
PSTypeName = 'Ship.Corvette.LightFrigate'
|
||||||
Owner = 'Martian Congressional Republic Navy'
|
Owner = 'Martian Congressional Republic Navy'
|
||||||
Type = 'Light Frigate'
|
Type = 'Light Frigate'
|
||||||
Class = 'Corvette'
|
Class = 'Corvette'
|
||||||
Registry = 'ECF-270'
|
Registry = 'ECF-270'
|
||||||
HullNumber = '158'
|
HullNumber = '158'
|
||||||
Length = '46'
|
LengthInMeter = 46
|
||||||
|
Name = 'Rocinante'
|
||||||
}
|
}
|
||||||
# Legacy syntax for injection a custom type name
|
# Legacy syntax for injection a custom type name
|
||||||
# $Rocinante.PSObject.TypeNames.insert(0,'Rocinante')
|
# $Rocinante.PSObject.TypeNames.insert(0,'Ship.Corvette.LightFrigate')
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
> $Rocinante | Get-Member
|
> $Rocinante | Get-Member
|
||||||
|
|
||||||
TypeName: Rocinante
|
TypeName: Ship.Corvette.LightFrigate
|
||||||
|
|
||||||
Name MemberType Definition
|
Name MemberType Definition
|
||||||
---- ---------- ----------
|
---- ---------- ----------
|
||||||
Equals Method bool Equals(System.Object obj)
|
Equals Method bool Equals(System.Object obj)
|
||||||
GetHashCode Method int GetHashCode()
|
GetHashCode Method int GetHashCode()
|
||||||
GetType Method type GetType()
|
GetType Method type GetType()
|
||||||
ToString Method string ToString()
|
ToString Method string ToString()
|
||||||
Class NoteProperty string Class=Corvette
|
Class NoteProperty string Class=Corvette
|
||||||
HullNumber NoteProperty string HullNumber=158
|
HullNumber NoteProperty string HullNumber=158
|
||||||
Length NoteProperty string Length=46
|
LengthInMeter NoteProperty int LengthInMeter=46
|
||||||
Owner NoteProperty string Owner=Martian Congressional Republic Navy
|
Name NoteProperty string Name=Rocinante
|
||||||
Registry NoteProperty string Registry=ECF-270
|
Owner NoteProperty string Owner=Martian Congressional Republic Navy
|
||||||
Type NoteProperty string Type=Light Frigate
|
Registry NoteProperty string Registry=ECF-270
|
||||||
|
Type NoteProperty string Type=Light Frigate
|
||||||
|
|
||||||
> $Rocinante.PSObject.TypeNames
|
> $Rocinante.PSObject.TypeNames
|
||||||
Rocinante
|
Ship.Corvette.LightFrigate
|
||||||
System.Management.Automation.PSCustomObject
|
System.Management.Automation.PSCustomObject
|
||||||
System.Object
|
System.Object
|
||||||
```
|
```
|
||||||
@ -156,14 +164,14 @@ function Invoke-Launch {
|
|||||||
param (
|
param (
|
||||||
[Parameter(Mandatory = $true)]
|
[Parameter(Mandatory = $true)]
|
||||||
[ValidateNotNullOrEmpty()]
|
[ValidateNotNullOrEmpty()]
|
||||||
[PSTypeName('Rocinante')]$Ship
|
[PSTypeName('Ship.Corvette.LightFrigate')]$Ship
|
||||||
)
|
)
|
||||||
|
|
||||||
begin {}
|
begin {}
|
||||||
|
|
||||||
process {
|
process {
|
||||||
$DockLength = '50'
|
$DockLength = 50
|
||||||
if ($Ship.Length > $DockLength) {
|
if ($Ship.LengthInMeter -gt $DockLength) {
|
||||||
Write-Error -Message "Ship doesn't fit in the docking station." -ErrorAction 'Stop'
|
Write-Error -Message "Ship doesn't fit in the docking station." -ErrorAction 'Stop'
|
||||||
}
|
}
|
||||||
# ...
|
# ...
|
||||||
@ -174,7 +182,7 @@ function Invoke-Launch {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Final Thoughts
|
## 💭 Final Thoughts
|
||||||
|
|
||||||
Over time, your PowerShell functions become more and more complex. You will reach a point where you start using
|
Over time, your PowerShell functions become more and more complex. You will reach a point where you start using
|
||||||
objects as parameters. This is where the PSTypeName parameter attribute shown can help you.
|
objects as parameters. This is where the PSTypeName parameter attribute shown can help you.
|
||||||
@ -192,31 +200,33 @@ You should consider creating a your objects within a wrapper function to mimic a
|
|||||||
```powershell
|
```powershell
|
||||||
function New-LightFrigate {
|
function New-LightFrigate {
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
|
[OutputType('Ship.Corvette.LightFrigate')]
|
||||||
param (
|
param (
|
||||||
[Parameter(Mandatory = $true)]
|
|
||||||
[ValidateNotNullOrEmpty()]
|
|
||||||
[string]$Name,
|
|
||||||
|
|
||||||
[Parameter(Mandatory = $true)]
|
[Parameter(Mandatory = $true)]
|
||||||
[ValidateNotNullOrEmpty()]
|
[ValidateNotNullOrEmpty()]
|
||||||
[string]$Registry,
|
[string]$Registry,
|
||||||
|
|
||||||
[Parameter(Mandatory = $true)]
|
[Parameter(Mandatory = $true)]
|
||||||
[ValidateNotNullOrEmpty()]
|
[ValidateNotNullOrEmpty()]
|
||||||
[string]$HullNumber
|
[string]$HullNumber,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[ValidateNotNullOrEmpty()]
|
||||||
|
[string]$Name
|
||||||
)
|
)
|
||||||
|
|
||||||
begin {}
|
begin {}
|
||||||
|
|
||||||
process {
|
process {
|
||||||
$Ship = [PSCustomObject]@{
|
$Ship = [PSCustomObject]@{
|
||||||
PSTypeName = $Name
|
PSTypeName = 'Ship.Corvette.LightFrigate'
|
||||||
Owner = 'Martian Congressional Republic Navy'
|
Owner = 'Martian Congressional Republic Navy'
|
||||||
Type = 'Light Frigate'
|
Type = 'Light Frigate'
|
||||||
Class = 'Corvette'
|
Class = 'Corvette'
|
||||||
Registry = $Registry
|
Registry = $Registry
|
||||||
HullNumber = $HullNumber
|
HullNumber = $HullNumber
|
||||||
Length = '46'
|
LengthInMeter = 46
|
||||||
|
Name = $Name
|
||||||
}
|
}
|
||||||
Write-Output $Ship
|
Write-Output $Ship
|
||||||
}
|
}
|
||||||
@ -224,5 +234,5 @@ function New-LightFrigate {
|
|||||||
end {}
|
end {}
|
||||||
}
|
}
|
||||||
|
|
||||||
$Rocinante = New-LightFrigate -Name 'Rocintante' -Registry 'DE-MB2' -HullNumber '158'
|
$Rocinante = New-LightFrigate -Name 'Rocinante' -Registry 'DE-MB2' -HullNumber '158'
|
||||||
```
|
```
|
||||||
|
BIN
content/posts/pstypename/ship.jpg
Normal file
BIN
content/posts/pstypename/ship.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
Loading…
Reference in New Issue
Block a user