Сохранить хеш-таблицу в нотации объектов PowerShell (PSON)

Вопрос Загрузка хеш-таблицы PowerShell из файла? Документы, как загрузить файл, который содержит хеш-таблицу в формате 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'}
    )            
}

5 ответов

Решение

Нашел решение для чтения / записи хеш-таблиц в INI-файл:

Я пришел к тому же вопросу.

Использование ConvertTo-JSON действительно является наиболее очевидным решением, но в более ранних версиях PowerShell этот командлет недоступен, кроме того, почему вы должны говорить на другом языке (например, JSON), если вы не хотите обмениваться какими-либо данными с другим языком? Я обнаружил, что командлет ConvertTo-PSON будет удобен для хранения данных, а также будет очень полезен для отображения, раскрытия и исследования точной информации о переменной объекта, так что это результат:

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 действительно уже существует в виде: 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

В этом базовом примере объект преобразуется в строку PowerShell, аналогичную командлету ConvertTo-JSON, который можно снова преобразовать с помощью собственного командлета Invoke-Expression PowerShell.

строгий

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 

Слои

Опция слоев будет определять, как уровни слоя будут расширяться по отдельным линиям. Каждый уровень слоя получит дополнительный отступ для вкладки.

Слои 0 Одна строка без пробелов (сжатый режим)

Слои 1 Одна строка, отформатированная с пробелами (по умолчанию)

Слои 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] тип, который будет заменен на New-Object PSObject –Property при запуске PowerShell 2.0, если вы хотите обмениваться данными из более ранней версии PowerShell с PowerShell 2.0, вы можете использовать опцию –Version 2.0.

Примеры

Используя хэш-таблицу в оригинальном вопросе от Крейга:

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

Write-Host (PSON $ Craig) # Стандартный

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

Write-Host (PSON $ Craig -Layers 0) # Сжатый

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

Write-Host (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"}
        )
}

Write-Host (PSON $ Craig -Strict -Layers 9) # Строгий, 9 (все) слои

[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.

Попробуйте *-CliXml командлеты. Чтобы сохранить объект:

@{            
 "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

Одним из способов было бы поместить определение хеш-таблицы в блок скриптов:

$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" = "report 0"
"parameters" = @ (@ {"name" = "параметр 0"; "default" = 1; "values"=1,2,3,4}, @{"name" = "параметр 1"; "по умолчанию" = 'A'; "values" = 'A', 'B', 'C'})
}

Внутри скрипта вам нужно вызвать блок скрипта для создания экземпляра хеш-таблицы:

$hash = .$hashtable

Как использовать сокращенную "нотацию объекта" для создания объекта в PowerShell:

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

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я знаю, что это не отвечает на вопрос OP напрямую, но это может помочь людям, подобным мне, искать очень похожую проблему и приземлиться здесь.

Другие вопросы по тегам