Add PsTypeName post #14

Merged
OCram85 merged 12 commits from PSType into master 2022-03-17 11:43:18 +01:00
2 changed files with 62 additions and 52 deletions
Showing only changes of commit 26c348c41a - Show all commits

View File

@ -1,10 +1,10 @@
---
title: 'Parameter validation with PSTypeName'
title: 'Parameter Validation with PSTypeName'
date: 2022-03-16T09:24:56+01:00
draft: true
#draft: true
categories: ['PowerShell']
tags: ['parameter validation']
tags: ['parameter', 'validation']
# lastmod: 2022-03-16T09:24:56+01:00
# showDateUpdated: true
@ -19,10 +19,14 @@ tags: ['parameter validation']
# sharingLinks: [null]
---
If you're using `PSCustomObject`s with customized _TypeNames_ you could validate them with additional parameter
attributes.
![ship](ship.jpg 'Photo by [Rod Long](https://unsplash.com/@rodlong) on [Unsplash](https://unsplash.com)')
## 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:
@ -33,7 +37,8 @@ $Rocinante = [PSCustomObject]@{
Class = 'Corvette'
Registry = 'ECF-270'
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
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Class NoteProperty string Class=Corvette
HullNumber NoteProperty string HullNumber=158
Length NoteProperty string Length=46
Owner NoteProperty string Owner=Martian Congressional Republic Navy
Registry NoteProperty string Registry=ECF-270
Type NoteProperty string Type=Light Frigate
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Class NoteProperty string Class=Corvette
HullNumber NoteProperty string HullNumber=158
LengthInMeter NoteProperty int LengthInMeter=46
Name NoteProperty string Name=Rocinante
Owner NoteProperty string Owner=Martian Congressional Republic Navy
Registry NoteProperty string Registry=ECF-270
Type NoteProperty string Type=Light Frigate
> $Rocinante.PSObject.TypeNames
System.Management.Automation.PSCustomObject
@ -79,8 +85,8 @@ function Invoke-Launch {
# Manual input validation for $Ship
# test if all needed properties are present.
$DockLength = '50'
if ($Ship.Length > $DockLength) {
$DockLength = 50
if ($Ship.LengthInMeter -gt $DockLength) {
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
> $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.
## PSTypeName Usage
## 🛡️ PSTypeName Usage
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]@{
# You can use special property 'PSTypeName'
# to set it implicit within the creation.
PSTypeName = 'Rocinante'
PSTypeName = 'Ship.Corvette.LightFrigate'
Owner = 'Martian Congressional Republic Navy'
Type = 'Light Frigate'
Class = 'Corvette'
Registry = 'ECF-270'
HullNumber = '158'
Length = '46'
LengthInMeter = 46
Name = 'Rocinante'
}
# Legacy syntax for injection a custom type name
# $Rocinante.PSObject.TypeNames.insert(0,'Rocinante')
# $Rocinante.PSObject.TypeNames.insert(0,'Ship.Corvette.LightFrigate')
```
```bash
> $Rocinante | Get-Member
TypeName: Rocinante
TypeName: Ship.Corvette.LightFrigate
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Class NoteProperty string Class=Corvette
HullNumber NoteProperty string HullNumber=158
Length NoteProperty string Length=46
Owner NoteProperty string Owner=Martian Congressional Republic Navy
Registry NoteProperty string Registry=ECF-270
Type NoteProperty string Type=Light Frigate
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Class NoteProperty string Class=Corvette
HullNumber NoteProperty string HullNumber=158
LengthInMeter NoteProperty int LengthInMeter=46
Name NoteProperty string Name=Rocinante
Owner NoteProperty string Owner=Martian Congressional Republic Navy
Registry NoteProperty string Registry=ECF-270
Type NoteProperty string Type=Light Frigate
> $Rocinante.PSObject.TypeNames
Rocinante
Ship.Corvette.LightFrigate
System.Management.Automation.PSCustomObject
System.Object
```
@ -156,14 +164,14 @@ function Invoke-Launch {
param (
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[PSTypeName('Rocinante')]$Ship
[PSTypeName('Ship.Corvette.LightFrigate')]$Ship
)
begin {}
process {
$DockLength = '50'
if ($Ship.Length > $DockLength) {
$DockLength = 50
if ($Ship.LengthInMeter -gt $DockLength) {
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
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
function New-LightFrigate {
[CmdletBinding()]
[OutputType('Ship.Corvette.LightFrigate')]
param (
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$Name,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$Registry,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$HullNumber
[string]$HullNumber,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$Name
)
begin {}
process {
$Ship = [PSCustomObject]@{
PSTypeName = $Name
PSTypeName = 'Ship.Corvette.LightFrigate'
Owner = 'Martian Congressional Republic Navy'
Type = 'Light Frigate'
Class = 'Corvette'
Registry = $Registry
HullNumber = $HullNumber
Length = '46'
LengthInMeter = 46
Name = $Name
}
Write-Output $Ship
}
@ -224,5 +234,5 @@ function New-LightFrigate {
end {}
}
$Rocinante = New-LightFrigate -Name 'Rocintante' -Registry 'DE-MB2' -HullNumber '158'
$Rocinante = New-LightFrigate -Name 'Rocinante' -Registry 'DE-MB2' -HullNumber '158'
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB