Powershell динамически добавляет элемент в массив. Массив powershell


powershell - Powershell: Как инициализировать массив пользовательских объектов?

Я новичок в PowerShell, и обычно Google или поисковые форумы, подобные этим, дают ответы, которые я ищу, но не на этот раз. Итак, вот мой вопрос (обобщенный из конкретной задачи по соображениям конфиденциальности/безопасности):

Во-первых, поскольку это приводит к моему вопросу, я начну с того, что я работал с XML в битве в Powershell и хотел бы как быстро прочитать данные из xml файлов в массивы пользовательских объектов. Например, если у меня был следующий XML файл:

<stuff> <item name="Joe" age="32"> <info>something about him</info> </item> <item name="Sue" age="29"> <info>something about her</info> </item> <item name="Cat" age="12"> <info>something else</info> </item> </stuff>

И если я прочитал это просто, вот так:

[xml]$myxml = Get-Content .\my.xml

... тогда я могу получить массив моих элементов, например:

[array]$myitems = $myxml.stuff.Item $myitems name age info ---- --- ---- Joe 32 something about him Sue 29 something about her Cat 12 something else

Итак, теперь МОЙ ВОПРОС. Как создать подобную структуру массива настраиваемых объектов и инициализировать их в script, БЕЗ чтения файла? О, да, я могу сделать много циклов и/или много создание/инициализация отдельных объектов... и затем добавление в массив... по одному...

Но, похоже, должен быть способ выполнить это создание/инициализацию более простым способом. Обратите внимание, что ключ здесь состоит в том, что мои пользовательские объекты имеют более 2 элементов (в противном случае я бы использовал хэш в одно мгновение!).

Я даже посмотрел на создание большой строки XML и использование Select-XML, но просто не смог правильно получить синтаксис (если бы это была даже правильная дорога, чтобы двигаться вниз).

Итак, любая помощь здесь была бы высоко оценена.

qaru.site

arrays - Инициализация массива PowerShell

Исходный пример возвращает ошибку, потому что массив создан пустым, а затем вы пытаетесь получить доступ к n-му элементу, чтобы присвоить ему значение.

Здесь есть несколько творческих ответов, многие из которых я не знал, прежде чем читать этот пост. Все отлично подходят для небольшого массива, но, как указывает n0rd, есть существенные различия в производительности.

Здесь я использую Measure-Command, чтобы узнать, сколько времени занимает каждая инициализация. Как вы могли догадаться, любой подход, который использует явный цикл PowerShell, медленнее, чем те, которые используют конструкторы .Net или операторы PowerShell (которые были бы скомпилированы в IL или собственный код).

Резюме

  • New-Object и @(somevalue)*n быстрые (около 20k тиков для 100k элементов).
  • Создание массива с оператором диапазона n..m на 10x медленнее (200k тиков).
  • Использование ArrayList с помощью метода Add() на 1000x медленнее базовой линии (20M тиков), как и цикл с уже существующим массивом с использованием for() или ForEach-Object (aka foreach, %),
  • Добавление с += является наихудшим (2M тикает только для 1000 элементов).

В целом, я бы сказал, что массив * n является "лучшим", потому что:

  • Это быстро.
  • Вы можете использовать любое значение, а не только значение по умолчанию для этого типа.
  • Вы можете создавать повторяющиеся значения (для иллюстрации, введите это в приглашении командной строки: (1..10)*10 -join " " или ('one',2,3)*3)
  • Тесный синтаксис.

Единственный недостаток:

  • Неочевидный. Если вы еще не видели эту конструкцию раньше, неясно, что она делает.

Но имейте в виду, что для многих случаев, когда вы хотите инициализировать элементы массива некоторым значением, тогда строго типизированный массив именно то, что вам нужно. Если вы инициализируете все до $false, то будет ли массив когда-либо удерживать что-либо, кроме $false или $true? Если нет, то New-Object type[] n - это "лучший" подход.

Тестирование

Создайте и размер массива по умолчанию, затем назначьте значения:

PS> Measure-Command -Expression {$a = new-object object[] 100000} | Format-List -Property "Ticks" Ticks : 20039 PS> Measure-Command -Expression {for($i=0; $i -lt $a.Length;$i++) {$a[$i] = $false}} | Format-List -Property "Ticks" Ticks : 28866028

Создание массива Boolean немного медленнее, чем массив Object:

PS> Measure-Command -Expression {$a = New-Object bool[] 100000} | Format-List -Property "Ticks" Ticks : 130968

Не ясно, что это делает, документация для New-Object просто говорит, что второй параметр - это список аргументов, который передается конструктору объекта .Net. В случае массивов параметр, очевидно, является желаемым размером.

Добавление с помощью + =

PS> $a=@() PS> Measure-Command -Expression { for ($i=0; $i -lt 100000; $i++) {$a+=$false} } | Format-List -Property "Ticks"

Мне надоело ждать, чтобы это закончилось, поэтому ctrl + c:

PS> $a=@() PS> Measure-Command -Expression { for ($i=0; $i -lt 100; $i++) {$a+=$false} } | Format-List -Property "Ticks" Ticks : 147663 PS> $a=@() PS> Measure-Command -Expression { for ($i=0; $i -lt 1000; $i++) {$a+=$false} } | Format-List -Property "Ticks" Ticks : 2194398

Так же, как (6 * 3) концептуально похож на (6 + 6 + 6), поэтому ($ somearray * 3) должен дать тот же результат, что и ($ somearray + $somearray + $somearray). Но с массивами + является конкатенацией, а не добавлением.

Если $array + = $element медленный, вы можете ожидать, что $array * $n также будет медленным, но это не так:

PS> Measure-Command -Expression { $a = @($false) * 100000 } | Format-List -Property "Ticks" Ticks : 20131

Так же, как Java имеет класс StringBuilder, чтобы избежать создания нескольких объектов при добавлении, так что кажется, что PowerShell имеет ArrayList.

PS> $al = New-Object System.Collections.ArrayList PS> Measure-Command -Expression { for($i=0; $i -lt 1000; $i++) {$al.Add($false)} } | Format-List -Property "Ticks" Ticks : 447133 PS> $al = New-Object System.Collections.ArrayList PS> Measure-Command -Expression { for($i=0; $i -lt 10000; $i++) {$al.Add($false)} } | Format-List -Property "Ticks" Ticks : 2097498 PS> $al = New-Object System.Collections.ArrayList PS> Measure-Command -Expression { for($i=0; $i -lt 100000; $i++) {$al.Add($false)} } | Format-List -Property "Ticks" Ticks : 19866894

Оператор диапазона и цикл Where-Object:

PS> Measure-Command -Expression { $a = 1..100000 } | Format-List -Property "Ticks" Ticks : 239863 Measure-Command -Expression { $a | % {$false} } | Format-List -Property "Ticks" Ticks : 102298091

Примечания:

  • Я перечислил переменную между каждым прогоном ($a=$null).
  • Тестирование проводилось на планшете с процессором Atom; вы, вероятно, увидите более быстрые скорости на других машинах. [edit: примерно на два раза быстрее на настольной машине.]
  • Когда я пробовал несколько прогонов, наблюдалась небольшая вариация. Ищите порядки величины, а не точные цифры.
  • Тестирование проводилось с помощью PowerShell 3.0 в Windows 8.

Выражение признательности

Благодаря @halr9000 для массива * n, @Scott Saad и Lee Desmond для нового объекта и @EBGreen для ArrayList.

Благодаря @n0rd за то, что я задумался о производительности.

qaru.site

arrays - Массив массива PowerShell

После чтения этой полезной статьи в блоге Windows PowerShell я понял, что могу "сдвинуть" с первой части массива, но didn "Невозможно" переключить "или нажимать элементы на фронте массива в PowerShell.

Я создаю массив хеш-объектов, с последним элементом чтения, который сначала вставляется в массив. Мне интересно, есть ли лучший способ достичь этого.

## Create a list of files for this collection, pushing item on top of all other items if ($csvfiles[$collname]) { $csvfiles[$collname] = @{ repdate = $date; fileobj = $csv }, $csvfiles[$collname] | %{$_} } else { $csvfiles[$collname] = @{ repdate = $date; fileobj = $csv } }

Несколько замечаний:

  • Мне нужно развернуть предыдущий элемент массива с циклом foreach% {$ _}, потому что просто обращение к массиву создало бы структуру вложенных массивов. Я должен иметь все элементы на одном уровне.
  • Мне нужно различать пустой массив и тот, который содержит элементы. Если я попытаюсь развернуть пустой массив, он помещает элемент $null в конец массива.

Мысли?

PS: Причина, по которой пустой элемент хэша создает значение NULL, заключается в том, что $null рассматривается как скаляр в PowerShell. Подробнее см. https://connect.microsoft.com/PowerShell/feedback/details/281908/foreach-should-not-execute-the-loop-body-for-a-scalar-value-of-null.

Ответ:

Похоже, что лучшим решением является предварительное создание пустого массива, когда это необходимо, а не код вокруг проблемы $null. Здесь переписывается с использованием .NET ArrayList и собственного массива PoSh.

if (!$csvfiles.ContainsKey($collname)) { $csvfiles[$collname] = [System.Collections.ArrayList]@() } $csvfiles[$collname].insert(0, @{ repdate = $repdate; fileobj = $csv }) ## NATIVE POSH SOLUTION... if (!$csvfiles.ContainsKey($collname)) { $csvfiles[$collname] = @() } $csvfiles[$collname] = @{ repdate = $repdate; fileobj = $csv }, ` $csvfiles[$collname] | %{$_} задан jsuddsjr 22 нояб. '12 в 0:16 источник поделиться

qaru.site

arrays - Powershell - объединение массивов

Я новичок в powershell и нуждаюсь в помощи. Мой первый script для работы автоматизирует новых и названных пользователей в среде AD.

Дамп CSV будет выполняться один раз в день из нашей системы Peoplesoft. Я использую Import-CSV и создаю 3 массива (новые, термины и обработанные).

Проблема, с которой я столкнулась, состоит в объединении трех массивов, когда я прохожу через всех пользователей и пытаюсь вернуть их обратно в файл. Код разбивается на строки $New += $Term. Я считаю, что это связано с тем, что в моем тестовом файле есть только 1 запись каждого типа пользователя (новая, термическая и обработанная) (я знаю, добавьте больше пользователей и hellip; не могу. Это может быть реальный результат для любого конкретный день). Ниже приведен пример кода:

#Get Credentials from user $c = Get-Credential #Get Date for $Term array population $e = Get-Date -format M/d/yyyy #Set file location and variable for said file $File = "c:\users\nmaddux\desktop\adduserstuff\test.csv" #Import record sets for New and Term users $New = @() $Term = @() $Procd = @() $New = Import-Csv $File | Where-Object { $_.TermDate -eq "" -and $_.LastName -ne "" -and $_.Processdate -eq "" } $Term = Import-Csv $File | Where-Object { $_.TermDate -ne "" -and $_.Processdate -eq "" -and $_.TermDate -le $e } $Procd = Import-Csv $File | Where-Object { $_.Processdate -ne "" } #Process both new and term users provided there are records to process for each If ($New -ne $NULL -and $Term -ne $NULL) { # Some code to process users } $new += $term $new += $Procd $new | Export-Csv $file -NoTypeInformation -ErrorAction SilentlyContinue

Таким образом, он будет экспортировать, но только частичные результаты.

error - вызов метода не выполнен, потому что [System.Management.Automation.PSObject] не содержит метода с именем "op_Addition".

источник поделиться

qaru.site

arrays - Powershell динамически добавляет элемент в массив

Здесь вы хорошо разбираетесь в "переменной переменной"; в принципе ты никогда не напишешь

$User.Machine1 $User.Machine2 $User.Machine...

потому что вы не знаете, сколько машин есть, поэтому вы не можете записывать имена свойств в свой код. Массивы являются ответом на это, у вас есть одна переменная в вашем коде, которая ссылается на массив, со всеми машинами в нем. Тогда ваш код имеет смысл, он прост и разумен и работает, но не соответствует вашей мечте о CSV - потому что ваши данные не CSV-формы.

Если вы добавляете одно свойство для каждой машины для каждого пользователя, вы получаете некоторых пользователей с одной машиной, а некоторые с четырьмя... и это срабатывает ConvertTo-Csv Format-Table, ConvertTo-Csv, Out-GridView, потому что они берут первый объект они видят в качестве шаблона, а затем любые столбцы на других объектах, которые не были на первом объекте, они падают.

Таким образом, вы должны делать то, что делает TheMadTechnician, и возвращаться и динамически добавлять все пустые свойства MachineN ко всем объектам, и это намного проще, если вы просто скажете фронт "там будут N столбцов".

Затем вы можете подсчитать их, и я получаю следующее:

$ADGroup = "SomeADGroup" $ColumnCount = 10 Get-ADGroupMember -Identity $ADGroup -Recursive | Get-ADUser | ForEach-Object { $User = [ordered]@{ 'User' = $_.SurName + ", " + $_.GivenName } $Machines = @((Get-ADComputer -Filter "Description -like '*$($User.User)*'").Name) for ($i=0; $i -lt $ColumnCount; $i++) { $User["Machine$i"] = $Machines[$i] } [PSCustomObject]$User } | ConvertTo-Csv

NB. Я полагаюсь на поведение вне границ, если вам нужно этого избежать, добавьте 10 столбцов пустой строки в конец списка "Машины" в качестве буфера.

Но я все равно был бы очень соблазнен просто скомпонировать CSV самостоятельно, с манипуляциями с строкой, а не с помощью объектов вообще, поскольку вы не используете их, поскольку они должны "использоваться", но только далеко иду делая правильные свойства только для того, чтобы выбросить их, чтобы получить CSV.

Вне темы, ваш код очень запутан:

$UserList = Get-ADGroupMember -Identity $ADGroup -Recursive ' | Select SamAccountName ' | foreach-object {(Get-ADUser -Identity $_.SamAccountName ' | Select @{n='AssignedUser';e={$_.SurName + ", " + $_.GivenName}}).AssignedUser}

Вы получаете член группы AD, затем вы выбираете SamAccountName таким образом, который абсолютно ничего не делает, затем вы перебираете результаты вместо того, чтобы конвейерно обрабатывать их непосредственно в Get-ADUser, без каких-либо преимуществ, затем вы выбираете вычисленное свойство и затем бросаете его и получить значение. Вместо:

Get-ADGroupMember -Identity $ADGroup -Recursive | Get-ADUser | ForEach-Object { $_.SurName + ', ' + $_.GivenName }

Получите членов группы, получите своих пользователей AD и вычислите свою строку из этих результатов.

а также

$Results = New-Object System.Collections.Generic.List[System.Object] -> $Results = @()

или, еще лучше:

$Results = @() foreach ($x in $y) { $Results += ... } -> $Results = foreach ($x in y ) { ... }

И в

| ForEach-Object { [pscustomobject] $_ } |

Вы... могли бы сделать их PSCustomObjects, когда вы их создавали, тогда вам это не понадобится.

qaru.site

Массивы в Windows PowerShell, часть 1

После разговора о переменных, поговорим о массивах в Windows PowerShell.

PowerShell удобен тем, что здесь не нужно предварительно объявлять массив, а также указывать его начало и конец. Для создания массива мы просто присваиваем значения его элементам. Пример:

$a=1,2,3

В данном случае мы создали массив из трех элементов.

При создании массива можно использовать оператор диапазона (..). Это удобно для больших массивов, где числа идут по порядку.

$a=5..15

Обращение к элементам массива

Для обращения к элементам массива достаточно ввести его имя.

Количество элементов массива можно посмотреть в его свойстве Length.

Если нужно обратиться к определенному элементу массива, то при обращении нужно указать его порядковый номер. Обратите внимание, что нумерация элементов массива начинается с нуля.

В качестве порядкового номера можно указать и отрицательное значение. Так, например, [-1] означает последний элемент массива.

Если нужно отразить подмножество элементов, можно использовать уже знакомый нам оператор диапазона.

Последний элемент массива еще нумеруется как Length-1 (что логично, поскольку нумерация начинается с нуля). Это удобно, поскольку можно не смотреть общее число элементов массива, а просто выделить диапазон, к примеру, [7..($a.Length-1)].

Изменение значения элемента массива производятся оператором присваивания. Пример:

$a[3]=27 Изменение значения элемента массива.

Как видим, значение четвертого элемента массива сменилось на 27.

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

Продолжение следует…

webistore.ru

arrays - Powershell заполняет массив из списка файлов

Мне нужно заполнить массив powershell именами файлов, хранящихся в каталоге, на основе их имен. Мне нужен другой массив для каждого набора файлов (см. Пример структуры папок), который будет использоваться как часть другого процесса.

Я бы хотел, чтобы это было автоматическим и создавало массивы "на лету", поэтому у меня были бы массивы, содержащие все имена файлов, начинающиеся с processor123, другое для processorabc и processorxyz. Имена этих массивов могут храниться в другом массиве с именем $arrynames. Он должен быть динамическим, если будет введен новый процессор, я не хочу полагаться на то, что пользователи будут вводить имена файлов.

Пример структуры папок;

c:\directory\processor123\processor123.log.20150604 c:\directory\processor123\processor123.log.20150603 c:\directory\processor123\processor123.log.20150602 c:\directory\processor123\processor123.log.20150601 c:\directory\processor123\processor123.log.20150531 c:\directory\processorabc.log.20150604 c:\directory\processorabc.log.20150603 c:\directory\processorabc.log.20150602 c:\directory\processorabc.log.20150601 c:\directory\processorabc.log.20150531 c:\directory\processorxyz.log.20150604 c:\directory\processorxyz.log.20150603 c:\directory\processorxyz.log.20150602 c:\directory\processorxyz.log.20150601 c:\directory\processorxyz.log.20150531

$ ArryNames

processor123 processorabc processorxyz

$ processor123

c:\directory\processor123\processor123.log.20150604 c:\directory\processor123\processor123.log.20150603 c:\directory\processor123\processor123.log.20150602 c:\directory\processor123\processor123.log.20150601 c:\directory\processor123\processor123.log.20150531

$ processorabc

c:\directory\processorabc.log.20150604 c:\directory\processorabc.log.20150603 c:\directory\processorabc.log.20150602 c:\directory\processorabc.log.20150601 c:\directory\processorabc.log.20150531 задан Wiggum123 04 июня '15 в 15:34 источник поделиться

qaru.site