以PowerShell对象表示法(PSON)保存哈希表

时间:2013-02-28 15:37:17

标签: powershell powershell-v2.0

问题Loading a PowerShell hashtable from a file?记录了如何将包含PSON格式哈希表的文件加载到变量中,但如何将哈希表保存为PSON格式的文件?

哈希表:

@{            
 "name" = "report 0"            
 "parameters" = @(
    @{"name" = "parameter 0"; "default" = 1; "values"=1,2,3,4},
    @{"name" = "parameter 1"; "default" = 'A'; "values" = 'A','B','C'}
    )            
}

4 个答案:

答案 0 :(得分:11)

我遇到了同样的问题。

使用 ConvertTo-JSON 确实是最明显的工作,但在早期版本的PowerShell中,这个Cmdlet不可用,除非你为什么不说另一种语言(例如JSON)想用另一种语言交换任何数据? 我发现 ConvertTo-PSON Cmdlet可以很好地存储数据,也非常有助于显示,显示和探索对象变量的确切信息,所以这就是结果:

Function ConvertTo-PSON($Object, [Int]$Depth = 9, [Int]$Layers = 1, [Switch]$Strict, [Version]$Version = $PSVersionTable.PSVersion) {
    $Format = $Null
    $Quote = If ($Depth -le 0) {""} Else {""""}
    $Space = If ($Layers -le 0) {""} Else {" "}
    If ($Object -eq $Null) {"`$Null"} Else {
        $Type = "[" + $Object.GetType().Name + "]"
        $PSON = If ($Object -is "Array") {
            $Format = "@(", ",$Space", ")"
            If ($Depth -gt 1) {For ($i = 0; $i -lt $Object.Count; $i++) {ConvertTo-PSON $Object[$i] ($Depth - 1) ($Layers - 1) -Strict:$Strict}}
        } ElseIf ($Object -is "Xml") {
            $Type = "[Xml]"
            $String = New-Object System.IO.StringWriter
            $Object.Save($String)
            $Xml = "'" + ([String]$String).Replace("`'", "'") + "'"
            If ($Layers -le 0) {($Xml -Replace "\r\n\s*", "") -Replace "\s+", " "} ElseIf ($Layers -eq 1) {$Xml} Else {$Xml.Replace("`r`n", "`r`n`t")}
            $String.Dispose()
        } ElseIf ($Object -is "DateTime") {
            "$Quote$($Object.ToString('s'))$Quote"
        } ElseIf ($Object -is "String") {
            0..11 | ForEach {$Object = $Object.Replace([String]"```'""`0`a`b`f`n`r`t`v`$"[$_], ('`' + '`''"0abfnrtv$'[$_]))}; "$Quote$Object$Quote"
        } ElseIf ($Object -is "Boolean") {
            If ($Object) {"`$True"} Else {"`$False"}
        } ElseIf ($Object -is "Char") {
            If ($Strict) {[Int]$Object} Else {"$Quote$Object$Quote"}
        } ElseIf ($Object -is "ValueType") {
            $Object
        } ElseIf ($Object.Keys -ne $Null) {
            If ($Type -eq "[OrderedDictionary]") {$Type = "[Ordered]"}
            $Format = "@{", ";$Space", "}"
            If ($Depth -gt 1) {$Object.GetEnumerator() | ForEach {$_.Name + "$Space=$Space" + (ConvertTo-PSON $_.Value ($Depth - 1) ($Layers - 1) -Strict:$Strict)}}
        } ElseIf ($Object -is "Object") {
            If ($Version -le [Version]"2.0") {$Type = "New-Object PSObject -Property "}
            $Format = "@{", ";$Space", "}"
            If ($Depth -gt 1) {$Object.PSObject.Properties | ForEach {$_.Name + "$Space=$Space" + (ConvertTo-PSON $_.Value ($Depth - 1) ($Layers - 1) -Strict:$Strict)}}
        } Else {$Object}
        If ($Format) {
            $PSON = $Format[0] + (&{
                If (($Layers -le 1) -or ($PSON.Count -le 0)) {
                    $PSON -Join $Format[1]
                } Else {
                    ("`r`n" + ($PSON -Join "$($Format[1])`r`n")).Replace("`r`n", "`r`n`t") + "`r`n"
                }
            }) + $Format[2]
        }
        If ($Strict) {"$Type$PSON"} Else {"$PSON"}
    }
} Set-Alias PSON ConvertTo-PSON -Description "Convert variable to PSON"

我昵称(别名)只是 PSON ,因为 ConvertFrom-PSON cmdlet确实已经存在以下形式: Invoke-Expression

Set-Alias ConvertFrom-PSON Invoke-Expression -Description "Convert variable from PSON"

它将我在此处列出的大多数(全部?)本机PowerShell对象类型转换为单个测试对象:

$Object = @{
    String    = [String]"Text"
    Char      = [Char]65
    Byte      = [Byte]66
    Int       = [Int]67
    Long      = [Long]68
    Null      = $Null
    Booleans  = $False, $True
    Decimal   = [Decimal]69
    Single    = [Single]70
    Double    = [Double]71
    DateTime  = [DateTime]"Monday, October 7, 1963 9:47:00 PM"
    Array     = @("One", "Two", @("Three", "Four"), "Five")
    HashTable = @{city="New York"; currency="Dollar (`$)"; postalCode=10021; Etc = @("Three", "Four", "Five")}
    Ordered   = [Ordered]@{One = 1; Two = 2; Three = 3; Four = 4}
    Object    = New-Object PSObject -Property @{Name = "One"; Value = 1; Text = @("First", "1st")}
}

要将对象转换为PSON字符串,您只需输入命令:

PSON $Object

此基本示例将对象转换为类似于 ConvertTo-JSON cmdlet的PowerShell字符串,该字符串可以使用本机 Invoke-Expression PowerShell cmdlet再次转换回来。

严格

ConvertTo-PSON 还有一个 -Strict 选项,可以通过显式添加类型名称来阻止任何类型转换,这将为JSON格式带来很大的好处。 这种类型转换通常会在对象类型转换时发生:

Type                    JSON           PSON      PSON -Strict
----------------------- -------------- --------- ------------
String                  String         String    String
Char                    String         String    Char
Byte                    Int32          Int32     Byte
Int32 (Int)             Int32          Int32     Int32
Int64 (Long)            Int32          Int32     Int64
Null                    Null           Null      Null
Boolean                 Boolean        Boolean   Boolean
Decimal                 Int32          Int32     Decimal
Single                  Int32          Int32     Single
Double                  Int32          Int32     Double
DateTime                DateTime       DateTime  DateTime
Object[] (Array)        Object[]       Object[]  Object[]
HashTable               PSCustomObject HashTable HashTable
Ordered                 PSCustomObject HashTable Ordered
PSCustomObject (Object) PSCustomObject HashTable PSCustomObject
XML                     (TypeName)     String    XML

将对象存储在例如一个文件,注册表,数据库等,最好是使用 -Strict 选项并定义0层将压缩数据(删除所有空格):

$PSON1 = PSON -Layers 0 -Strict $Object 

“图层”选项将定义图层级别如何在单独的线条上展开。每个图层级别都会获得额外的标签缩进。

-Layers 0一行没有任何空格(压缩模式)

-Layers 1一行用空格格式化(默认)

-Layers X多个图层在多行上展开,直到深度为X级(缩进)

让我们将PSON字符串转换回来并确认结果:

$Test1 = invoke-expression $PSON1      # ConvertFrom-PSON
$PSON2 = PSON -Layers 4 -Strict $Test1 # ConvertTo-PSON again in a better readable format
Write-Host $PSON2
$Test2 = invoke-expression $PSON2      #Confirm object structure is still intact

结果如下:

[Hashtable]@{
        Decimal = [Decimal]69;
        Long = [Int64]68;
        Char = [Char]65;
        Array = [Object[]]@(
                [String]"One",
                [String]"Two",
                [Object[]]@(
                        [String]"Three",
                        [String]"Four"
                ),
                [String]"Five"
        );
        Object = [PSCustomObject]@{
                Name = [String]"One";
                Value = [Int32]1;
                Text = [Object[]]@(
                        [String]"First",
                        [String]"1st"
                )
        };
        Int = [Int32]67;
        Byte = [Byte]66;
        HashTable = [Hashtable]@{
                postalCode = [Int32]10021;
                currency = [String]"Dollar`t(`$)";
                city = [String]"New York";
                Etc = [Object[]]@(
                        [String]"Three",
                        [String]"Four",
                        [String]"Five"
                )
        };
        Booleans = [Object[]]@(
                [Boolean]$False,
                [Boolean]$True
        );
        Null = $Null;
        String = [String]"Text";
        Ordered = [Ordered]@{
                One = [Int32]1;
                Two = [Int32]2;
                Three = [Int32]3;
                Four = [Int32]4
        };
        DateTime = [DateTime]"1963-10-07T21:47:00";
        Single = [Single]70;
        Double = [Double]71
}

深度

深度选项类似于 ConvertTo-JSON 命令中的深度选项。默认情况下,深度限制为9个级别。深度为0的级别将删除字符串中的双引号,这可能会在您期望字符串的情况下派上用场,但如果不是,则希望收到警报,例如:

Write-Host "User name:" (PSON $UserName 0)

PowerShell 2.0不包括[PSCustomObject]类型,在运行PowerShell 2.0时将替换为New-Object PSObject –Property,如果您想使用PowerShell 2.0从更高版本的PowerShell交换数据,则可以使用< strong> -Version 2.0 选项。

实施例

使用Craig原始问题中的哈希表:

$Craig = @{
    "name" = "report 0"
    "parameters" = @(
        @{"name" = "parameter 0"; "default" = 1; "values"=1,2,3,4},
        @{"name" = "parameter 1"; "default" = 'A'; "values" = 'A','B','C'}
    )
}

写主机(PSON $ Craig) #Standard

@{name = "report 0"; parameters = @(@{values=@(1,2,3,4);default=1;name="parameter 0"},@{values=@("A","B","C");default="A";name="parameter 1"})}

写主机(PSON $ Craig -Layers 0) #Compressed

@{name="report 0";parameters=@(@{values=@(1,2,3,4);default=1;name="parameter 0"},@{values=@("A","B","C");default="A";name="parameter 1"})}

写主机(PSON $ Craig -Layers 3)#3层

@{
        name = "report 0";
        parameters = @(
                @{values = @(1,2,3,4); default = 1; name = "parameter 0"},
                @{values = @("A","B","C"); default = "A"; name = "parameter 1"}
        )
}

写主机(PSON $ Craig -Strict -Layers 9) #Strict,9(all)layers

[Hashtable]@{
        name = [String]"report 0";
        parameters = [Object[]]@(
                [Hashtable]@{
                        values = [Object[]]@(
                                [Int32]1,
                                [Int32]2,
                                [Int32]3,
                                [Int32]4
                        );
                        default = [Int32]1;
                        name = [String]"parameter 0"
                },
                [Hashtable]@{
                        values = [Object[]]@(
                                [String]"A",
                                [String]"B",
                                [String]"C"
                        );
                        default = [String]"A";
                        name = [String]"parameter 1"
                }
        )
}

最新见ConvertTo-Expression上的PowerShell Gallery

答案 1 :(得分:9)

尝试使用*-CliXml cmdlet。要保存对象:

@{            
 "name" = "report 0"            
 "parameters" = @(
    @{"name" = "parameter 0"; "default" = 1; "values"=1,2,3,4},
    @{"name" = "parameter 1"; "default" = 'A'; "values" = 'A','B','C'}
    )            
} | Export-Clixml -Path c:\hash.xml

要读回来:

Import-Clixml c:\hash.xml

答案 2 :(得分:3)

一种方法是将哈希表定义放在scriptblock中:

$hashtable = {
  @{            
    "name" = "report 0"            
    "parameters" = @(
        @{"name" = "parameter 0"; "default" = 1; "values"=1,2,3,4},
        @{"name" = "parameter 1"; "default" = 'A'; "values" = 'A','B','C'}
        )            
    }
}

$hashtable.tostring()

@ {
    “name”=“报告0”
    “参数”= @(         @ {“name”=“参数0”; “default”= 1; “值”= 1,2,3,4},         @ {“name”=“参数1”; “default”='A'; “values”='A','B','C'}         )
    }

在脚本中,您需要调用脚本块来实例化哈希表:

$hash = .$hashtable

答案 3 :(得分:0)

如何使用速记&#34;对象符号&#34;在PowerShell中生成一个对象:

$object = New-Object -TypeName PSObject -Property @{name="foo";age=21}

免责声明:我知道这不会直接回答OP的问题,但它可能会帮助像我这样的人寻找一个非常相似的问题并在这里登陆。