如何在PowerShell中转换为JSON时排除非值对象属性

ma8fv8wu  于 2023-10-21  发布在  Shell
关注(0)|答案(4)|浏览(137)

我有一段代码,但我想知道是否有更好的方法来做。到目前为止,我找不到任何相关的东西。以下是事实:

  • 我有一个有n个属性的对象。
  • 我想使用(ConvertTo-JSON)将此对象转换为JSON。
  • 我不想在JSON中包含那些没有值的对象属性。

创建对象(并不重要):

$object = New-Object PSObject
Add-Member -InputObject $object -MemberType NoteProperty -Name TableName -Value "MyTable"
Add-Member -InputObject $object -MemberType NoteProperty -Name Description -Value "Lorem ipsum dolor.."
Add-Member -InputObject $object -MemberType NoteProperty -Name AppArea -Value "UserMgmt"
Add-Member -InputObject $object -MemberType NoteProperty -Name InitialVersionCode -Value ""

我需要改进的那一行(过滤掉非值属性,不在JSON中包含它们)

# So I want to 'keep' and deliver to the JSON only the properties that are valued (first 3).
$object | select -Property TableName, Description, AppArea, InitialVersion | ConvertTo-Json

这条线提供的是:

Results:
{
    "TableName":  "MyTable",
    "Description":  "Lorem ipsum dolor..",
    "AppArea":  "UserMgmt",
    "InitialVersion":  null
}

What I want to obtain:
{
    "TableName":  "MyTable",
    "Description":  "Lorem ipsum dolor..",
    "AppArea":  "UserMgmt"
}

我已经尝试过了,但我不喜欢它,因为我有更多的属性要处理:

$JSON = New-Object PSObject

if ($object.TableName){
   Add-Member -InputObject $JSON -MemberType NoteProperty -Name TableName -Value $object.TableName
}

if ($object.Description){
   Add-Member -InputObject $JSON -MemberType NoteProperty -Name Description -Value $object.Description
}

if ($object.AppArea){
   Add-Member -InputObject $JSON -MemberType NoteProperty -Name AppArea -Value $object.AppArea
}

if ($object.InitialVersionCode){
   Add-Member -InputObject $JSON -MemberType NoteProperty -Name InitialVersionCode -Value $object.InitialVersionCode
}

$JSON | ConvertTo-Json
x0fgdtte

x0fgdtte1#

像这样吗

$object = New-Object PSObject

Add-Member -InputObject $object -MemberType NoteProperty -Name TableName -Value "MyTable"
Add-Member -InputObject $object -MemberType NoteProperty -Name Description -Value "Lorem ipsum dolor.."
Add-Member -InputObject $object -MemberType NoteProperty -Name AppArea -Value "UserMgmt"
Add-Member -InputObject $object -MemberType NoteProperty -Name InitialVersionCode -Value ""

# Iterate over objects
$object | ForEach-Object {
    # Get array of names of object properties that can be cast to boolean TRUE
    # PSObject.Properties - https://msdn.microsoft.com/en-us/library/system.management.automation.psobject.properties.aspx
    $NonEmptyProperties = $_.psobject.Properties | Where-Object {$_.Value} | Select-Object -ExpandProperty Name

    # Convert object to JSON with only non-empty properties
    $_ | Select-Object -Property $NonEmptyProperties | ConvertTo-Json
}

测试结果:

{
    "TableName":  "MyTable",
    "Description":  "Lorem ipsum dolor..",
    "AppArea":  "UserMgmt"
}
wr98u20j

wr98u20j2#

我在我的个人资料中为此目的设置了以下功能。优点:我可以将一个对象集合通过管道传递给它,并从管道上的所有对象中删除null。

Function Remove-Null {
    [cmdletbinding()]
    param(
        # Object to remove null values from
        [parameter(ValueFromPipeline,Mandatory)]
        [object[]]$InputObject,
        #By default, remove empty strings (""), specify -LeaveEmptyStrings to leave them.
        [switch]$LeaveEmptyStrings
    )
    process {
        foreach ($obj in $InputObject) {
            $AllProperties = $obj.psobject.properties.Name
            $NonNulls = $AllProperties |
                where-object {$null -ne $obj.$PSItem} |
                where-object {$LeaveEmptyStrings.IsPresent -or -not [string]::IsNullOrEmpty($obj.$PSItem)}
            $obj | Select-Object -Property $NonNulls
        }
    }
}

一些用法示例:

$AnObject = [pscustomobject]@{
    prop1="data"
    prop2="moredata"
    prop5=3
    propblnk=""
    propnll=$null
}
$AnObject | Remove-Null

prop1 prop2    prop5
----- -----    -----
data  moredata     3

$ObjList =@(
    [PSCustomObject]@{
        notnull = "data"
        more = "sure!"
        done = $null
        another = ""
    },
    [PSCustomObject]@{
        notnull = "data"
        more = $null
        done = $false
        another = $true
    }
)
$objList | Remove-Null | fl #format-list because the default table is misleading

notnull : data
more    : sure!

notnull : data
done    : False
another : True
mwg9r5ms

mwg9r5ms3#

beatcracker's helpful answer提供了有效的解决方案;让我用一个利用PSv 4+功能的精简版本来补充它:

# Sample input object
$object = [pscustomobject] @{
  TableName = 'MyTable'
  Description = 'Lorem ipsum dolor...'
  AppArea = 'UserMgmt'
  InitialVersionCode = $null
}

# Start with the list of candidate properties.
# For simplicity we target *all* properties of input object $obj
# but you could start with an explicit list as wellL
#   $candidateProps = 'TableName', 'Description', 'AppArea', 'InitialVersionCode'
$candidateProps = $object.psobject.properties.Name

# Create the filtered list of those properties whose value is non-$null
# The .Where() method is a PSv4+ feature.
$nonNullProps = $candidateProps.Where({ $null -ne $object.$_ })

# Extract the list of non-null properties directly from the input object
# and convert to JSON.
$object | Select-Object $nonNullProps | ConvertTo-Json
gajydyqb

gajydyqb4#

我自己修改了batmanama's answer,它接受了一个额外的参数,允许您删除该参数中列表中的元素。举例来说:

Get-CimInstance -ClassName Win32_UserProfile | 
Remove-Null -AlsoRemove 'Win32_FolderRedirectionHealth' | Format-Table

我已经发布了一个gist版本,包括PowerShell文档。

Function Remove-Null {
    [CmdletBinding()]
    Param(
        # Object from which to remove the null values.
        [Parameter(ValueFromPipeline,Mandatory)]
        $InputObject,
        # Instead of also removing values that are empty strings, include them
        # in the output.
        [Switch]$LeaveEmptyStrings,
        # Additional entries to remove, which are either present in the
        # properties list as an object or as a string representation of the
        # object.
        # I.e. $item.ToString().
        [Object[]]$AlsoRemove = @()
    )
    Process {
        # Iterate InputObject in case input was passed as an array
        ForEach ($obj in $InputObject) {
            $obj | Select-Object -Property (
                $obj.PSObject.Properties.Name | Where-Object {
                    -not (
                        # If prop is null, remove it
                        $null -eq $obj.$_ -or
                        # If -LeaveEmptyStrings is not specified and the property
                        # is an empty string, remove it
                        (-not $LeaveEmptyStrings.IsPresent -and
                            [string]::IsNullOrEmpty($obj.$_)) -or
                        # If AlsoRemove contains the property, remove it
                        $AlsoRemove.Contains($obj.$_) -or
                        # If AlsoRemove contains the string representation of
                        # the property, remove it
                        $AlsoRemove.Contains($obj.$_.ToString())
                    )
                }
            )
        }
    }
}

请注意,这里的process块自动迭代管道对象,因此当一个项显式传递到数组中(例如将其 Package 在单个元素数组,$array中)或作为直接参数提供时(例如Remove-Null -InputObject $(Get-ChildItem)),ForEach只会重复执行一次。
值得一提的是,mine和batmanama的函数都将从 * 每个 * 单独的对象中删除这些属性。这就是它如何正确利用PowerShell管道的方式。此外,这意味着如果InputObject中的任何对象具有 * 不 * 匹配的属性(例如,它们notnull),输出表仍将显示该属性,即使它已从其他 * 确实 * 匹配的项中删除了这些属性。
这里有一个简单的例子来展示这种行为:

@([pscustomobject]@{Number=1;Bool=$true},
[pscustomobject]@{Number=2;Bool=$false},
[pscustomobject]@{Number=3;Bool=$true},
[pscustomobject]@{Number=4;Bool=$false}) | Remove-Null -AlsoRemove $false

Number Bool
------ ----
     1 True
     2
     3 True
     4

相关问题