|
#Requires -Version 7 |
|
using namespace System.Collections.Generic |
|
using namespace System.Text |
|
using namespace System.Text.Json |
|
using namespace System.Text.Json.Serialization |
|
using namespace System.Linq |
|
|
|
$assembly = Add-type -AssemblyName System.Text.Json -PassThru -ea 'stop' |
|
|
|
<# |
|
This isn't an example of what you should do, it's testing what you can do |
|
|
|
Notes: |
|
- You can call [Text.Json.JsonSerializer]::Serialize |
|
on a pwsh class, using the custom type name. |
|
|
|
- Objects Like [Diagnostics.Process] have many properties |
|
you do not want to serialize like 'Modules'. |
|
Instead of ConvertTo-Json -Depth1, You can apply one of the Json Attributes |
|
|
|
- You can conditionally ignore keys that might emit null values, like: |
|
[JsonIgnoreAttribute( Condition = [JsonIgnoreCondition]::WhenWritingNull ) ] |
|
|
|
#> |
|
|
|
function AutoJson { |
|
<# |
|
.SYNOPSIS |
|
Calls [Text.Json.JsonSerializer] using a pwsh class name |
|
.notes |
|
[System.Text.Json.JsonSerializer] has a ton of overloads |
|
.LINK |
|
https://docs.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializer?view=net-8.0#methods |
|
#> |
|
[CmdletBinding()] |
|
param( |
|
[Parameter(ValueFromPipeline)] |
|
[Alias('InObj')] [object] $Object, |
|
|
|
# Without a type, it falls back to GetType() |
|
[Alias('Tinfo')] [type] $TypeInfo |
|
) |
|
process { |
|
if( -not $TypeInfo ) { $TypeInfo = $Object.GetType() } |
|
[Text.Json.JsonSerializer]::Serialize( <# value: #> $Object, <# tinfo #> $TypeInfo ) |
|
'AutoJson: TryConvert type: {0}' -f $TypeInfo | Write-verbose |
|
} |
|
} |
|
|
|
class SomePS { |
|
[string] $ProcessName |
|
[int] $Id |
|
|
|
# [example kind 1]: Property on instances to include, but, never serialize it |
|
[Serialization.JsonIgnoreAttribute()] |
|
[Diagnostics.ProcessModuleCollection] $Modules |
|
|
|
# [example kind 2]: Serialize property if it's not null, but ignore it if it's null |
|
# note: It does not work here because [object][string]::empty is not null |
|
[JsonIgnoreAttribute( Condition = [JsonIgnoreCondition]::WhenWritingNull ) ] |
|
[object] $MainWindowTitle |
|
|
|
SomePS ( [object]$Other ) { |
|
$WantedProps = [Linq.Enumerable]::Intersect( # because linq is fun |
|
[string[]] $This.PSObject.Properties.Name, |
|
[string[]] $Other.PSObject.Properties.Name ) |
|
|
|
foreach($PropName in $WantedProps) { |
|
$This.$PropName = $Other.$PropName |
|
} |
|
# hard coded version: |
|
# $This.ProcessName = $Other.ProcessName |
|
# $This.Id = $Other.Id |
|
# $this.MainWindowTitle = $Other.MainWindowTitle |
|
# $This.Modules = $Other.Module |
|
} |
|
} |
|
$ps ??= Get-Process |
|
|
|
$hasModules = $ps | ? Modules | Select-Object -First 4 |
|
$hasTitle = $ps | ? MainWindowTitle | Select-Object -first 4 |
|
$noTitle = $ps | ? -Not MainWindowTitle | Select-Object -first 4 |
|
|
|
'Start:' | Write-Host -fore blue |
|
|
|
# [a] works |
|
$hasModules -as [SomePS[]] |
|
<# Out: |
|
ProcessName Id Modules |
|
----------- -- ------- |
|
ApplicationFrameHost 19636 {System.Diagnostics.ProcessModule (ApplicationFrameHost.exe), System.Diagnost .... |
|
#> |
|
|
|
$hasModules -as [SomePS[]] | %{ AutoJson -InObj $_ -TypeInfo ([SomePS]) } |
|
<# Out: |
|
{"ProcessName":"ApplicationFrameHost","Id":19636} |
|
#> |
|
|
|
return |
|
|
|
# cool, typedata is constrained to derived types |
|
{ |
|
$hasModules -as [SomePS[]] | %{ AutoJson -InObj $_ -TypeInfo ([System.Diagnostics.Process]) } |
|
} | Should -Throw -because 'Typedef used did not derive from type' |
|
<# Out: |
|
Exception calling "Serialize" with "2" argument(s): "The specified |
|
type [System.Diagnostics.Process] must derive from the specific value's type [SomePS]." |
|
#> |
|
|
|
$hasTitle -as [SomePs[]] | %{ AutoJson -InObj $_ } |
|
|
|
|
|
$hasModules, $hasTitle, $noTitle -as [SomePs[]] |
|
| AutoJson |
|
|
|
<# Outputs: |
|
{"ProcessName":"ApplicationFrameHost","Id":19636,"MainWindowTitle":"Snip \u0026 Sketch"} |
|
{"ProcessName":"AggregatorHost","Id":9268,"MainWindowTitle":""} |
|
#> |