Хеш-таблицы в PowerShell (строки которые начинаются на @) (полное руководство)


Оглавление

1. Что такое хеш-таблицы в PowerShell

2. Для чего применяются хеш-таблицы

1) Хранение данных

2) Опции командлета

3) Форматирование выводимых данных

4) Конвертация в JSON

3. Синтаксис создания хеш-таблиц

4. Почему в хеш-таблице не соблюдается порядок ключей. Как создать упорядоченную хеш-таблицу

5. Вывод содержимого хеш-таблицы

6. Свойства .keys и .values


7. Получение значений по ключам из хеш-таблицы

8. Добавление и удаление ключей и значений

9. Как очистить содержимое хеш-таблицы

10. Перебор ключей и значений хеш-таблицы

11. Типы объектов в HashTables

12. Сортировка ключей и значений

13. Как правильно скопировать хеш-таблицу. Метод .Clone()

14. Как посчитать количество записей в хеш-таблицы

15. Как проверить, существуют ли в хеш-таблице определённые ключи или значения

16. Использование хеш-таблиц для передачи аргументов в командлет

16.1 Основы сплаттинга

16.2 Сплаттинг для необязательных параметров

16.3 Несколько хеш таблиц с опциями для одного командлета

16.4 Сплаттинг для чистого кода

16.5 Подстановка аргументов в программы за пределами PowerShell

17. Использование хеш-таблиц для форматирования вывода

18. Создание хеш-таблицы из строки. Командлет ConvertFrom-StringData

19. Конвертация хеш-таблицы в JSON

20. Преобразование JSON в хэш-таблицу

21. Полезные ссылки


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. Полезные ссылки


Рекомендуется Вам:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *