Хеш-таблицы в PowerShell (строки которые начинаются на @) (полное руководство)
Оглавление
1. Что такое хеш-таблицы в PowerShell
2. Для чего применяются хеш-таблицы
3) Форматирование выводимых данных
3. Синтаксис создания хеш-таблиц
4. Почему в хеш-таблице не соблюдается порядок ключей. Как создать упорядоченную хеш-таблицу
5. Вывод содержимого хеш-таблицы
7. Получение значений по ключам из хеш-таблицы
8. Добавление и удаление ключей и значений
9. Как очистить содержимое хеш-таблицы
10. Перебор ключей и значений хеш-таблицы
11. Типы объектов в HashTables
12. Сортировка ключей и значений
13. Как правильно скопировать хеш-таблицу. Метод .Clone()
14. Как посчитать количество записей в хеш-таблицы
15. Как проверить, существуют ли в хеш-таблице определённые ключи или значения
16. Использование хеш-таблиц для передачи аргументов в командлет
16.2 Сплаттинг для необязательных параметров
16.3 Несколько хеш таблиц с опциями для одного командлета
16.4 Сплаттинг для чистого кода
16.5 Подстановка аргументов в программы за пределами PowerShell
17. Использование хеш-таблиц для форматирования вывода
18. Создание хеш-таблицы из строки. Командлет ConvertFrom-StringData
19. Конвертация хеш-таблицы в JSON
20. Преобразование JSON в хэш-таблицу
1. Что такое хеш-таблицы в PowerShell
Хеш таблица в PowerShell — это строка, содержащая пары «имя» = «значение», данная строка помещается в {} (фигурные скобки) и начинается с символа «@».
Синтаксис хеш-таблицы:
@{ NAME = VALUE; [ NAME = VALUE; ] ...}
Или:
@{ NAME = VALUE [NAME = VALUE ] … }
Пример создания хеш-таблицы:
$hash = @{ Number = 1; Shape = "Square"; Color = "Blue"}
Если вы знакомы с другими языками программирования, то хеш-таблицы в PowerShell похожи на такой тип данных как словари в Python или массивы со строковыми ключами в PHP (ассоциированный массив).
2. Для чего применяются хеш-таблицы
1) Хранение данных
Прежде всего, хеш-таблицы используются для хранения данных. От массивов хеш таблицы отличаются тем, что каждому хранимому значению соответствует определённый (и уникальный) ключ.
2) Опции командлета
Хеш-таблицы весьма интересны в PowerShell, поскольку могут использоваться не только для хранения данных. Скорее всего вы видели примеры использования хеш-таблиц в качестве строк, в которых собраны аргументы перед передачей их в командлет. Возможно, именно в таком качестве вы и встречались с хеш-таблицами в различных учебниках по PowerShell.
К примеру, вы могли видеть что-то вроде такого:
$Options = @{ Path = "/home/mial/test" Recurse = $True Filter = "*.php" Exclude = "html" } Get-ChildItem @Options
То есть создаётся хеш таблица, которая затем передаётся в командлет.
На самом деле, показанные выше команды являются полной аналогией следующей команды:
Get-ChildItem -Path /home/mial/test -Recurse -Filter "*.php" -Exclude "html"
При большом количестве аргументов это действительно удобно и более наглядно.
3) Форматирование выводимых данных
Следующие команды показывают, как хеш-таблицы используются для форматирования выводимых данных:
Get-ChildItem | Format-Table Mode, LastWriteTime, Length, @{Label="Имя"; Expression={$_.Name}} Get-ChildItem | Format-Table @{Label="Режим"; Expression={$_.Mode}}, @{Label="Последняя запись в"; Expression={$_.LastWriteTime}}, @{Label="Размер"; Expression={$_.Length}}, @{Label="Имя"; Expression={$_.Name}}
Эти примеры взяты из статьи «Как поменять заголовок столбца в выводе PowerShell. Как поменять ширину и выравнивание в таблицах».
4) Конвертация в JSON
Хеш-таблицы могут быть конвертированы в строку в формате JSON.
Все эти пример использования хеш-таблиц будут рассмотрены далее в этой статье.
3. Синтаксис создания хеш-таблиц
Синтаксис хеш-таблицы:
@{ NAME = VALUE; [NAME = VALUE ] ...}
То есть строка начинается с символа «@» и заключена в фигурные скобки. Пары «имя» и «значение» отделяются знаком «=» (равно). В качестве разделителя пар имя=значения используется «;» (точка с запятой).
Также разделителем пар имя=значения может быть символ новой строки:
@{ NAME = VALUE [NAME = VALUE ] … }
То есть следующие две команды идентичны:
$hash = @{ Number = 1; Shape = "Square"; Color = "Blue"} $hash = @{ Number = 1 Shape = "Square" Color = "Blue" }
Обратите внимание, что ключи не помещаются в кавычки, а значения помещаются в кавычки. Точнее говоря, значения (если это строки) всегда должны помещаться в кавычки. Ключи также должны помещаться в кавычки, если они содержат пробелы.
Примечание: при обращении к значению хеш-таблицы по ключу, если ключ является строкой, то она всегда должна помещаться в кавычки (независимо от наличия пробелов), например:
$hash["Number"]
Чтобы иметь возможность выполнять различные действия с хеш-таблицей, назначьте её значение переменной.
При желании, вы можете создать пустую хеш-таблицу:
$hash = @{}
4. Почему в хеш-таблице не соблюдается порядок ключей. Как создать упорядоченную хеш-таблицу
Если вы будете перебирать значения хеш-таблицы (как это сделать будет показано ниже), то вы обратите внимание, что порядок добавления ключей со значениями и порядок их перебора не совпадают.
Тем не менее, вы можете создать упорядоченную хеш-таблицу, для этого перед символов «@» нужно добавить строку «[ordered]», то есть:
[ordered]@{ NAME = VALUE ; [ NAME = VALUE ] ...}
Или используя в качестве разделителя символ новой строки:
$hash = [ordered]@{ Number = 1 Shape = "Square" Color = "Blue" }
Обратите внимание, что свойство «[ordered]» нужно указывать во время создания таблицы, его нельзя указать для уже созданной таблицы.
Пример создания пустой упорядоченной хеш-таблицы:
$hash = [ordered]@{}
5. Вывод содержимого хеш-таблицы
Для вывода содержимого хеш-таблицы, укажите имя переменной, в которой она сохранена:
$hash
6. Свойства .keys и .values
Хеш-таблицы имеют свойства .keys и .values. Используйте точечную нотацию для отображения всех ключей или всех значений.
$hash.keys
Вывод:
Number Shape Color
Вывод всех значений хеш-таблицы:
$hash.values
Вывод:
1 Square Blue
Обратите внимание на свойство .keys — они пригодится при переборе всех значений хеш-таблицы.
7. Получение значений по ключам из хеш-таблицы
Таблицы хэш-таблиц не являются массивами, поэтому вы не можете использовать целое число в качестве индекса в хеш-таблице, но вы можете использовать имя ключа для получения его значения в хеш-таблицы. Если ключ представляет собой строковое значение, заключите имя ключа в кавычки.
Например:
$hash["Number"] 1
Каждое имя ключа также является свойством хеш-таблицы, а его значением является значение свойства имени ключа. Используйте следующий формат для отображения значений свойств.
Пример:
$hashtable.KEY VALUE
Примеры:
$hash.Number 1 $hash.Color Blue
8. Добавление и удаление ключей и значений
Чтобы добавить ключи и значения в хеш-таблицу, используйте следующий формат команды.
$hash["KEY"] = "VALUE"
Например, чтобы добавить в хеш-таблицу ключ «Time» со значением «Now», используйте следующий формат инструкции.
$hash["Time"] = "Now"
Вы также можете добавить ключи и значения в хеш-таблицу, используя метод Add() объекта System.Collections.Hashtable. Метод Add() имеет следующий синтаксис:
Add(Key, Value)
Например, чтобы добавить ключ Time со значением Now в хеш-таблицу, используйте следующий формат инструкции.
$hash.Add("Time", "Now")
Кроме того, вы можете добавлять ключи и значения в хеш-таблицу, используя оператор сложения (+), чтобы добавить хеш-таблицу к существующей хеш-таблице. Например, следующий оператор добавляет ключ Time со значением Now в хеш-таблицу в переменной $hash.
$hash = $hash + @{Time="Now"}
Вы также можете добавлять значения, которые хранятся в переменных.
$t = "Today" $now = (Get-Date) $hash.Add($t, $now)
Вы не можете использовать оператор вычитания для удаления пары ключ-значение из хеш-таблицы, но вы можете использовать метод Remove() объекта Hashtable. Метод Remove() принимает ключ в качестве значения.
Метод Remove имеет следующий синтаксис:
Remove(Key)
Например, чтобы удалить пару ключ-значение Time=Now из хеш-таблицы в значении переменной $hash, введите:
$hash.Remove("Time")
9. Как очистить содержимое хеш-таблицы
Вы можете очистить содержимое хеш-таблицы просто присвоив ей пустое значение:
$hash = @{}
Либо вы можете воспользоваться методом .clear():
$hash.clear()
Обратите внимание, что данные методы очистки хеш-таблицы не являются равнозначными. Подробности об их различии описаны в разделе 13. Как правильно скопировать хеш-таблицу. Метод .Clone().
10. Перебор ключей и значений хеш-таблицы
Вы можете перебирать ключи в хеш-таблице, чтобы обработать значения несколькими способами. Каждый из примеров в этом разделе имеет идентичный вывод. Они перебирают переменную $hash, в которую сохранена следующая хеш-таблица:
$hash = [ordered]@{ Number = 1; Shape = "Square"; Color = "Blue"}
Примечание: В этих примерах $hash определяется как упорядоченный словарь, чтобы гарантировать, что вывод всегда будет в одном и том же порядке. Показанные ниже примеры работают одинаково и для обычных, не упорядоченных хеш-таблиц, но порядок вывода будет непредсказуем.
Каждый показанный ниже пример возвращает одинаковый результат — сообщение для каждого ключа и его значения:
The value of 'Number' is: 1 The value of 'Shape' is: Square The value of 'Color' is: Blue
В этом примере используется блок foreach для перебора ключей.
foreach ($Key in $hash.Keys) { "The value of '$Key' is: $($hash[$Key])" }
В этом примере используется ForEach-Object для перебора ключей.
$hash.Keys | ForEach-Object { "The value of '$_' is: $($hash[$_])" }
В этом примере используется метод GetEnumerator для отправки каждой пары ключ-значение через конвейер в ForEach-Object.
$hash.GetEnumerator() | ForEach-Object { "The value of '$($_.Key)' is: $($_.Value)" }
В этом примере используются методы GetEnumerator и ForEach для перебора каждой пары ключ-значение.
$hash.GetEnumerator().ForEach({"The value of '$($_.Key)' is: $($_.Value)"})
11. Типы объектов в HashTables
Ключи и значения в хеш-таблице могут относиться к любому типу объекта .NET, а одна хеш-таблица может содержать ключи и значения нескольких типов.
12. Сортировка ключей и значений
Элементы в хеш-таблице по своей сути неупорядоченны. Пары «ключ-значение» могут появляться в другом порядке каждый раз, когда вы их отображаете.
Хотя вы не можете сортировать хеш-таблицы, вы можете использовать метод хеш-таблиц GetEnumerator для перечисления ключей и значений, а затем использовать командлет Sort-Object для сортировки перечисляемых значений для отображения.
Например, следующие команды перебирают ключи и значения в хеш-таблице в переменной $p, а затем сортируют ключи в алфавитном порядке.
$p.GetEnumerator() | Sort-Object -Property key Name Value ---- ----- Hash2 {[a, 1], [b, 2], [c, 3]} Notepad System.Diagnostics.Process (Notepad) PowerShell System.Diagnostics.Process (pwsh) WinRM Running
Следующая команда использует ту же процедуру для сортировки значений хеш-функции в порядке убывания.
$p.GetEnumerator() | Sort-Object -Property Value -Descending Name Value ---- ----- PowerShell System.Diagnostics.Process (pwsh) Notepad System.Diagnostics.Process (Notepad) Hash2 {[a, 1], [b, 2], [c, 3]} WinRM Running
13. Как правильно скопировать хеш-таблицу. Метод .Clone()
Рассмотрим следующий пример, в нём содержимое переменной $hash (хеш-таблица) присваивается другой переменной $another. Затем содержимое $hash очищается. Что мы должны увидеть при выводе переменной $another?
$hash = @{ Number = 1; Shape = "Square"; Color = "Blue"} $another = $hash $hash.Clear() $another
Предполагается, что должна быть выведена хеш-таблица, но переменная $another пуста.
Дело в том, что переменной $another присвоена ссылка на память, где хранится хеш-таблица; и если хеш-таблица удалена, то и значение второй переменной становится пустым.
Аналогично происходит и при внесении изменений в исходную хеш-таблицу — копия этой хеш-таблицы в другой переменной отзеркаливает все изменения.
Чтобы этого избежать — чтобы сохранить значение скопированной хеш-таблицы даже если начальная переменная очищена или изменена, используйте метод .Clone():
$hash = @{ Number = 1; Shape = "Square"; Color = "Blue"} $another = $hash.Clone() $hash.Clear() $another
В данном случае при выводе содержимого переменной $another будет показана хеш-таблица.
Такого же результата можно достигнуть если выбрать другой способ очистки начальной переменной. Если вместо метода .Clear() присвоить пустое значение, то скопированные копии хеш-таблицы будут сохранены:
$hash = @{ Number = 1; Shape = "Square"; Color = "Blue"} $another = $hash $hash = @{} $another
14. Как посчитать количество записей в хеш-таблицы
С помощью свойства .Count вы можете узнать, сколько записей помещено в хеш-таблицу:
$hash.Count 3
15. Как проверить, существуют ли в хеш-таблице определённые ключи или значения
В большинстве случаев вы можете просто проверить значение примерно так:
if( $person.age ){...}
Это просто, но стало для меня источником многих ошибок, потому что я упустил одну важную деталь в своей логике. Я начал использовать его, чтобы проверить наличие ключа. Если значение ключа оказывалось $false или ноль, то оператор неожиданно возвращал $false.
if( $person.age -ne $null ){...}
Это решает эту проблему для нулевых значений, но не для $null и несуществующих ключей.
В общем, предыдущие способы больше подходят для проверки, не является ли значение пустым или равным $null. Но если вам нужно проверить, имеется ли определённый ключ, то используйте свойство .ContainsKey(). Например:
if( $person.ContainsKey('age') ){...}
У нас также есть .ContainsValue() для ситуации, когда вам нужно проверить имеется ли определённое значение в хеш-таблице без перебора всего содержимого хеш-таблицы.
16. Использование хеш-таблиц для передачи аргументов в командлет
16.1 Основы сплаттинга
Возвращаемся к уже упомянутому методу применения хеш-таблиц для перечисления опций командлета. Даже если вы не собираетесь использовать этот метод в своих командах, понимание сплатинга (splat) поможет вам читать скрипты в учебниках по PowerShell.
Идея состоит в том, что вместо предоставления всех свойств командлету в одной строке вы можете сначала упаковать их в хеш-таблицу. Затем вы можете передать хэш-таблицу функции особым образом. Ниже приведён пример создания области DHCP обычным способом.
Add-DhcpServerV4Scope -Name 'TestNetwork' -StartRange '10.0.0.2' -EndRange '10.0.0.254' -SubnetMask '255.255.255.0' -Description 'Network for testlab A' -LeaseDuration (New-TimeSpan -Days 8) -Type "Both"
Без использования сплаттинга все эти вещи необходимо указать в одной строке. Строка команды получается весьма длинной и либо прокручивается за пределы экрана, либо переносится туда, где ей вздумается. В любом случае, суть команды и опций становится труднее понять.
Теперь сравните это с командой, использующей сплаттинг.
$DHCPScope = @{ Name = 'TestNetwork' StartRange = '10.0.0.2' EndRange = '10.0.0.254' SubnetMask = '255.255.255.0' Description = 'Network for testlab A' LeaseDuration = (New-TimeSpan -Days 8) Type = "Both" } Add-DhcpServerV4Scope @DHCPScope
Эта команда в точности идентично предыдущему командлету. Просто найдите минутку и оцените, насколько легко читать этот пример. Это одна и та же команда со всеми одинаковыми опциями и их значениями. Второй вариант легче понять и поддерживать в дальнейшем, если нужно будет внести в него изменения.
Итак, не что следует уделить внимание:
- создаётся обычная хеш-таблица, в которой нужно соблюдать правила синтаксиса (для разделителей пар ключ=значение используется новая строка, строковые значения всегда помещаются в кавычки)
- обратите внимание, что в качестве ключей используются имена опций командлета, но дефис перед названии опции не ставится
- в качестве значения может подставляться результат работы командлета (в том числе запущенного с опциями), в этом случае командлет и его опции должны быть помещены в круглые скобки
- при передаче созданной хеш-таблицы в качестве аргументов командлета, вместо привычного имени переменной перед которой стоит символ «$», передаётся имя переменной перед которой стоит символ «@».
16.2 Сплаттинг для необязательных параметров
Один из наиболее распространённых способов использования сплаттинга — это работа с необязательными параметрами, которые берутся из другого места моего сценария. Допустим, я запускаю командлет Get-CIMInstance, имеющий необязательный аргумент $Credential.
$CIMParams = @{ ClassName = 'Win32_Bios' ComputerName = $ComputerName } if($Credential) { $CIMParams.Credential = $Credential } Get-CIMInstance @CIMParams
Я начинаю с создания хеш-таблицы с обязательными параметрами. Если $Credential существует, то он эта переменная добавляется в хеш-таблицу.
Затем полученная хеш-таблица (независимо от того, установлена ли в ней опция Credential или нет) передаётся командлету Get-CIMInstance.
Код получился весьма понятным и при желании в него можно добавить другие параметры или логику. Функция Get-CIMInstance вызывается только один раз, независимо от передаваемых ей параметров.
16.3 Несколько хеш таблиц с опциями для одного командлета
Вы можете объединить несколько хеш-таблиц в один и тот же командлет. Если мы вернёмся к рассмотренному выше примеру:
$Common = @{ SubnetMask = '255.255.255.0' LeaseDuration = (New-TimeSpan -Days 8) Type = "Both" } $DHCPScope = @{ Name = 'TestNetwork' StartRange = '10.0.0.2' EndRange = '10.0.0.254' Description = 'Network for testlab A' } Add-DhcpServerv4Scope @DHCPScope @Common
С помощью такого подхода можно создавать списки общих для нескольких командлетов списков опций. А уникальные для определённых командлетов опции можно вынести в отдельную хеш-таблицу. Это может ещё больше увеличить читаемость исходного кода.
16.4 Сплаттинг для чистого кода
Нет ничего плохого в выделении одного параметра, если это сделает ваш код чище.
$log = @{Path = '.\logfile.log'} Add-Content "logging this command" @log
16.5 Подстановка аргументов в программы за пределами PowerShell
Splatting также работает с некоторыми исполняемыми файлами, использующими синтаксис /param:value. Например, Robocopy.exe имеет такие параметры.
В результате можно создать хеш-таблицу и передать её среди прочих аргументов в robocopy:
$robo = @{R=1;W=1;MT=8} robocopy source destination @robo
Не знаю, насколько это все полезно, но мне показалось интересным.
17. Использование хеш-таблиц для форматирования вывода
Существует несколько командлетов, которые поддерживают использование хеш-таблиц для создания пользовательских или вычисляемых свойств. Обычно это можно увидеть с помощью Select-Object и Format-Table. Хэш-таблицы имеют специальный синтаксис, который в полностью развёрнутом виде выглядит следующим образом.
$property = @{ name = 'totalSpaceGB' expression = { ($_.used + $_.free) / 1GB } }
name — это то, как командлет пометит этот столбец, а expression — это блок сценария, который выполняется для вставки в данный столбец, где $_ — это значение объекта переданному по каналу (трубе, конвейеру, «|»).
Вот этот скрипт в действии:
$drives = Get-PSDrive | Where Used $drives | Select-Object -Property name, $property
Пример вывода:
Name totalSpaceGB ---- ------------ C 118.35 Temp 118.35 Y 915.46 Z 1832.70
Я поместил настраиваемый формат вывода в переменную, но это можно легко определить в строке, и вы можете сократить name до n и expression до e пока вы этим занимаетесь.
$drives | Select-Object -property name, @{n='totalSpaceGB';e={($_.used + $_.free) / 1GB}}
Смотрите также: Как поменять заголовок столбца в выводе PowerShell. Как поменять ширину и выравнивание в таблицах
18. Создание хеш-таблицы из строки. Командлет ConvertFrom-StringData
Командлет ConvertFrom-StringData преобразует строку или следующую строку пар ключ-значение в хеш-таблицу.
В следующем примере показано, как создать здесь строку пользовательских сообщений из предыдущего примера и как использовать ConvertFrom-StringData для преобразования их из строки в хеш-таблицу.
Следующая команда создает здесь строку пар ключ-значение, а затем сохраняет ее в переменной $string.
$string = @" Msg1 = Type "Windows". Msg2 = She said, "Hello, World." Msg3 = Enter an alias (or "nickname"). "@
Эта команда использует командлет ConvertFrom-StringData для преобразования здесь строки в хеш-таблицу.
ConvertFrom-StringData $string Name Value ---- ----- Msg3 Enter an alias (or "nickname"). Msg2 She said, "Hello, World." Msg1 Type "Windows".
Смотрите также:
Get-Help about_Quoting_Rules -Full
19. Конвертация хеш-таблицы в JSON
С помощью командлета ConvertTo-JSON вы можете преобразовать хеш-таблицу в формат JSON:
$hash | ConvertTo-JSON
20. Преобразование JSON в хэш-таблицу
С помощью командлета ConvertFrom-Json используемого с опцией -AsHashtable, вы можете преобразовать строку JSON в хэш-таблицу:
Пример:
'{ "a": "b" }' | ConvertFrom-Json -AsHashtable
Вывод:
Name Value ---- ----- a b
21. Полезные ссылки
Связанные статьи:
- Операторы сравнения в PowerShell (64.5%)
- Основы работы с PowerShell в Linux [Руководство для начинающих] (50%)
- Подстановочные символы в PowerShell (50%)
- Регулярные выражения в PowerShell (50%)
- Как определить тип объекта в PowerShell (50%)
- Как установить PowerShell последней версии на Windows 11 (RANDOM - 7.3%)