Skip to content

Instantly share code, notes, and snippets.

@markwragg
Created May 17, 2017 14:08
Show Gist options
  • Save markwragg/287c4cea8e0d497652b890dc9d6f4004 to your computer and use it in GitHub Desktop.
Save markwragg/287c4cea8e0d497652b890dc9d6f4004 to your computer and use it in GitHub Desktop.
PowerShell function to create a Class Definition from an existing object. Forked from Brian Scholer (https://github.com/briantist).
function New-ClassDefinitionFromObject {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[object]$InputObject,
[Parameter()]
[String]$Name = 'Root',
[SupportsWildcards()]
[String[]]$EnumType
)
End {
function helper {
[CmdletBinding()]
param(
[Parameter(Mandatory,ValueFromPipeline)]
[object]$InputObject,
[ValidateRange(1,99)] # ConvertFrom-Json supports depth up to 99
[uint16]$Depth = 1,
[ValidateNotNullOrEmpty()]
[String]$ParentKey = $Name,
[Parameter(Mandatory)]
[hashtable]$DataData,
[SupportsWildcards()]
[String[]]$EnumType
)
Process {
$InputObject.PSObject.Properties.ForEach({
$prop = $_
$propData = @{
Name = "{$($prop.Name)}"
Type = @()
IsObject = $prop.Value -is [PSObject]
IsArray = $prop.Value -is [Array]
IsEnum = $EnumType -and $prop.Name -ilike $EnumType
Depth = $Depth
ParentKey = $ParentKey
}
if ($propData.IsArray) {
$prop.Value | helper -Depth ($Depth+1) -DataData $DataData -EnumType $EnumType -ParentKey $propData.Name
if ($DataData.classes.ParentKey -contains $propData.Name) {
$propData.IsObject = $true
}
}
$propData.Type += $prop.TypeNameOfValue
if (
$prop.IsEnum -and (
$prop.Value -isnot [String] -or
$prop.Value -notmatch '^[a-zA-Z][a-zA-Z0-9_]*$'
)
) {
throw [System.InvalidOperationException]"The property '$($propData.Name)' cannot be an enum because one its values is not valid for an enum."
}
if ($propData.IsObject) {
$prop.Value | helper -Depth ($Depth+1) -DataData $DataData -EnumType $EnumType -ParentKey $propData.Name
}
if ($propData.IsEnum) {
if ($DataData.enums.ContainsKey($propData.Name)) {
if ($DataData.enums[$propData.Name] -notcontains $prop.Value) {
$DataData.enums[$propData.Name] += $prop.Value
}
} else {
$DataData.enums[$propData.Name] = @($prop.Value)
}
}
if ($DataData.classes.Where({$_.Name -eq $propData.Name -and $_.ParentKey -eq $propData.ParentKey})) {
return # Naively skip it (for now?)
}
$DataData.classes += [PSCustomObject]$propData
})
}
}
$NL = [System.Environment]::NewLine
$data = @{
classes = @()
enums = @{}
}
helper -InputObject $InputObject -DataData $data -EnumType $EnumType
$data.classes += [PSCustomObject]@{
Name = $Name
Depth = 0
IsObject = $true
}
$defs = @{
classes = @()
enums = @()
}
$data.classes | Sort-Object -Property Depth -Descending | ForEach-Object -Process {
$class = $_
if ($class.IsEnum) {
$defs.enums += "enum $($class.Name)$NL{$NL`t$($data.enums[$class.Name] -join ';')$NL}$NL"
}
if ($class.IsObject) {
$params = $data.classes.Where({$_.ParentKey -eq $class.Name}).ForEach({
$type = if ($_.IsEnum -or $_.IsObject) {
$_.Name
} else {
$_.Type[0]
}
if ($_.IsArray) {
$type = "$type[]"
}
$type = "[$type]"
$label = $_.Name
"`t$type`$$label"
}) -join $NL
$defs.classes += "class $($class.Name)$NL{$NL$params$NL}$NL"
}
}
"$($defs.enums -join $NL)$NL$($defs.classes -join $NL)"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment