0
Follow
5
View

Dynamically Build JSON - PowerShell

cyj4229115 注册会员
2023-01-26 11:47

You may check to see which parameters were not used by comparing the bound parameters against all available parameters for your command and then use this to remove the different elements from your hash table.

function New-DynamicJson {
    Param(
        [Parameter(Mandatory = $true)]
        $TaskID,
        $Comment,
        $Status,
        $Owner
    )

    $baseTask = @{
        task = [ordered]@{
            Id      = $TaskID;
            comment = $Comment;
            status  = @{
                name = $Status;
            }
            owner   = @{
                name = $Owner;
            }
        }
    }

    $commonParams = 'Verbose', 'Debug', 'ErrorAction', 'WarningAction', 'InformationAction', 'ErrorVariable',
                    'WarningVariable', 'InformationVariable', 'OutVariable', 'OutBuffer', 'PipelineVariable'


    $MyInvocation.MyCommand.Parameters.Keys.Where({ $_ -notin $commonParams }) |
        Where-Object { $_ -notin $PSBoundParameters.Keys } |
            ForEach-Object { $baseTask.task.Remove($_) }

    $baseTask | ConvertTo-Json
}

Output

PS> New-DynamicJson -TaskID 103 -Comment 'some comment'

{
    "task":  {
                 "Id":  103,
                 "comment":  "some comment"
             }
}

(Thank you mklement0 for the suggestion to use $MyInvocation instead of $PSCmdlet.MyInvocation which also makes the solution work in non-advanced functions)

suyuguoqiao 注册会员
2023-01-26 11:47

You can take something like that with care. The idea is to convert names ('status') to paths where it should be ('status.name') and then get a hashtable like

'id' = 22
'status.name' = 'new'
'comment' = 'text'
'owner.name' = 'user'

and convert it to multi-layered hashtable based on "dot" separator then:

$baseTask = @{
    task = @{
        comment = $Comment;
        status = @{
            name = $Status;
        owner = @{
            name = $Owner;
        }
    }
}

And then to JSON


The example below is an example and should be used with caution as it HAS some problems.

function test {
    [CMDLetBinding()]
    Param(
        [Parameter(Mandatory=$true)]
        $TaskID,
        $Comment,
        $Status,
        $Owner
)
    $paramList = @{}
    $params = $PSCmdlet.MyInvocation.BoundParameters
    foreach ($paramName in $params.Keys) {
        switch -Exact  ($paramName) {
            'TaskID'  { $paramList['id'] = $params[$paramName] }
            'Comment' { $paramList['comment'] = $params[$paramName] }
            'Status'  { $paramList['status.name'] = $params[$paramName] }
            'Owner'   { $paramList['owner.name']  = $params[$paramName] }
        }
    }
    $replaced = 0
    do {
        $replaced = 0
        $keys = @($paramList.Keys)
        foreach ($key in $keys) {
            $dotPos = $key.LastIndexOf('.')
            if ($dotPos -gt 0) {
                $value =  $paramList[$key]
                if (-not $value.GetType().IsValueType) {
                    if ($value.Clone -ne $null) {
                        $value = $value.Clone()
                    }
                }
                $subKey = $key.Substring($dotPos + 1)
                $newKey = $key.Substring(0, $dotPos)
                $paramList.Remove($key) | Out-Null
                $newVal = @{$subKey=$value}
                $paramList.Add($newKey, $newVal)
                $replaced++
            }
        }
    } while ($replaced -gt 0)
    return $paramList
    
}

test -TaskID 123 -Status 'New' -Comment 'Test' -Owner 'user' | ConvertTo-Json -Depth 10 -Compress:$false