PowerShell — Zabbix — Json

PowerShell v3 и выше!

Сижу я, смотрю на поделки zabbix-админов и прям улыбка не сползает и слёзы))

Например для автообнаружения процессоров используется вот это:

{

$items = Get-WmiObject Win32_PerfFormattedData_PerfOS_Processor | select name  |where-object {$_.name -ne '_Total'}

write-host -NoNewline "{"
write-host -NoNewline "`"data`":["

$line =  "{`"{#PROCNUM}`":`"" + $items[0].Name + "`"}"
write-host -NoNewline $line

for($c = 1; $c -lt $items.Count; ++$c) {
$line =  ",{`"{#PROCNUM}`":`"" + $items[$c].Name + "`"}"
write-host -NoNewline $line
}

write-host -NoNewline "]"
write-host -NoNewline "}"

бла бла бла... 

Ужас…

Про объекты мы не слышали, мы лёгких путей не искали, давайте генерить строку, в конце концов нам платят только за знание zabbix

Хватит троллинга, посмотрим на ошибки и исправим их.

1-е замечание:

каждый pipeline — это по сути цикл, конечно все программирование в мире построено на циклах и мощь пошика как раз в конвеере, но зачем добавлять в код бесполезные операции?

Вместо

 

Get-WmiObject Win32_PerfFormattedData_PerfOS_Processor | select name  |where-object {$_.name -ne '_Total'}

 

Давайте так

Get-WmiObject -Class Win32_PerfFormattedData_PerfOS_Processor -Filter {Name != '_Total'}

Таким образом мы без дополнительного where-object сразу отфильтровали ненужное прям через WMI.

2-е:

Далее мы избавимся от переменных, запуская цикл в манере пошика, а не как попало, итого вместо for используем foreach, обычно я использую его алиас «%»

Не надо так делать, зачем хранить массив в отдельно переменной?

for($i = 0; $i -lt $items.count; $i++) {$items[$i]}

Это уже ближе, но всеравно не то

foreach ($item in $items) {$item}

Вот синтаксис пошика, который идеально подходит для конвеера:

$items | % {$_}

Все-таки не хватает счетчика? Нет проблем, правда здесь он не нужен))

$items | % -begin {$i = 0} -process {$_; $i++}

Молчу про PipelineVariable, может в следующий раз…

В фигурных скобках я выводил переменную цикла, с которой можно работать на каждой итерации

3-е:

Собственно если пораскинуть мозгами, можно догадаться почему люди пытаются генерить Json вручную. Потому что нужно создать объект со свойством data и вдобавок этому свойству нужно задать значение в виде объекта!! о ужас!

Значит так, у нас есть штатный командлет ConvertTo-Json (начиная с 3-го пошика), который на вход принимает объект или хэш-таблицу, типа @{‘v1’ = 1}

Теперь посмотрим в Json, который принимает zabbix и увидим, что после data стоит квадратная скобка, в формате json это значит что далее идет массив значений поэтому в пошике мы создаем массив с помощью @(), а внутрь помещаем хэш-таблицы или объекты @( @{‘v1’ = 1}, @{‘v2’ = 2} )

Внимание: если просто вывести на экран, то разницы между @( @{‘v1’ = 1}, @{‘v2’ = 2} ) и @{‘v1’ = 1; ‘v2’ = 2} вы не увидете, но разница существенна, в первом случае у нас массив хэш-таблиц, а во-втором у нас хэш-таблица с несколькими уникальными ключами! В первом случае первый элемент мы получаем через индекс объекта в массиве @( @{‘v1’ = 1}, @{‘v2’ = 2} )[0], а во втором мы должны обратиться к ключу таблицы @{‘v1’ = 1; ‘v2’ = 2}[‘v1’]

Да, если порядок свойств имеет значение, а для создания объектов это часто имеет значение, то можно использовать не [Hashtable], а [OrderedDictionary] вот так: [ordered]@{‘v1’ = 1; ‘v2’ = 2}

Получаем красивый, аккуратный и читаемый код:

@{
	'data' = @(
		Get-WmiObject -Class Win32_PerfFormattedData_PerfOS_Processor -Filter {Name != '_Total'} | % {
			@{
				'{#PROCNUM}' = $_.Name
			}
		}
	)
} | ConvertTo-Json
 

Ну или как я привык, создаем объекты с помощью преобразования [Hashtable] в [PSCustomObject]

[pscustomobject]@{
	'data' = @(
		Get-WmiObject -Class Win32_PerfFormattedData_PerfOS_Processor -Filter {Name != '_Total'} | % {
			[pscustomobject]@{
				'{#PROCNUM}' = $_.Name
			}
		}
	)
} | ConvertTo-Json

Удачи!

Реклама

PowerShell — Zabbix — Json: 11 комментариев

  1. «Вот синтаксис пошика, который идеально подходит для конвеера:
    $items | % {$_}»

    Для конвейера он-то идеален, только в случае, когда уже есть готовая коллекция (переменная $items) цикл отработает в разы быстрее, чем конвейер, хоть конвейер и выглядит проще.
    Запустите и сравните:

    $items = 1..100000
    
    (Measure-Command {
        foreach($item in $items)
        {
            ($item)
        }
    }).TotalMilliseconds
    
    (Measure-Command {
        $items | ForEach-Object{$_}
    }).TotalMilliseconds
    

    Нравится

    Ответить
    • Проверил конкретный сценарий, разницы почти нет ))

      $PerfOS_Processor = @(Get-WmiObject -Class Win32_PerfFormattedData_PerfOS_Processor -Filter {Name != '_Total'})
      
      function t1 {
      @{'data' = @(
      		Foreach ($Processor in $PerfOS_Processor) {
      			@{
      				'{#PROCNUM}' = $Processor.Name
      			}
      		}
      	)
      } | ConvertTo-Json
      }
      
      function t2 {
      @{
      	'data' = @(
      		$PerfOS_Processor | % {
      			@{
      				'{#PROCNUM}' = $_.Name
      			}
      		}
      	)
      } | ConvertTo-Json
      }
      
      1..10 | % {
      	[pscustomobject][ordered]@{
      		't1'=$((Measure-Command {t1}).TotalMilliseconds);
      		't2'=$((Measure-Command {t2}).TotalMilliseconds);
      	}
      }
      
      
      

      Нравится

      Ответить
      • В моём примере (и на моём компьютере) код с циклом выполняется 627 мс, а с конвейером 2630 мс, с увеличением количества проходов цикла разница будет всё существеннее. Но дело не в этом, я просто хотел проинформировать, что цикл работает чуточку быстрее конвейера, но раз Вы в курсе считаю тему закрытой. Спасибо за статью, хорошего дня и всё такое 🙂

        Нравится

      • И вам! Мне понравился Ваш бложик, буду почитывать. У меня пока как-то тяжело идут тексты, хотя с грамотностью и словарным запасом все в порядке)) хорошего дня!

        Нравится

  2. От это прям огонь статья. Для тех кто использует HWMonitor, там в WMI постоянно задваиваются датчики и получается оттак:
    {
    «data»: [
    {
    «{#SENAME}»: «CPU Package»,
    «{#ID}»: «3849»
    },
    {
    «{#SENAME}»: «CPU Package»,
    «{#ID}»: «3849»
    }
    ]
    }

    Лечится отэтим | select -Unique

    @{
    ‘data’ = @(
    Get-WmiObject -Namespace Root\OpenHardwareMonitor -Class sensor | Where-Object {$_.SensorType -eq «$2» -and $_.Name -notmatch «#|VBAT» -and $_.Parent -notmatch «hdd»} | % {
    @{
    ‘{#ID}’ = $_.InstanceID
    ‘{#SENAME}’ = $_.Name
    }
    }
    ) | select -Unique
    } | ConvertTo-Json

    Нравится

    Ответить
  3. Все обсуждают производительность циклов, а мне хотелось бы уточнить насчет собственно, Заббикса. Код будет работать, если вызывать командлет convertto-json с ключом -Compress. В противном случае, заббикс утверждает, что «value should be a json object».
    Еще для таких нубов, как я, добавлю, что если есть сильное пожелание поместить конструирование json-объекта внутрь цикла (например, много предварительных вычислений, или что-то еще), можно заранее объявить что-то вроде $json = @{ ‘data’ = @() }
    а потом добавлять элементы так:
    $json.data += @(
    @{‘{#NAME}’ = $value }
    )
    За статью спасибо. Теперь не понимаю, почему почти везде городится огород с рисованием текстового файлика.

    Нравится

    Ответить
    • Огород городится потому, что ConvertTo-Json появился только в PowerShell 3, а обновляться всем неохота))
      Заранее создать конструктор для json нативно в PowerShell нельзя, но, кажется, можно использовать дотнетовские классы и в конце запустить сериализатор.
      И напоминаю, что у всех объектов PowerShell есть метод GetType(). Если вы примените его к переменной, созданной на выходе ConvertTo-Json, то увидите, что это просто строка.
      Ну и напоследок:
      Зачем вам конструктор? Посмотрите мой код и вы увидите, что хеш-таблицы берут на себя эту функцию. Вы можете создавать объекты любой вложенности и конвертировать в json, попробуйте хеш-таблицы

      Нравится

      Ответить

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

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s