Разное

Powershell массивы: Все, что вы хотели знать о массивах — PowerShell

Содержание

Все, что вы хотели знать о массивах — PowerShell



  • Чтение занимает 20 мин

В этой статье

Массивы являются основополагающей функцией большинства языков программирования.Arrays are a fundamental language feature of most programming languages. Они представляют собой коллекцию значений или объектов, с которыми вы, скорее всего, рано или поздно обязательно столкнетесь.They’re a collection of values or objects that are difficult to avoid. Давайте рассмотрим массивы и все доступные в них возможности.Let’s take a close look at arrays and everything they have to offer.

Примечание

Оригинал этой статьи впервые был опубликован в блоге автора @KevinMarquette.The original version of this article appeared on the blog written by @KevinMarquette. Группа разработчиков PowerShell благодарит Кевина за то, что он поделился с нами этими материалами.The PowerShell team thanks Kevin for sharing this content with us. Ознакомьтесь с его блогом на веб-сайте PowerShellExplained.com.Please check out his blog at PowerShellExplained.com.

Что такое массив?What is an array?

Я начну с основного технического описания массивов и способов их использования в большинстве языков программирования, а затем расскажу о других вариантах их использования в PowerShell.I’m going to start with a basic technical description of what arrays are and how they are used by most programming languages before I shift into the other ways PowerShell makes use of them.

Массив представляет собой структуру данных, которая выступает в качестве коллекции из нескольких элементов.An array is a data structure that serves as a collection of multiple items. Можно выполнить итерацию по массиву или получить доступ к отдельным элементам, используя индекс.You can iterate over the array or access individual items using an index. Массив создается в виде последовательного фрагмента памяти, где все значения сохраняются непосредственно рядом друг с другом.The array is created as a sequential chunk of memory where each value is stored right next to the other.

Далее я расскажу обо всем этом подробнее.I’ll touch on each of those details as we go.

Основное использованиеBasic usage

Массивы представляют собой основную функцию PowerShell, поэтому в PowerShell предусмотрен простой синтаксис для работы с ними.Because arrays are such a basic feature of PowerShell, there is a simple syntax for working with them in PowerShell.

Создание массиваCreate an array

Для создания пустого массива можно использовать @().An empty array can be created by using @()

PS> $data = @()
PS> $data.count
0

Мы можем создать массив и заполнить его значениями, просто заключив их в скобки @().We can create an array and seed it with values just by placing them in the @() parentheses.

PS> $data = @('Zero','One','Two','Three')
PS> $data.count
4

PS> $data
Zero
One
Two
Three

В этом массиве 4 элемента.This array has 4 items. При вызове переменной $data отображается список этих элементов.When we call the $data variable, we see the list of our items. Если речь о строковом массиве, в этом случае отображается по одному строковому элементу в строке.If it’s an array of strings, then we get one line per string.

Можно объявить массив для нескольких строковых элементов.We can declare an array on multiple lines. В этом случае запятая является необязательной и, как правило, пропускается.The comma is optional in this case and generally left out.

$data = @(
    'Zero'
    'One'
    'Two'
    'Three'
)

Я предпочитаю объявлять массивы для нескольких строковых элементов вот таким образом.I prefer to declare my arrays on multiple lines like that. Это не только упрощает чтение при наличии нескольких элементов, но и делает сравнение с предыдущими версиями более легким и удобным, если используется система управления версиями.Not only does it get easier to read when you have multiple items, it also makes it easier to compare to previous versions when using source control.

Другой синтаксисOther syntax

Известно, что @() является синтаксисом для создания массива, однако в большинстве случаев чаще используются списки с разделителями-запятыми.It’s commonly understood that @() is the syntax for creating an array, but comma-separated lists work most of the time.

$data = 'Zero','One','Two','Three'
Write-Output для создания массивовWrite-Output to create arrays

Один из полезных трюков, о котором следует упомянуть, заключается в использовании Write-Output для быстрого создания строк в консоли.One cool little trick worth mentioning is that you can use Write-Output to quickly create strings at the console.

$data = Write-Output Zero One Two Three

Это очень удобно, поскольку не нужно заключать строки в кавычки, если параметр принимает строки.This is handy because you don’t have to put quotes around the strings when the parameter accepts strings. В сценарии я бы этого не стал делать, но для консоли это вполне приемлемо.I would never do this in a script but it’s fair game in the console.

Доступ к элементамAccessing items

Теперь вам нужен доступ к имеющимся массивам с элементами, а также возможность обновлять их.Now that you have an array with items in it, you may want to access and update those items.

OffsetOffset

Для доступа к отдельным элементам используются скобки [] со значением смещения не менее 0.To access individual items, we use the brackets [] with an offset value starting at 0. Мы получаем первый элемент в массиве следующим образом.This is how we get the first item in our array:

PS> $data = 'Zero','One','Two','Three'
PS> $data[0]
Zero

Причина, по которой мы используем ноль, заключается в том, что первый элемент находится в самом начале списка, поэтому, чтобы его достичь, потребуется смещение на 0 элементов.The reason why we use zero here is because the first item is at the beginning of the list so we use an offset of 0 items to get to it. Чтобы перейти ко второму элементу, требуется смещение на 1, чтобы пропустить первый элемент.To get to the second item, we would need to use an offset of 1 to skip the first item.

PS> $data[1]
One

Это означает, что для последнего элемента используется значение смещения 3.This would mean that the last item is at offset 3.

PS> $data[3]
Three
ИндексIndex

Теперь вы видите, почему я выбрал для примера именно эти значения.Now you can see why I picked the values that I did for this example. Я представил это как смещение, поскольку это по сути именно оно, однако в данном случае смещение чаще называется индексом.I introduced this as an offset because that is what it really is, but this offset is more commonly referred to as an index. Это индекс, начинающийся с 0.An index that starts at 0. Далее в этой статье я буду называть смещение индексом.For the rest of this article I will call the offset an index.

Специальные возможности использования индексаSpecial index tricks

В большинстве языков можно указать только одно число в качестве индекса, и в ответ вы получаете один элемент.In most languages, you can only specify a single number as the index and you get a single item back.
PowerShell дает гораздо большую гибкость.PowerShell is much more flexible. Можно использовать несколько индексов одновременно.You can use multiple indexes at once. Благодаря списку индексов можно выбрать несколько элементов.By providing a list of indexes, we can select several items.

PS> $data[0,2,3]
Zero
Two
Three

Элементы возвращаются с учетом порядка предоставляемых индексов.The items are returned based on the order of the indexes provided. Если индекс дублируется, то в обоих случаях вы получите именно этот элемент.If you duplicate an index, you get that item both times.

PS> $data[3,0,3]
Three
Zero
Three

Чтобы указать последовательность чисел, можно использовать встроенный оператор ...We can specify a sequence of numbers with the built-in .. operator.

PS> $data[1..3]
One
Two
Three

Это работает и в обратном порядке.This works in reverse too.

PS> $data[3..1]
Three
Two
One

Для смещения с конца можно указать отрицательные значения индекса.You can use negative index values to offset from the end. Поэтому, если требуется последний элемент в списке, можно использовать -1.So if you need the last item in the list, you can use -1.

PS> $data[-1]
Three

При работе с оператором .. необходимо учитывать следующее.One word of caution here with the .. operator. Последовательности 0..-1 и -1..0 вычислены со значениями 0,-1 и -1,0.The sequence 0..-1 and -1..0 evaluate to the values 0,-1 and -1,0. Легко увидеть $data[0..-1] и предположить, что там будут перечислены все элементы, если забыть об этой детали.It’s easy to see $data[0..-1] and think it would enumerate all items if you forget this detail. $data[0..-1] дает то же значение, что и $data[0,-1], предоставляя первый и последний элементы в массиве (и ни одного из остальных значений).$data[0..-1] gives you the same value as $data[0,-1] by giving you the first and last item in the array (and none of the other values).

Вне допустимого диапазонаOut of bounds

В большинстве языков при попытке доступа к индексу элемента, который находится дальше, чем конец массива, возникает ошибка или исключение.In most languages, if you try to access an index of an item that is past the end of the array, you would get some type of error or an exception. PowerShell просто не возвращает ничего.PowerShell silently returns nothing.

PS> $null -eq $data[9000]
True
Индексирование в массив значений null невозможноCannot index into a null array

Если используется переменная $null и вы пытаетесь индексировать ее как массив, выводится исключение System.Management.Automation.RuntimeException с сообщением Cannot index into a null array.If your variable is $null and you try to index it like an array, you get a System.Management.Automation.RuntimeException exception with the message Cannot index into a null array.

PS> $empty = $null
SP> $empty[0]
Error: Cannot index into a null array.

Убедитесь, что массивы не являются $null, прежде чем пытаться получить доступ к элементам внутри них.So make sure your arrays are not $null before you try to access elements inside them.

CountCount

Массивы и другие коллекции содержат свойство Count, которое показывает количество элементов в массиве.Arrays and other collections have a count property that tells you how many items are in the array.

PS> $data.count
4

В PowerShell 3.0 в большинство объектов добавляется свойство Count.PowerShell 3.0 added a count property to most objects. У вас может быть один объект, который должен сообщать свойство Count, равное 1.you can have a single object and it should give you a count of 1.

PS> $date = Get-Date
PS> $date.count
1

Даже $null имеет свойство Count, только оно возвращает 0.Even $null has a count property except it returns 0.

PS> $null.count
0

Однако в этом случае есть ряд сложностей, о которых я расскажу подробнее, когда буду говорить о проверке на наличие $null или пустых массивов далее в этой статье.There are some traps here that I will revisit when I cover checking for $null or empty arrays later on in this article.

Ошибка завышения или занижения на единицуOff-by-one errors

Общая ошибка программирования возникает потому, что массивы начинаются с индекса 0.A common programming error is created because arrays start at index 0. Ошибки завышения/занижения на единицу можно представить двумя способами.Off-by-one errors can be introduced in two ways.

Первый — просто думать, что вам нужен второй элемент, использовать индекс 2 и действительно получить третий элемент.The first is by mentally thinking you want the second item and using an index of 2 and really getting the third item. Можно также думать, что у вас четыре элемента и вам нужен последний из них, и использовать свойство Count для доступа к последнему элементу.Or by thinking that you have four items and you want last item, so you use the count to access the last item.

$data[ $data.count ]

В PowerShell вполне достаточно сделать это и указать, какой элемент существует в индексе 4: $null.PowerShell is perfectly happy to let you do that and give you exactly what item exists at index 4: $null. Следует использовать $data.count - 1 или -1, о которых мы говорили выше.You should be using $data.count - 1 or the -1 that we learned about above.

PS> $data[ $data.count - 1 ]
Three

В этом случае получить последний элемент можно с помощью индекса -1.This is where you can use the -1 index to get the last element.

PS> $data[ -1 ]
Three

Ли Дейли также подсказал, что мы можем использовать $data.GetUpperBound(0) для получения максимального номера индекса.Lee Dailey also pointed out to me that we can use $data.GetUpperBound(0) to get the max index number.

PS> $data.GetUpperBound(0)
3
PS> $data[ $data.GetUpperBound(0) ]
Three

Второй наиболее распространенный способ — если вы выполняете итерацию по списку и не останавливаетесь в нужный момент.The second most common way is when iterating the list and not stopping at the right time. Я об этом расскажу подробнее, когда мы будем говорить об использовании цикла for.I’ll revisit this when we talk about using the for loop.

Обновление элементовUpdating items

Для обновления существующих элементов в массиве можно использовать тот же индекс.We can use the same index to update existing items in the array. Это позволяет напрямую обновлять отдельные элементы.This gives us direct access to update individual items.

$data[2] = 'dos'
$data[3] = 'tres'

При попытке обновить элемент, который находится за последним элементом, возникает ошибка Index was outside the bounds of the array..If we try to update an item that is past the last element, then we get an Index was outside the bounds of the array. error.

PS> $data[4] = 'four'
Index was outside the bounds of the array.
At line:1 char:1
+ $data[4] = 'four'
+ ~~~~~~~~~~~~~
+ CategoryInfo          : OperationStopped: (:) [], IndexOutOfRangeException
+ FullyQualifiedErrorId : System.IndexOutOfRangeException

Я расскажу об этом позже, когда буду говорить об увеличении массива.I’ll revisit this later when I talk about how to make an array larger.

ИтерацияIteration

В какой-то момент вам может потребоваться выполнить обход или итерацию по всему списку и применить действия к каждому элементу в массиве.At some point, you might need to walk or iterate the entire list and perform some action for each item in the array.

PipelinePipeline

Предполагается, что массивы и конвейер PowerShell должны использоваться совместно.Arrays and the PowerShell pipeline are meant for each other. Это один из самых простых способов обработки этих значений.This is one of the simplest ways to process over those values. При передаче массива в конвейер каждый элемент внутри массива обрабатывается по отдельности.When you pass an array to a pipeline, each item inside the array is processed individually.

PS> $data = 'Zero','One','Two','Three'
PS> $data | ForEach-Object {"Item: [$PSItem]"}
Item: [Zero]
Item: [One]
Item: [Two]
Item: [Three]

Если вы еще не видели $PSItem, просто помните, что это то же самое, что и $_.If you have not seen $PSItem before, just know that it’s the same thing as $_. Можно использовать любой из них, так как оба этих элемента представляют текущий объект в конвейере.You can use either one because they both represent the current object in the pipeline.

Цикл ForEachForEach loop

Цикл ForEach эффективно работает с коллекциями.The ForEach loop works well with collections. Используется следующий синтаксис: foreach ( <variable> in <collection> )Using the syntax: foreach ( <variable> in <collection> )

foreach ( $node in $data )
{
    "Item: [$node]"
}
Метод ForEachForEach method

Я часто забываю о нем, однако этот метод эффективен для простых операций.I tend to forget about this one but it works well for simple operations. PowerShell позволяет вызывать .ForEach() для коллекции.PowerShell allows you to call .ForEach() on a collection.

PS> $data.foreach({"Item [$PSItem]"})
Item [Zero]
Item [One]
Item [Two]
Item [Three]

.foreach() принимает параметр, который является блоком сценария.The .foreach() takes a parameter that is a script block. Можно удалить круглые скобки и просто указать блок сценария.You can drop the parentheses and just provide the script block.

$data.foreach{"Item [$PSItem]"}

Такой синтаксис менее популярен, но он работает точно так же.This is a lesser known syntax but it works just the same. Метод foreach добавлен в PowerShell 4.0.This foreach method was added in PowerShell 4.0.

Цикл ForFor loop

Цикл for активно используется в большинстве других языков, но в PowerShell он применяется редко.The for loop is used heavily in most other languages but you don’t see it much in PowerShell. Однако если он все же используется, то зачастую это происходит в контексте обхода массива.When you do see it, it’s often in the context of walking an array.

for ( $index = 0; $index -lt $data.count; $index++)
{
    "Item: [{0}]" -f $data[$index]
}

В первую очередь мы инициализируем $index для 0.The first thing we do is initialize an $index to 0. Затем мы добавляем условие, что $index должно быть меньше $data.count.Then we add the condition that $index must be less than $data.count. Наконец, мы указываем, что при каждой обработке цикла необходимо увеличивать индекс на 1.Finally, we specify that every time we loop that me must increase the index by 1. В этом случае $index++ расшифровывается как $index = $index + 1.In this case $index++ is short for $index = $index + 1.

При каждом использовании цикла for следует обращать особое внимание на условие.Whenever you’re using a for loop, pay special attention to the condition. Здесь я использовал $index -lt $data.count.I used $index -lt $data.count here. При этом довольно легко получить слегка неверное условие и в результате получить в логике ошибку завышения/занижения на единицу.It’s easy to get the condition slightly wrong to get an off-by-one error in your logic. При использовании $index -le $data.count или $index -lt ($data.count - 1) всегда получается слегка неверное условие.Using $index -le $data.count or $index -lt ($data.count - 1) are ever so slightly wrong. Это может привести к тому, что в вашем результате будет обрабатываться слишком много или слишком мало элементов.That would cause your result to process too many or too few items. Это классическая ошибка завышения/занижения на единицу.This is the classic off-by-one error.

Цикл SwitchSwitch loop

Эту ошибку легко упустить из виду.This is one that is easy to overlook. Если вы укажете массив для Оператор switch, он проверит каждый элемент в массиве.If you provide an array to a switch statement, it checks each item in the array.

$data = 'Zero','One','Two','Three'
switch( $data )
{
    'One'
    {
        'Tock'
    }
    'Three'
    {
        'Tock'
    }
    Default
    {
        'Tick'
    }
}
Tick
Tock
Tick
Tock

С помощью оператора switch можно выполнить массу полезных действий.There are a lot of cool things that we can do with the switch statement. Об этом я подробно рассказываю в другой статье.I have another article dedicated to this.

Обновление значенийUpdating values

Если массив является коллекцией строковых или целочисленных значений, в отдельных случаях требуется обновление значений в массиве в процессе их циклической обработки.When your array is a collection of string or integers (value types), sometimes you may want to update the values in the array as you loop over them. В большинстве циклов, описанных выше, используется переменная в цикле, которая содержит копию значения.Most of the loops above use a variable in the loop that holds a copy of the value. При обновлении этой переменной исходное значение в массиве не обновляется.If you update that variable, the original value in the array is not updated.

Исключением для этого оператора является цикл for.The exception to that statement is the for loop. Если вам требуется обход массива и обновление значений в нем, вам нужен цикл for.If you want to walk an array and update values inside it, then the for loop is what you’re looking for.

for ( $index = 0; $index -lt $data.count; $index++ )
{
    $data[$index] = "Item: [{0}]" -f $data[$index]
}

В этом примере принимается значение по индексу, вносится ряд изменений, а затем тот же индекс используется, чтобы назначить значение обратно.This example takes a value by index, makes a few changes, and then uses that same index to assign it back.

Массивы объектовArrays of Objects

До сих пор мы помещали в массив только тип значения, однако массивы также могут содержать и объекты.So far, the only thing we’ve placed in an array is a value type, but arrays can also contain objects.

$data = @(
    [pscustomobject]@{FirstName='Kevin';LastName='Marquette'}
    [pscustomobject]@{FirstName='John'; LastName='Doe'}
)

Многие командлеты возвращают коллекции объектов в виде массивов, когда они назначаются переменной.Many cmdlets return collections of objects as arrays when you assign them to a variable.

$processList = Get-Process

Все основные функции, о которых мы говорили, по-прежнему применяются для массивов объектов с некоторыми оговорками.All of the basic features we already talked about still apply to arrays of objects with a few details worth pointing out.

Доступ к свойствамAccessing properties

Можно использовать индекс для доступа к отдельному элементу в коллекции, как и в случае с типами значений.We can use an index to access an individual item in a collection just like with value types.

PS> $data[0]

FirstName LastName
-----     ----
Kevin     Marquette

Мы можем напрямую получать доступ к свойствам и обновлять их.We can access and update properties directly.

PS> $data[0].FirstName

Kevin

PS> $data[0].FirstName = 'Jay'
PS> $data[0]

FirstName LastName
-----     ----
Jay       Marquette
Свойства массиваArray properties

Обычно для доступа ко всем свойствам необходимо перечислить весь список следующим образом:Normally you would have to enumerate the whole list like this to access all the properties:

PS> $data | ForEach-Object {$_.LastName}

Marquette
Doe

Кроме того, можно использовать командлет Select-Object -ExpandProperty.Or by using the Select-Object -ExpandProperty cmdlet.

PS> $data | Select-Object -ExpandProperty LastName

Marquette
Doe

Однако PowerShell дает возможность запрашивать LastName напрямую.But PowerShell offers us the ability to request LastName directly. PowerShell самостоятельно перечисляет все эти данные и возвращает пустой список.PowerShell enumerates them all for us and returns a clean list.

PS> $data.LastName

Marquette
Doe

Перечисление выполняется в обычном порядке, но мы избавлены от всех связанных с этим сложностей.The enumeration still happens but we don’t see the complexity behind it.

Фильтрация Where-ObjectWhere-Object filtering

Именно здесь в игру вступает Where-Object, поэтому мы можем отфильтровать и выбрать объекты, которые следует исключить из массива, с учетом их свойств.This is where Where-Object comes in so we can filter and select what we want out of the array based on the properties of the object.

PS> $data | Where-Object {$_.FirstName -eq 'Kevin'}

FirstName LastName
-----     ----
Kevin     Marquette

Можно написать тот же запрос, чтобы получить искомый FirstName.We can write that same query to get the FirstName we are looking for.

$data | Where FirstName -eq Kevin
Where()Where()

В массивах доступен метод Where(), который позволяет указать scriptblock для фильтра.Arrays have a Where() method on them that allows you to specify a scriptblock for the filter.

$data.Where({$_.FirstName -eq 'Kevin'})

Эта функция добавлена в PowerShell 4.0.This feature was added in PowerShell 4.0.

Обновление объектов в циклахUpdating objects in loops

Если применяются типы значений, единственным способом обновить массив является использование цикла, поскольку нам нужно знать индекс, чтобы заменить значение.With value types, the only way to update the array is to use a for loop because we need to know the index to replace the value. Для объектов предусмотрено больше возможностей, поскольку они относятся к ссылочным типам.We have more options with objects because they are reference types. Приведем краткий пример:Here is a quick example:

foreach($person in $data)
{
    $person.FirstName = 'Kevin'
}

Этот цикл обходит каждый объект в массиве $data.This loop is walking every object in the $data array. Поскольку объекты являются ссылочными типами, переменная $person ссылается на тот же объект, который находится в массиве.Because objects are reference types, the $person variable references the exact same object that is in the array. Таким образом, обновления для свойств применяются к исходным свойствам.So updates to its properties do update the original.

Этот способ по-прежнему не позволяет заменить весь объект.You still can’t replace the whole object this way. При попытке назначить новый объект переменной $person ссылка на переменную обновляется на другой элемент, который больше не указывает на исходный объект в массиве.If you try to assign a new object to the $person variable, you’re updating the variable reference to something else that no longer points to the original object in the array. То есть это работает не так, как вы ожидали:This doesn’t work like you would expect:

foreach($person in $data)
{
    $person = [pscustomobject]@{
        FirstName='Kevin'
        LastName='Marquette'
    }
}

ОператорыOperators

Операторы в PowerShell также эффективны для массивов.The operators in PowerShell also work on arrays. Некоторые из них работают несколько иначе.Some of them work slightly differently.

-join-join

Оператор -join является самым очевидным примером, поэтому давайте рассмотрим его первым.The -join operator is the most obvious one so let’s look at it first. Мне нравится оператор -join, я его часто использую.I like the -join operator and use it often. Он объединяет все элементы в массиве с помощью заданного символа или строки.It joins all elements in the array with the character or string that you specify.

PS> $data = @(1,2,3,4)
PS> $data -join '-'
1-2-3-4
PS> $data -join ','
1,2,3,4

В операторе -join мне особенно нравится то, что он обрабатывает единичные элементы.One of the features that I like about the -join operator is that it handles single items.

PS> 1 -join '-'
1

Я использую его для ведения журнала и подробных сообщений.I use this inside logging and verbose messages.

PS> $data = @(1,2,3,4)
PS> "Data is $($data -join ',')."
Data is 1,2,3,4.
-join $array-join $array

Вот еще один полезный прием, о котором мне рассказал Ли Дейли.Here is a clever trick that Lee Dailey pointed out to me. Если нужно объединить все без использования разделителя, вместо этого:If you ever want to join everything without a delimiter, instead of doing this:

PS> $data = @(1,2,3,4)
PS> $data -join $null
1234

Можно использовать -join с массивом в качестве параметра без префикса.You can use -join with the array as the parameter with no prefix. Этот пример наглядно демонстрирует то, о чем я говорил.Take a look at this example to see that I’m talking about.

PS> $data = @(1,2,3,4)
PS> -join $data
1234

-replace и -split-replace and -split

Другие операторы, такие как -replace и -split, выполняются для каждого элемента в массиве.The other operators like -replace and -split execute on each item in the array. Не скажу, что я их когда-нибудь таким образом использовал, но вот пример этого.I can’t say that I have ever used them this way but here is an example.

PS> $data = @('ATX-SQL-01','ATX-SQL-02','ATX-SQL-03')
PS> $data -replace 'ATX','LAX'
LAX-SQL-01
LAX-SQL-02
LAX-SQL-03

-contains-contains

Оператор -contains позволяет проверить массив значений, чтобы определить, содержит ли он указанное значение.The -contains operator allows you to check an array of values to see if it contains a specified value.

PS> $data = @('red','green','blue')
PS> $data -contains 'green'
True

-in-in

Если одно значение, которое вам нужно проверить, совпадает с одним или несколькими значениями, можно использовать оператор -in.When you have a single value that you would like to verify matches one of several values, you can use the -in operator. Значение должно быть в левой, а массив — в правой части оператора.The value would be on the left and the array on the right-hand side of the operator.

PS> $data = @('red','green','blue')
PS> 'green' -in $data
True

Такой способ может оказаться дорогостоящим, если список достаточно велик.This can get expensive if the list is large. Я часто использую шаблон регулярного выражения, если проверяется большое количество значений.I often use a regex pattern if I’m checking more than a few values.(red|green|blue)$

PS> ‘green’ -match $pattern
True

-eq и -ne-eq and -ne

Равенство и массивы могут оказаться достаточно сложными.Equality and arrays can get complicated. Если массив располагается в левой части, выполняется сравнение всех элементов.When the array is on the left side, every item gets compared. Вместо возврата True возвращается совпадающий объект.Instead of returning True, it returns the object that matches.

PS> $data = @('red','green','blue')
PS> $data -eq 'green'
green

Если используется оператор -ne, вы получаете все значения, которые не равны имеющемуся.When you use the -ne operator, we get all the values that are not equal to our value.

PS> $data = @('red','green','blue')
PS> $data -ne 'green'
red
blue

При использовании в операторе if() возвращается значение True.When you use this in an if() statement, a value that is returned is a True value. Если значение не возвращается, то речь о значении False.If no value is returned, then it’s a False value. Оба этих оператора оцениваются как True.Both of these next statements evaluate to True.

$data = @('red','green','blue')
if ( $data -eq 'green' )
{
    'Green was found'
}
if ( $data -ne 'green' )
{
    'And green was not found'
}

Я еще вернусь к этому вопросу позднее, когда мы будем говорить о тестировании $null.I’ll revisit this in a moment when we talk about testing for $null.

-match-match

Оператор -match пытается сопоставить все элементы в коллекции.The -match operator tries to match each item in the collection.

PS> $servers = @(
    'LAX-SQL-01'
    'LAX-API-01'
    'ATX-SQL-01'
    'ATX-API-01'
)
PS> $servers -match 'SQL'
LAX-SQL-01
ATX-SQL-01

При использовании -match с одним значением специальная переменная $Matches заполняется сведениями о соответствии.When you use -match with a single value, a special variable $Matches gets populated with match info. Этого не происходит, если массив обрабатывается таким образом.This isn’t the case when an array is processed this way.

Этот же подход можно использовать в случае с Select-String.We can take the same approach with Select-String.

$servers | Select-String SQL

Я подробно расскажу о переменных Select-String, -match и $matches в другой публикации под названием Множество способов использования регулярных выражений (Множество способов использования регулярных выражений).I take a closer look at Select-String,-match and the $matches variable in another post called The many ways to use regex.

$null или empty$null or empty

Проверка на наличие $null или пустых массивов может быть непростой задачей.Testing for $null or empty arrays can be tricky. Далее описаны самые распространенные проблемы, связанные с массивами.Here are the common traps with arrays.

На первый взгляд этот оператор выглядит вполне работоспособным.At a glance, this statement looks like it should work.

if ( $array -eq $null)
{
    'Array is $null'
}

Однако я только что рассказал, как -eq проверяет каждый элемент в массиве.But I just went over how -eq checks each item in the array. Таким образом, у нас может быть массив из нескольких элементов с одним значением $null и результатом вычисления будет $trueSo we can have an array of several items with a single $null value and it would evaluate to $true

$array = @('one',$null,'three')
if ( $array -eq $null)
{
    'I think Array is $null, but I would be wrong'
}

Именно поэтому рекомендуется размещать $null в левой части оператора.This is why it’s a best practice to place the $null on the left side of the operator. Благодаря этому сценарий выполняется без проблем.This makes this scenario a non-issue.

if ( $null -eq $array )
{
    'Array actually is $null'
}

Массив $null не равен пустому массиву.A $null array isn’t the same thing as an empty array. Если вы уверены, что у вас есть массив, проверьте количество объектов в нем.If you know you have an array, check the count of objects in it. Если это массив $null, число объектов равно 0.If the array is $null, the count is 0.

if ( $array.count -gt 0 )
{
    "Array isn't empty"
}

Однако есть еще одна сложность, которую нужно учитывать в этом случае.There is one more trap to watch out for here. Можно использовать count даже при наличии одного объекта, если только этот объект не является PSCustomObject.You can use the count even if you have a single object, unless that object is a PSCustomObject. Эта ошибка исправлена в PowerShell 6.1.This is a bug that is fixed in PowerShell 6.1.
Это хорошая новость, однако многие люди по-прежнему используют версию 5.1, так что им стоит иметь в виду указанную ошибку.That’s good news, but a lot of people are still on 5.1 and need to watch out for it.

PS> $object = [PSCustomObject]@{Name='TestObject'}
PS> $object.count
$null

Если вы по-прежнему используете PowerShell 5.1, можно перенести объект в массив перед проверкой количества объектов, чтобы получить точное число.If you’re still on PowerShell 5.1, you can wrap the object in an array before checking the count to get an accurate count.

if ( @($array).count -gt 0 )
{
    "Array isn't empty"
}

Чтобы безопасно воспроизвести этот сценарий, проверьте $null, а затем проверьте число объектов.To fully play it safe, check for $null, then check the count.

if ( $null -ne $array -and @($array).count -gt 0 )
{
    "Array isn't empty"
}

All -eqAll -eq

Недавно кто-то спрашивал, как проверить, соответствует ли каждое значение в массиве заданному значению.I recently saw someone ask how to verify that every value in an array matches a given value.
Пользователь Reddit /u/bis предложил это разумное решение, которое проверяет наличие некорректных значений, а затем инвертирует результат.Reddit user /u/bis had this clever solution that checks for any incorrect values and then flips the result.

$results = Test-Something
if ( -not ( $results -ne 'Passed') )
{
    'All results a Passed'
}

Добавление в массивыAdding to arrays

На этом этапе вас начинает интересовать, как добавить элементы в массив.At this point, you’re starting to wonder how to add items to an array. Собственно говоря, никак.The quick answer is that you can’t. Массив имеет фиксированный размер в памяти.An array is a fixed size in memory. Если необходимо увеличить массив или добавить в него один элемент, то в этом случае необходимо создать новый массив и скопировать в него все значения из старого.If you need to grow it or add a single item to it, then you need to create a new array and copy all the values over from the old array. На первый взгляд это требует значительных усилий, однако PowerShell значительно упрощает создание нового массива.This sounds like a lot of work, however, PowerShell hides the complexity of creating the new array. В PowerShell реализован оператор сложения (+) для массивов.PowerShell implements the addition operator (+) for arrays.

Примечание

В PowerShell не реализована операция вычитания.PowerShell does not implement a subtraction operation. Если требуется гибкая альтернатива массиву, необходимо использовать универсальный объект List.If you want a flexible alternative to an array, you need to use a generic List object.

Сложение массивовArray addition

Для создания нового массива можно использовать оператор сложения.We can use the addition operator with arrays to create a new array. Итак, дано два массива:So given these two arrays:

$first = @(
    'Zero'
    'One'
)
$second = @(
    'Two'
    'Three'
)

Мы можем сложить их вместе, чтобы получить новый массив.We can add them together to get a new array.

PS> $first + $second

Zero
One
Two
Three

Плюс равно (+=)Plus equals +=

Мы можем создать новый массив и добавить в него элемент следующим образом:We can create a new array in place and add an item to it like this:

$data = @(
    'Zero'
    'One'
    'Two'
    'Three'
)
$data += 'four'

Просто помните, что каждый раз, когда вы используете +=, выполняется дублирование и создание нового массива.Just remember that every time you use += that you’re duplicating and creating a new array. Это не проблема, если речь идет о небольших наборах данных, но масштабирование в этом случае выполняется очень ограниченно.This is a not an issue for small datasets but it scales extremely poorly.

Назначение конвейераPipeline assignment

Можно назначить результаты любого конвейера для добавления в любую переменную.You can assign the results of any pipeline into a variable. Она будет считаться массивом, если содержит несколько элементов.It’s an array if it contains multiple items.

$array = 1..5 | ForEach-Object {
    "ATX-SQL-$PSItem"
}

Обычно если мы говорим об использовании конвейера, мы подразумеваем типичные однострочные сценарии PowerShell.Normally when we think of using the pipeline, we think of the typical PowerShell one-liners. Можно использовать конвейер с операторами foreach() и другими циклами.We can leverage the pipeline with foreach() statements and other loops. Таким образом, вместо добавления элементов в массив в цикле можно поместить элементы в конвейер.So instead of adding items to an array in a loop, we can drop items onto the pipeline.

$array = foreach ( $node in (1..5))
{
    "ATX-SQL-$node"
}

Типы массивовArray Types

По умолчанию массив в PowerShell создается как тип [PSObject[]].By default, an array in PowerShell is created as a [PSObject[]] type. Благодаря этому он может содержать любые типы объектов и значений.This allows it to contain any type of object or value. Это возможно, поскольку все наследуется из типа PSObject.This works because everything is inherited from the PSObject type.

Строго типизированные массивыStrongly typed arrays

Массив любого типа можно создать с помощью сходного синтаксиса.You can create an array of any type using a similar syntax. Если вы создаете строго типизированный массив, он может содержать только значения или объекты заданного типа.When you create a strongly typed array, it can only contain values or objects the specified type.

PS> [int[]] $numbers = 1,2,3
PS> [int[]] $numbers2 = 'one','two','three'
ERROR: Cannot convert value "one" to type "System.Int32". Input string was not in a correct format."

PS> [string[]] $strings = 'one','two','three'

ArrayListArrayList

Добавление элементов в массив накладывает самые серьезные ограничения, однако существует ряд других коллекций, которые можно использовать для решения этой проблемы.Adding items to an array is one of its biggest limitations, but there are a few other collections that we can turn to that solve this problem.

Как правило, если нам нужен массив, поддерживающий более быструю работу, мы в первую очередь вспоминаем о ArrayList.The ArrayList is commonly one of the first things that we think of when we need an array that is faster to work with. Он выступает в качестве массива объектов везде, где это необходимо, и при этом поддерживает быстрое добавление элементов.It acts like an object array every place that we need it, but it handles adding items quickly.

Мы создаем ArrayList и добавляем в него элементы следующим образом.Here is how we create an ArrayList and add items to it.

$myarray = [System.Collections.ArrayList]::new()
[void]$myArray.Add('Value')

Для получения этого типа вызывается .NET.We are calling into .NET to get this type. В этом случае для его создания используется конструктор по умолчанию.In this case, we are using the default constructor to create it. Затем вызывается метод Add, чтобы добавить в него элемент.Then we call the Add method to add an item to it.

Причина, по которой я использую [void] в начале строки, заключается в подавлении кода возврата.The reason I’m using [void] at the beginning of the line is to suppress the return code. Некоторые вызовы .NET выполняют такую функцию, и в результате могут быт получены неожиданные выходные данные.Some .NET calls do this and can create unexpected output.

Если единственными данными в массиве являются строки, ознакомьтесь также с использованием StringBuilder.If the only data that you have in your array is strings, then also take a look at using StringBuilder. Это практически то же самое, но некоторые методы предназначены только для работы со строками.It’s almost the same thing but has some methods that are just for dealing with strings. StringBuilder специально предназначен для повышения производительности.The StringBuilder is specially designed for performance.

Обычно пользователи переходят на ArrayList с массивов.It’s common to see people move to ArrayList from arrays. Однако это наследие тех времен, когда в C# еще не была предусмотрена универсальная поддержка.But it comes from a time where C# didn’t have generic support. От ArrayList отказываются в пользу универсального List[]The ArrayList is deprecated in support for the generic List[]

Универсальный списокGeneric List

Универсальный тип — это особый тип в C#, который определяет обобщенный класс, при этом пользователь указывает типы данных, которые используются в процессе создания.A generic type is a special type in C# that defines a generalized class and the user specifies the data types it uses when created. Поэтому если требуется список чисел или строк, необходимо определить, что требуется список типов int или string.So if you want a list of numbers or strings, you would define that you want list of int or string types.

Список для строк создается следующим образом.Here is how you create a List for strings.

$mylist = [System.Collections.Generic.List[string]]::new()

Так же создается список чисел.Or a list for numbers.

$mylist = [System.Collections.Generic.List[int]]::new()

Можно привести существующий массив к списку следующим образом, не создавая сначала объект:We can cast an existing array to a list like this without creating the object first:

$mylist = [System.Collections.Generic.List[int]]@(1,2,3)

Синтаксис можно сократить с помощью оператора using namespace в PowerShell 5 и более поздних версиях.We can shorten the syntax with the using namespace statement in PowerShell 5 and newer. Оператор using должен быть первой строкой сценария.The using statement needs to be the first line of your script. Объявляя пространство имен, PowerShell позволяет исключить из него типы данных при ссылке на них.By declaring a namespace, PowerShell lets you leave it off of the data types when you reference them.

using namespace System.Collections.Generic
$myList = [List[int]]@(1,2,3)

Это позволяет сделать List гораздо более удобным.This makes the List much more usable.

Вам доступен аналогичный метод Add.You have a similar Add method available to you. В отличие от ArrayList метод Add не возвращает значение, поэтому для него не нужно выполнять void.Unlike the ArrayList, there is no return value on the Add method so we don’t have to void it.

$myList.Add(10)

Кроме того, мы по-прежнему можем получить доступ к таким элементам, как другие массивы.And we can still access the elements like other arrays.

PS> $myList[-1]
10
List[PSObject]List[PSObject]

Можно получить список любого типа, но, если вам неизвестен тип объектов, в качестве контейнера для них можно использовать [List[PSObject]].You can have a list of any type, but when you don’t know the type of objects, you can use [List[PSObject]] to contain them.

$list = [List[PSObject]]::new()
Remove()Remove()

Как ArrayList, так и универсальные List[] поддерживают удаление элементов из коллекции.The ArrayList and the generic List[] both support removing items from the collection.

using namespace System.Collections.Generic
$myList = [List[string]]@('Zero','One','Two','Three')
[void]$myList.Remove("Two")
Zero
One
Three

При работе с типами значений из списка удаляется первый из типов.When working with value types, it removes the first one from the list. Его можно вызвать снова, чтобы еще раз удалить это значение.You can call it over and over again to keep removing that value. Если используются ссылочные типы, необходимо предоставить объект, который требуется удалить.If you have reference types, you have to provide the object that you want removed.

[list[System.Management.Automation.PSDriveInfo]]$drives = Get-PSDrive
$drives.remove($drives[2])
$delete = $drives[2]
$drives.remove($delete)

Метод Remove возвращает true, если удалось найти и удалить элемент из коллекции.The remove method returns true if it was able to find and remove the item from the collection.

Другие коллекцииMore collections

Можно использовать также множество других коллекций, однако эти оптимальны в качестве замены массивам.There are many other collections that can be used but these are the good generic array replacements.
Если вам интересно узнать больше о других вариантах, взгляните на Gist, собранный Марком Краусом.If you’re interested in learning about more of these options, take a look at this Gist that Mark Kraus put together.

Другие особенностиOther nuances

Итак, мы рассмотрели все основные функции, и вот еще кое-что, о чем я хотел рассказать, прежде чем мы закончим.Now that I have covered all the major functionality, here are a few more things that I wanted to mention before I wrap this up.

Массивы с предварительно заданным размеромPre-sized arrays

Я уже говорил, что вы не сможете изменить размер массива после того, как он создан.I mentioned that you can’t change the size of an array once it’s created. Можно создать массив с предварительно заданным размером, вызвав его с помощью конструктора new($size).We can create an array of a pre-determined size by calling it with the new($size) constructor.

$data = [Object[]]::new(4)
$data.count
4

Умножение массивовMultiplying arrays

Еще один интересный прием — массив можно умножить на целое число.An interesting little trick is that you can multiply an array by an integer.

PS> $data = @('red','green','blue')
PS> $data * 3
red
green
blue
red
green
blue
red
green
blue

Инициализация с нулевыми значениямиInitialize with 0

Один из распространенных сценариев предполагает создание массива, заполненного нулевыми значениями.A common scenario is that you want to create an array with all zeros. Если планируется использовать только целые числа, строго типизированный массив целых чисел по умолчанию принимает все значения равными нулю.If you’re only going to have integers, a strongly typed array of integers defaults to all zeros.

PS> [int[]]::new(4)
0
0
0
0

Для этого также можно использовать умножение.We can use the multiplying trick to do this too.

PS> $data = @(0) * 4
PS> $data
0
0
0
0

Особенно полезно в умножении то, что можно использовать любое значение.The nice thing about the multiplying trick is that you can use any value. Поэтому если планируется по умолчанию использовать значение 255, это будет хорошим вариантом.So if you would rather have 255 as your default value, this would be a good way to do it.

PS> $data = @(255) * 4
PS> $data
255
255
255
255

Вложенные массивыNested arrays

Массив внутри массива называется вложенным массивом.An array inside an array is called a nested array. Я не использую их в PowerShell, но часто использовал в других языках.I don’t use these much in PowerShell but I have used them more in other languages. Использовать массив массивов рекомендуется, если данные вписываются в шаблон типа сетки.Consider using an array of arrays when your data fits in a grid like pattern.

Существует два способа создания двумерного массива.Here are two ways we can create a two-dimensional array.

$data = @(@(1,2,3),@(4,5,6),@(7,8,9))

$data2 = @(
    @(1,2,3),
    @(4,5,6),
    @(7,8,9)
)

В этих примерах очень важно использовать запятую.The comma is very important in those examples. Ранее я приводил пример обычного массива из нескольких строк, где использование запятой не было обязательным.I gave an earlier example of a normal array on multiple lines where the comma was optional. В случае с многомерным массивом все иначе.That isn’t the case with a multi-dimensional array.

Для вложенного массива нотация индексов имеет некоторые изменения.The way we use the index notation changes slightly now that we’ve a nested array. Мы получаем значение 3, используя $data выше.Using the $data above, this is how we would access the value 3.

PS> $outside = 0
PS> $inside = 2
PS> $data[$outside][$inside]
3

Добавьте набор скобок для каждого уровня вложенности массива.Add a set of bracket for each level of array nesting. Первый набор квадратных скобок предназначен для внешнего массива, а после этого можно работать уже из него.The first set of brackets is for the outer most array and then you work your way in from there.

Write-Output -NoEnumerateWrite-Output -NoEnumerate

В PowerShell часто используется перечисление массивов и их разворачивание.PowerShell likes to unwrap or enumerate arrays. Это ключевой момент в использовании конвейера в PowerShell, однако бывают случаи, когда это нежелательно.This is a core aspect of the way PowerShell uses the pipeline but there are times that you don’t want that to happen.

Обычно я передаю объекты в Get-Member, чтобы получить дополнительные сведения о них.I commonly pipe objects to Get-Member to learn more about them. Когда я передаю туда массив, выполняется его разворачивание, и Get-Member видит элементы массива, а не фактический массив.When I pipe an array to it, it gets unwrapped and Get-Member sees the members of the array and not the actual array.

PS> $data = @('red','green','blue')
PS> $data | Get-Member
TypeName: System.String
...

Чтобы запретить разворачивание массива, можно использовать Write-Object -NoEnumerate.To prevent that unwrap of the array, you can use Write-Object -NoEnumerate.

PS> Write-Output -NoEnumerate $data | Get-Member
TypeName: System.Object[]
...

Есть еще один способ, который больше напоминает взлом (а я пытаюсь избежать таких взломов).I have a second way that’s more of a hack (and I try to avoid hacks like this). Перед передачей массива можно поставить запятую в его начале.You can place a comma in front of the array before you pipe it.

PS> ,$data | Get-Member
TypeName: System.Object[]
...

Возврат массиваReturn an array

Такое разворачивание массивов также выполняется при выводе или возврате значений из функции.This unwrapping of arrays also happens when you output or return values from a function. Для получения массива по-прежнему можно присвоить выходные данные переменной, что обычно не вызывает проблем.You can still get an array if you assign the output to a variable so this isn’t commonly an issue.

Хитрость в том, что создается новый массив.The catch is that you have a new array. Если это проблематично, можно решить проблему с помощью Write-Output -NoEnumerate $array или return ,$array.If that is ever a problem, you can use Write-Output -NoEnumerate $array or return ,$array to work around it.

Что-нибудь еще?Anything else?

Я знаю, что придется усвоить довольно большой объем информации.I know this is all a lot to take in. Но я надеюсь, что при каждом прочтении этой статьи вы будете узнавать что-то новое и эти знания окажутся полезными в долгосрочной перспективе.My hope is that you learn something from this article every time you read it and that it turns out to be a good reference for you for a long time to come. Если для вас эта статья была полезна, поделитесь ею с коллегами, которым она также может быть интересна.If you found this to be helpful, please share it with others you think may get value out of it.

Здесь, кстати, я рекомендую ознакомиться с похожей публикацией, посвященной хэш-таблицам.From here, I would recommend you check out a similar post that I wrote about hashtables.



Основы PowerShell: массивы и таблицы хеширования | Windows IT Pro/RE

Массивы и таблицы хеширования – две наиболее важных структуры данных, доступные в современных языках написания сценариев. Оболочка Windows PowerShell (http://www.windowsitpro.com/topics/powershell-scripting) поддерживает обе эти структуры. Массив, который иногда называют «коллекцией», содержит список элементов. Таблица хеширования, которую еще называют «словарем» или «массивом ассоциаций», содержит списки пар элементов. Далее в статье я покажу, как создавать массивы и таблицы хеширования, а также получать доступ к их элементам.

Создание массива

Массивы полезны в тех случаях, когда вы собираетесь хранить и просматривать список или коллекцию элементов. Один из простейших способов создать массив – использовать команду PowerShell, которая выводит более одного объекта. Например, в результате простого запуска команды Get-ChildItem будет выведен список объектов в текущем расположении. Этот список может быть сохранен в переменной. Если текущее расположение содержит более одного объекта, переменная, в которой вы сохранили список, становится массивом. Это действительно просто. Например, рассмотрим следующую команду PowerShell:

$list = Get-ChildItem $ENV:SystemRoot

После выполнения этой команды переменная $list содержит массив объектов FileInfo и DirectoryInfo.

Другой способ создать массив – указать объекты, разделив их запятыми, и присвоить их переменной:

$list = «A",»B«,"C»,«1",»2«,"3»

Доступ к элементам массива

Существует три способа обращения к элементам массива.

  • Использование инструкции foreach. Инструкция foreach оболочки PowerShell предоставляет удобный способ обращения к любому элементу массива. Например, чтобы вывести на экран элемент массива $list, нужно запустить команду:
foreach ( $item in $list ) { $item }
  • Использование команды ForEach-Object. Команда ForEach-Object рассматривает массив как входные данные из конвейера и передает каждый объект массива в блок сценария для обработки. Текущий элемент массива представлен специальной переменной $_. Чтобы вывести на экран элемент массива $list с помощью команды ForEach-Object, используйте команду:
$list | ForEach-Object { $_ }
  • Применение инструкции с номером индекса. К каждому объекту (элементу) массива можно обратиться по соответствующему номеру, начиная с 0. Например, выражение $list[0] ссылается на первый элемент в массиве, выражение $list[1] ссылается на второй элемент, и так далее. Так, чтобы вывести на экран каждый член массива с помощью инструкции for и номера индекса, запустите команду:
for ( $i = 0; $i -lt $list.Count; $i++ ) {
$list[$i]
}

Из этих трех подходов способ с индексами используется реже всего. Основная причина в том, что инструкция foreach и команда ForEach-Object обеспечивают более быстрое выполнение задачи.

При изучении этих трех подходов основной вопрос звучит так: в чем разница между использованием инструкции foreach и команды ForEach-Object? Разница в первую очередь в том, что при использовании инструкции foreach необходимо извлечь все элементы массива, прежде чем вы сможете получить доступ к ним. И наоборот, команда ForEach-Object использует преимущества конвейера PowerShell, позволяя получить доступ сразу к отдельному элементу.

Какой же из подходов выбрать? Ответ зависит от элементов массива. Если у вас сравнительно небольшое количество элементов массива и извлечение не займет много времени, инструкция foreach будет работать отлично. Если же у вас большой список элементов и извлечение элементов требует значительного времени (например, файлы на удаленном файловом сервере), вы, скорее всего, захотите использовать команду ForEach-Object. Также стоит подумать о применении команды Write-Progress. Если вы хотите задействовать эту команду в сценарии, чтобы информировать пользователя о ходе выполнения операции, вам придется предварительно извлечь все объекты с помощью инструкции foreach – это необходимо для расчета процента выполненной работы.

Есть еще один момент, из-за которого могут возникнуть затруднения при выборе между инструкцией foreach и командой ForEach-Object: псевдонимом команды ForEach-Object является ключевое слово foreach! Не забывайте, что при использовании выражения foreach после вертикальной черты (|) в конвейере PowerSh ell на самом деле вы вызываете команду ForEach-Object.

Другое затруднение, связанное с массивами, может проявиться, если вы знакомы с языками VBScript или JavaScript. В этих двух языках написания сценариев массивы и коллекции являются разными типами объектов. Однако в оболочке PowerShell вы можете рассматривать их как одно и то же.

Создание таблицы хеширования

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

Вы можете создать таблицу хеширования путем указания имени и значения между символами @{ и }. Например, чтобы создать таблицу хеширования, которая содержит имена трех серверов и их IP-адреса, следует выполнить команду:

$hash = @{«server1» = «192.168.17.21»;
«server2» = «192.168.17.22»;
«server3» = «192.168.17.23»}

Если вывести эту таблицу хеширования на экран (просто написать $hash в строке PowerShell и нажать клавишу ввода), вы увидите результаты, приведенные на рисунке. Заметьте, что оболочка PowerShell выводит данные столбца Name в произвольном порядке. Одна из особенностей таблицы хеширования заключается в том, что именованные элементы не имеют определенного порядка.

 

Рисунок. Таблица хэширования

Доступ к элементам таблицы хеширования

Чтобы получить значение из таблицы хеширования, вы можете указать имя таблицы хеширования и далее имя элемента, значение которого вы хотите получить, заключенное в квадратные скобки. Либо вы можете поставить точку между именем таблицы и именем элемента, значение которого вы хотите получить. Например, для созданной ранее переменной $hash любая из приведенных ниже команд вернет значение 192.168.17.21:

$hash[«server1»]
$hash.server1
$hash.«server1»

Имейте в виду, что кавычки в команде $hash[«server1»] необходимы. Без них оболочка PowerShell не сможет получить информацию о том, каким образом обрабатывать ключ server1. Однако если имя сервера хранится в переменной (например, $serverName), вы можете применить команду:

$hash[$serverName]

Некоторые команды PowerShell используют таблицы хеширования в качестве значений для параметров. Например, команда Select-Object задействует таблицы хеширования для вывода на экран вычисляемых свойств. Чтобы использовать таблицу хеширования при создании вычисляемого свойства для команды Select-Object, она должна иметь два парных значения: Name, которое задает имя вычисляемого свойства, и Expression, которое содержит блок сценариев, отвечающий за вычисление свойства. Например, возьмем команду:

Get-ChildItem $ENV:SystemRoot | select-object Name,
LastWriteTime, @{Name=«Day»;
Expression={$_.LastWriteTime.DayOfWeek}}

В этом случае команда Select-Object выведет имя, время последней записи и день недели для каждого файла и каталога в установочной папке Windows. Как и в случае с командой ForEach-Object, специальная переменная $_ ссылается на текущий объект.

.

Поделитесь материалом с коллегами и друзьями

Одномерные массивы в PowerShell

Индексы значений массивов начинаются с нуля

PS C:\> $arr1 = 1,2,3,4,5,6,7,8,9,10 # Объявляем числовой массив
PS C:\> $arr2 = "A", "B", "C", "D", "E", "F", "G" # Объявляем текстовый массив
PS C:\>
PS C:\> Write-Host $arr1 # Таким образом мы увидим значения массива в строчку
1 2 3 4 5 6 7 8 9 10
PS C:\> Write-Host $arr2
A B C D E F G
PS C:\> $arr1 # Таким образом мы увидим значения массива в столбик
1
2
3
4
5
6
7
8
9
10
PS C:\> $arr2
A
B
C
D
E
F
G
PS C:\>
PS C:\> $arr1[0] # Выберем из массива первый элемент
1
PS C:\> $arr1[1] # Выберем из массива второй элемент
2
PS C:\> $arr1[9] # Выберем из массива последний элемент
10
PS C:\> '{9}' -f $arr1 # Другой способ выбора элементов массива
10
PS C:\> $arr1[-1] # С помощью знака "минус" можно выбирать элементы начиная с конца массива
10
PS C:\> $arr1[-3]
8
PS C:\> $arr1[0,4,9] # Выбираем сразу несколько элементов из массива
1
5
10
PS C:\> $arr2[0..3] # Выбираем диапазон значений начиная с первого и заканчивая четвертым
A
B
C
D
PS C:\> $arr1[3..-2] # Выборка диапазона в обратном порядке, начиная с четвертого, затем третьего и заканчивая предпоследним
4
3
2
1
10
9
PS C:\> $arr1[0..2+7..9] # Выберем несколько диапазонов сразу с помощью знака "плюс"
1
2
3
8
9
10

Cast-объявление массивов

PS C:\> $arr3 = @(1,2,3,4,5,6,7,8,9,10) # Символ "собачка" перед скобками является явным указанием массива
PS C:\>
PS C:\> $arr4 = @(Get-Process -Name "powershell_ise" ; Get-Date -Format dd:mm:yyy ; Get-Service | Select-Object -First 1 | Format-Table -AutoSize -Wrap) # Значения массива можно разделять и символом "точка с запятой", если эти значения являются командлетами, то их не нужно заключать в кавычки
PS C:\>
PS C:\> $arr4 # При вызове массива, значениями которого являются командлеты, последние будут выполнены

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    736      76   363420     223660  1015 1 162,69   4536 powershell_ise


17:58:2013


Status  Name            DisplayName
------  ----            -----------
Running AdobeARMservice Adobe Acrobat Update Service


Управление элементами массивов

PS C:\> $arr5 = @("One"; "Two"; "Three"; "Four"; "Five") # Объявим текстовый массив
PS C:\>
PS C:\> $arr1 # Посмотрим на значения ранее созданного числового массива
1
2
3
4
5
6
7
8
9
10
 # МОДИФИКАЦИЯ
PS C:\> $arr1[8] # Выведем на экран значение массива с индексом 8
9
PS C:\> $arr1[8] = 34 # Заменим значение с индексом 8 на новое
PS C:\> $arr1 # Как видно, предпоследний элемент массива поменялся
1
2
3
4
5
6
7
8
34
10
 # ДОБАВЛЕНИЕ В КОНЕЦ МАССИВА
PS C:\>
PS C:\> $arr5
One
Two
Three
Four
Five
PS C:\> $arr5 += "Six" # Добавим в конец одномерного массива еще одно значение
PS C:\> $arr5
One
Two
Three
Four
Five
Six
 # ДОБАВЛЕНИЕ В СЕРЕДИНУ МАССИВА
PS C:\> 
PS C:\> $arr1
1
2
3
4
5
6
7
8
34
10
PS C:\> $arr1 = $arr1[0..7] + 9 + $arr1[8..10] # Добавление значения в массив arr1 на место между индексами 7 и 8
PS C:\> $arr1
1
2
3
4
5
6
7
8
9
34
10
 # УДАЛЕНИЕ ЗНАЧЕНИЯ ИЗ МАССИВА
PS C:\>
PS C:\> $arr1
1
2
3
4
5
6
7
8
9
34
10
PS C:\>
PS C:\> $arr1 = $arr1[0..3] + $arr1[5..10] # Удаление элемента с индексом 4 из массива arr1
PS C:\> $arr1
1
2
3
4
6
7
8
9
34
10

PowerShell-Docs.ru-ru/everything-about-arrays.md at live · MicrosoftDocs/PowerShell-Docs.ru-ru · GitHub

titledescriptionms.datems.customms.openlocfilehashms.sourcegitcommitms.translationtypems.contentlocalems.lasthandoffms.locfileid

Все, что вы хотели знать о массивах

Массивы являются основополагающей функцией большинства языков программирования.

10/08/2020

contributor-KevinMarquette

b26aa11aadbeea1984b2754cfcad061c7fa3ff1e

ba7315a496986451cfc1296b659d73ea2373d3f0

HT

ru-RU

12/10/2020

91852567

Массивы являются основополагающей функцией большинства языков программирования. Они представляют собой коллекцию значений или объектов, с которыми вы, скорее всего, рано или поздно обязательно столкнетесь. Давайте рассмотрим массивы и все доступные в них возможности.

[!NOTE]
Оригинал этой статьи впервые был опубликован в блоге автора @KevinMarquette. Группа разработчиков PowerShell благодарит Кевина за то, что он поделился с нами этими материалами. Ознакомьтесь с его блогом на веб-сайте PowerShellExplained.com.

Что такое массив?

Я начну с основного технического описания массивов и способов их использования в большинстве языков программирования, а затем расскажу о других вариантах их использования в PowerShell.

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

Далее я расскажу обо всем этом подробнее.

Основное использование

Массивы представляют собой основную функцию PowerShell, поэтому в PowerShell предусмотрен простой синтаксис для работы с ними.

Создание массива

Для создания пустого массива можно использовать @().

PS> $data = @()
PS> $data.count
0

Мы можем создать массив и заполнить его значениями, просто заключив их в скобки @().

PS> $data = @('Zero','One','Two','Three')
PS> $data.count
4

PS> $data
Zero
One
Two
Three

В этом массиве 4 элемента. При вызове переменной $data отображается список этих элементов. Если речь о строковом массиве, в этом случае отображается по одному строковому элементу в строке.

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

$data = @(
    'Zero'
    'One'
    'Two'
    'Three'
)

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

Другой синтаксис

Известно, что @() является синтаксисом для создания массива, однако в большинстве случаев чаще используются списки с разделителями-запятыми.

$data = 'Zero','One','Two','Three'
Write-Output для создания массивов

Один из полезных трюков, о котором следует упомянуть, заключается в использовании Write-Output для быстрого создания строк в консоли.

$data = Write-Output Zero One Two Three

Это очень удобно, поскольку не нужно заключать строки в кавычки, если параметр принимает строки. В сценарии я бы этого не стал делать, но для консоли это вполне приемлемо.

Доступ к элементам

Теперь вам нужен доступ к имеющимся массивам с элементами, а также возможность обновлять их.

Offset

Для доступа к отдельным элементам используются скобки [] со значением смещения не менее 0. Мы получаем первый элемент в массиве следующим образом.

PS> $data = 'Zero','One','Two','Three'
PS> $data[0]
Zero

Причина, по которой мы используем ноль, заключается в том, что первый элемент находится в самом начале списка, поэтому, чтобы его достичь, потребуется смещение на 0 элементов. Чтобы перейти ко второму элементу, требуется смещение на 1, чтобы пропустить первый элемент.

Это означает, что для последнего элемента используется значение смещения 3.

Индекс

Теперь вы видите, почему я выбрал для примера именно эти значения. Я представил это как смещение, поскольку это по сути именно оно, однако в данном случае смещение чаще называется индексом. Это индекс, начинающийся с 0. Далее в этой статье я буду называть смещение индексом.

Специальные возможности использования индекса

В большинстве языков можно указать только одно число в качестве индекса, и в ответ вы получаете один элемент.
PowerShell дает гораздо большую гибкость. Можно использовать несколько индексов одновременно. Благодаря списку индексов можно выбрать несколько элементов.

PS> $data[0,2,3]
Zero
Two
Three

Элементы возвращаются с учетом порядка предоставляемых индексов. Если индекс дублируется, то в обоих случаях вы получите именно этот элемент.

PS> $data[3,0,3]
Three
Zero
Three

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

PS> $data[1..3]
One
Two
Three

Это работает и в обратном порядке.

PS> $data[3..1]
Three
Two
One

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

При работе с оператором .. необходимо учитывать следующее. Последовательности 0..-1 и -1..0 вычислены со значениями 0,-1 и -1,0. Легко увидеть $data[0..-1] и предположить, что там будут перечислены все элементы, если забыть об этой детали. $data[0..-1] дает то же значение, что и $data[0,-1], предоставляя первый и последний элементы в массиве (и ни одного из остальных значений).

Вне допустимого диапазона

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

PS> $null -eq $data[9000]
True
Индексирование в массив значений null невозможно

Если используется переменная $null и вы пытаетесь индексировать ее как массив, выводится исключение System.Management.Automation.RuntimeException с сообщением Cannot index into a null array.

PS> $empty = $null
SP> $empty[0]
Error: Cannot index into a null array.

Убедитесь, что массивы не являются $null, прежде чем пытаться получить доступ к элементам внутри них.

Count

Массивы и другие коллекции содержат свойство Count, которое показывает количество элементов в массиве.

В PowerShell 3.0 в большинство объектов добавляется свойство Count. У вас может быть один объект, который должен сообщать свойство Count, равное 1.

PS> $date = Get-Date
PS> $date.count
1

Даже $null имеет свойство Count, только оно возвращает 0.

Однако в этом случае есть ряд сложностей, о которых я расскажу подробнее, когда буду говорить о проверке на наличие $null или пустых массивов далее в этой статье.

Ошибка завышения или занижения на единицу

Общая ошибка программирования возникает потому, что массивы начинаются с индекса 0. Ошибки завышения/занижения на единицу можно представить двумя способами.

Первый — просто думать, что вам нужен второй элемент, использовать индекс 2 и действительно получить третий элемент. Можно также думать, что у вас четыре элемента и вам нужен последний из них, и использовать свойство Count для доступа к последнему элементу.

В PowerShell вполне достаточно сделать это и указать, какой элемент существует в индексе 4: $null. Следует использовать $data.count - 1 или -1, о которых мы говорили выше.

PS> $data[ $data.count - 1 ]
Three

В этом случае получить последний элемент можно с помощью индекса -1.

Ли Дейли также подсказал, что мы можем использовать $data.GetUpperBound(0) для получения максимального номера индекса.

PS> $data.GetUpperBound(0)
3
PS> $data[ $data.GetUpperBound(0) ]
Three

Второй наиболее распространенный способ — если вы выполняете итерацию по списку и не останавливаетесь в нужный момент. Я об этом расскажу подробнее, когда мы будем говорить об использовании цикла for.

Обновление элементов

Для обновления существующих элементов в массиве можно использовать тот же индекс. Это позволяет напрямую обновлять отдельные элементы.

$data[2] = 'dos'
$data[3] = 'tres'

При попытке обновить элемент, который находится за последним элементом, возникает ошибка Index was outside the bounds of the array..

PS> $data[4] = 'four'
Index was outside the bounds of the array.
At line:1 char:1
+ $data[4] = 'four'
+ ~~~~~~~~~~~~~
+ CategoryInfo          : OperationStopped: (:) [], IndexOutOfRangeException
+ FullyQualifiedErrorId : System.IndexOutOfRangeException

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

Итерация

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

Pipeline

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

PS> $data = 'Zero','One','Two','Three'
PS> $data | ForEach-Object {"Item: [$PSItem]"}
Item: [Zero]
Item: [One]
Item: [Two]
Item: [Three]

Если вы еще не видели $PSItem, просто помните, что это то же самое, что и $_. Можно использовать любой из них, так как оба этих элемента представляют текущий объект в конвейере.

Цикл ForEach

Цикл ForEach эффективно работает с коллекциями. Используется следующий синтаксис: foreach ( <variable> in <collection> )

foreach ( $node in $data )
{
    "Item: [$node]"
}
Метод ForEach

Я часто забываю о нем, однако этот метод эффективен для простых операций. PowerShell позволяет вызывать .ForEach() для коллекции.

PS> $data.foreach({"Item [$PSItem]"})
Item [Zero]
Item [One]
Item [Two]
Item [Three]

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

$data.foreach{"Item [$PSItem]"}

Такой синтаксис менее популярен, но он работает точно так же. Метод foreach добавлен в PowerShell 4.0.

Цикл For

Цикл for активно используется в большинстве других языков, но в PowerShell он применяется редко. Однако если он все же используется, то зачастую это происходит в контексте обхода массива.

for ( $index = 0; $index -lt $data.count; $index++)
{
    "Item: [{0}]" -f $data[$index]
}

В первую очередь мы инициализируем $index для 0. Затем мы добавляем условие, что $index должно быть меньше $data.count. Наконец, мы указываем, что при каждой обработке цикла необходимо увеличивать индекс на 1. В этом случае $index++ расшифровывается как $index = $index + 1.

При каждом использовании цикла for следует обращать особое внимание на условие. Здесь я использовал $index -lt $data.count. При этом довольно легко получить слегка неверное условие и в результате получить в логике ошибку завышения/занижения на единицу. При использовании $index -le $data.count или $index -lt ($data.count - 1) всегда получается слегка неверное условие. Это может привести к тому, что в вашем результате будет обрабатываться слишком много или слишком мало элементов. Это классическая ошибка завышения/занижения на единицу.

Цикл Switch

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

$data = 'Zero','One','Two','Three'
switch( $data )
{
    'One'
    {
        'Tock'
    }
    'Three'
    {
        'Tock'
    }
    Default
    {
        'Tick'
    }
}
Tick
Tock
Tick
Tock

С помощью оператора switch можно выполнить массу полезных действий. Об этом я подробно рассказываю в другой статье.

Обновление значений

Если массив является коллекцией строковых или целочисленных значений, в отдельных случаях требуется обновление значений в массиве в процессе их циклической обработки. В большинстве циклов, описанных выше, используется переменная в цикле, которая содержит копию значения. При обновлении этой переменной исходное значение в массиве не обновляется.

Исключением для этого оператора является цикл for. Если вам требуется обход массива и обновление значений в нем, вам нужен цикл for.

for ( $index = 0; $index -lt $data.count; $index++ )
{
    $data[$index] = "Item: [{0}]" -f $data[$index]
}

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

Массивы объектов

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

$data = @(
    [pscustomobject]@{FirstName='Kevin';LastName='Marquette'}
    [pscustomobject]@{FirstName='John'; LastName='Doe'}
)

Многие командлеты возвращают коллекции объектов в виде массивов, когда они назначаются переменной.

$processList = Get-Process

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

Доступ к свойствам

Можно использовать индекс для доступа к отдельному элементу в коллекции, как и в случае с типами значений.

PS> $data[0]

FirstName LastName
-----     ----
Kevin     Marquette

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

PS> $data[0].FirstName

Kevin

PS> $data[0].FirstName = 'Jay'
PS> $data[0]

FirstName LastName
-----     ----
Jay       Marquette
Свойства массива

Обычно для доступа ко всем свойствам необходимо перечислить весь список следующим образом:

PS> $data | ForEach-Object {$_.LastName}

Marquette
Doe

Кроме того, можно использовать командлет Select-Object -ExpandProperty.

PS> $data | Select-Object -ExpandProperty LastName

Marquette
Doe

Однако PowerShell дает возможность запрашивать LastName напрямую. PowerShell самостоятельно перечисляет все эти данные и возвращает пустой список.

PS> $data.LastName

Marquette
Doe

Перечисление выполняется в обычном порядке, но мы избавлены от всех связанных с этим сложностей.

Фильтрация Where-Object

Именно здесь в игру вступает Where-Object, поэтому мы можем отфильтровать и выбрать объекты, которые следует исключить из массива, с учетом их свойств.

PS> $data | Where-Object {$_.FirstName -eq 'Kevin'}

FirstName LastName
-----     ----
Kevin     Marquette

Можно написать тот же запрос, чтобы получить искомый FirstName.

$data | Where FirstName -eq Kevin
Where()

В массивах доступен метод Where(), который позволяет указать scriptblock для фильтра.

$data.Where({$_.FirstName -eq 'Kevin'})

Эта функция добавлена в PowerShell 4.0.

Обновление объектов в циклах

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

foreach($person in $data)
{
    $person.FirstName = 'Kevin'
}

Этот цикл обходит каждый объект в массиве $data. Поскольку объекты являются ссылочными типами, переменная $person ссылается на тот же объект, который находится в массиве. Таким образом, обновления для свойств применяются к исходным свойствам.

Этот способ по-прежнему не позволяет заменить весь объект. При попытке назначить новый объект переменной $person ссылка на переменную обновляется на другой элемент, который больше не указывает на исходный объект в массиве. То есть это работает не так, как вы ожидали:

foreach($person in $data)
{
    $person = [pscustomobject]@{
        FirstName='Kevin'
        LastName='Marquette'
    }
}

Операторы

Операторы в PowerShell также эффективны для массивов. Некоторые из них работают несколько иначе.

-join

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

PS> $data = @(1,2,3,4)
PS> $data -join '-'
1-2-3-4
PS> $data -join ','
1,2,3,4

В операторе -join мне особенно нравится то, что он обрабатывает единичные элементы.

Я использую его для ведения журнала и подробных сообщений.

PS> $data = @(1,2,3,4)
PS> "Data is $($data -join ',')."
Data is 1,2,3,4.
-join $array

Вот еще один полезный прием, о котором мне рассказал Ли Дейли. Если нужно объединить все без использования разделителя, вместо этого:

PS> $data = @(1,2,3,4)
PS> $data -join $null
1234

Можно использовать -join с массивом в качестве параметра без префикса. Этот пример наглядно демонстрирует то, о чем я говорил.

PS> $data = @(1,2,3,4)
PS> -join $data
1234

-replace и -split

Другие операторы, такие как -replace и -split, выполняются для каждого элемента в массиве. Не скажу, что я их когда-нибудь таким образом использовал, но вот пример этого.

PS> $data = @('ATX-SQL-01','ATX-SQL-02','ATX-SQL-03')
PS> $data -replace 'ATX','LAX'
LAX-SQL-01
LAX-SQL-02
LAX-SQL-03

-contains

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

PS> $data = @('red','green','blue')
PS> $data -contains 'green'
True

-in

Если одно значение, которое вам нужно проверить, совпадает с одним или несколькими значениями, можно использовать оператор -in. Значение должно быть в левой, а массив — в правой части оператора.

PS> $data = @('red','green','blue')
PS> 'green' -in $data
True

Такой способ может оказаться дорогостоящим, если список достаточно велик. Я часто использую шаблон регулярного выражения, если проверяется большое количество значений.(red|green|blue)$

PS> ‘green’ -match $pattern
True

-eq и -ne

Равенство и массивы могут оказаться достаточно сложными. Если массив располагается в левой части, выполняется сравнение всех элементов. Вместо возврата True возвращается совпадающий объект.

PS> $data = @('red','green','blue')
PS> $data -eq 'green'
green

Если используется оператор -ne, вы получаете все значения, которые не равны имеющемуся.

PS> $data = @('red','green','blue')
PS> $data -ne 'green'
red
blue

При использовании в операторе if() возвращается значение True. Если значение не возвращается, то речь о значении False. Оба этих оператора оцениваются как True.

$data = @('red','green','blue')
if ( $data -eq 'green' )
{
    'Green was found'
}
if ( $data -ne 'green' )
{
    'And green was not found'
}

Я еще вернусь к этому вопросу позднее, когда мы будем говорить о тестировании $null.

-match

Оператор -match пытается сопоставить все элементы в коллекции.

PS> $servers = @(
    'LAX-SQL-01'
    'LAX-API-01'
    'ATX-SQL-01'
    'ATX-API-01'
)
PS> $servers -match 'SQL'
LAX-SQL-01
ATX-SQL-01

При использовании -match с одним значением специальная переменная $Matches заполняется сведениями о соответствии. Этого не происходит, если массив обрабатывается таким образом.

Этот же подход можно использовать в случае с Select-String.

$servers | Select-String SQL

Я подробно расскажу о переменных Select-String, -match и $matches в другой публикации под названием Множество способов использования регулярных выражений (Множество способов использования регулярных выражений).

$null или empty

Проверка на наличие $null или пустых массивов может быть непростой задачей. Далее описаны самые распространенные проблемы, связанные с массивами.

На первый взгляд этот оператор выглядит вполне работоспособным.

if ( $array -eq $null)
{
    'Array is $null'
}

Однако я только что рассказал, как -eq проверяет каждый элемент в массиве. Таким образом, у нас может быть массив из нескольких элементов с одним значением $null и результатом вычисления будет $true

$array = @('one',$null,'three')
if ( $array -eq $null)
{
    'I think Array is $null, but I would be wrong'
}

Именно поэтому рекомендуется размещать $null в левой части оператора. Благодаря этому сценарий выполняется без проблем.

if ( $null -eq $array )
{
    'Array actually is $null'
}

Массив $null не равен пустому массиву. Если вы уверены, что у вас есть массив, проверьте количество объектов в нем. Если это массив $null, число объектов равно 0.

if ( $array.count -gt 0 )
{
    "Array isn't empty"
}

Однако есть еще одна сложность, которую нужно учитывать в этом случае. Можно использовать count даже при наличии одного объекта, если только этот объект не является PSCustomObject. Эта ошибка исправлена в PowerShell 6.1.
Это хорошая новость, однако многие люди по-прежнему используют версию 5.1, так что им стоит иметь в виду указанную ошибку.

PS> $object = [PSCustomObject]@{Name='TestObject'}
PS> $object.count
$null

Если вы по-прежнему используете PowerShell 5.1, можно перенести объект в массив перед проверкой количества объектов, чтобы получить точное число.

if ( @($array).count -gt 0 )
{
    "Array isn't empty"
}

Чтобы безопасно воспроизвести этот сценарий, проверьте $null, а затем проверьте число объектов.

if ( $null -ne $array -and @($array).count -gt 0 )
{
    "Array isn't empty"
}

All -eq

Недавно кто-то спрашивал, как проверить, соответствует ли каждое значение в массиве заданному значению.
Пользователь Reddit /u/bis предложил это разумное решение, которое проверяет наличие некорректных значений, а затем инвертирует результат.

$results = Test-Something
if ( -not ( $results -ne 'Passed') )
{
    'All results a Passed'
}

Добавление в массивы

На этом этапе вас начинает интересовать, как добавить элементы в массив. Собственно говоря, никак. Массив имеет фиксированный размер в памяти. Если необходимо увеличить массив или добавить в него один элемент, то в этом случае необходимо создать новый массив и скопировать в него все значения из старого. На первый взгляд это требует значительных усилий, однако PowerShell значительно упрощает создание нового массива. В PowerShell реализован оператор сложения (+) для массивов.

[!NOTE]
В PowerShell не реализована операция вычитания. Если требуется гибкая альтернатива массиву, необходимо использовать универсальный объект List.

Сложение массивов

Для создания нового массива можно использовать оператор сложения. Итак, дано два массива:

$first = @(
    'Zero'
    'One'
)
$second = @(
    'Two'
    'Three'
)

Мы можем сложить их вместе, чтобы получить новый массив.

PS> $first + $second

Zero
One
Two
Three

Плюс равно (+=)

Мы можем создать новый массив и добавить в него элемент следующим образом:

$data = @(
    'Zero'
    'One'
    'Two'
    'Three'
)
$data += 'four'

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

Назначение конвейера

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

$array = 1..5 | ForEach-Object {
    "ATX-SQL-$PSItem"
}

Обычно если мы говорим об использовании конвейера, мы подразумеваем типичные однострочные сценарии PowerShell. Можно использовать конвейер с операторами foreach() и другими циклами. Таким образом, вместо добавления элементов в массив в цикле можно поместить элементы в конвейер.

$array = foreach ( $node in (1..5))
{
    "ATX-SQL-$node"
}

Типы массивов

По умолчанию массив в PowerShell создается как тип [PSObject[]]. Благодаря этому он может содержать любые типы объектов и значений. Это возможно, поскольку все наследуется из типа PSObject.

Строго типизированные массивы

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

PS> [int[]] $numbers = 1,2,3
PS> [int[]] $numbers2 = 'one','two','three'
ERROR: Cannot convert value "one" to type "System.Int32". Input string was not in a correct format."

PS> [string[]] $strings = 'one','two','three'

ArrayList

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

Как правило, если нам нужен массив, поддерживающий более быструю работу, мы в первую очередь вспоминаем о ArrayList. Он выступает в качестве массива объектов везде, где это необходимо, и при этом поддерживает быстрое добавление элементов.

Мы создаем ArrayList и добавляем в него элементы следующим образом.

$myarray = [System.Collections.ArrayList]::new()
[void]$myArray.Add('Value')

Для получения этого типа вызывается .NET. В этом случае для его создания используется конструктор по умолчанию. Затем вызывается метод Add, чтобы добавить в него элемент.

Причина, по которой я использую [void] в начале строки, заключается в подавлении кода возврата. Некоторые вызовы .NET выполняют такую функцию, и в результате могут быт получены неожиданные выходные данные.

Если единственными данными в массиве являются строки, ознакомьтесь также с использованием StringBuilder. Это практически то же самое, но некоторые методы предназначены только для работы со строками. StringBuilder специально предназначен для повышения производительности.

Обычно пользователи переходят на ArrayList с массивов. Однако это наследие тех времен, когда в C# еще не была предусмотрена универсальная поддержка. От ArrayList отказываются в пользу универсального List[]

Универсальный список

Универсальный тип — это особый тип в C#, который определяет обобщенный класс, при этом пользователь указывает типы данных, которые используются в процессе создания. Поэтому если требуется список чисел или строк, необходимо определить, что требуется список типов int или string.

Список для строк создается следующим образом.

$mylist = [System.Collections.Generic.List[string]]::new()

Так же создается список чисел.

$mylist = [System.Collections.Generic.List[int]]::new()

Можно привести существующий массив к списку следующим образом, не создавая сначала объект:

$mylist = [System.Collections.Generic.List[int]]@(1,2,3)

Синтаксис можно сократить с помощью оператора using namespace в PowerShell 5 и более поздних версиях. Оператор using должен быть первой строкой сценария. Объявляя пространство имен, PowerShell позволяет исключить из него типы данных при ссылке на них.

using namespace System.Collections.Generic
$myList = [List[int]]@(1,2,3)

Это позволяет сделать List гораздо более удобным.

Вам доступен аналогичный метод Add. В отличие от ArrayList метод Add не возвращает значение, поэтому для него не нужно выполнять void.

Кроме того, мы по-прежнему можем получить доступ к таким элементам, как другие массивы.

List[PSObject]

Можно получить список любого типа, но, если вам неизвестен тип объектов, в качестве контейнера для них можно использовать [List[PSObject]].

$list = [List[PSObject]]::new()
Remove()

Как ArrayList, так и универсальные List[] поддерживают удаление элементов из коллекции.

using namespace System.Collections.Generic
$myList = [List[string]]@('Zero','One','Two','Three')
[void]$myList.Remove("Two")
Zero
One
Three

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

[list[System.Management.Automation.PSDriveInfo]]$drives = Get-PSDrive
$drives.remove($drives[2])
$delete = $drives[2]
$drives.remove($delete)

Метод Remove возвращает true, если удалось найти и удалить элемент из коллекции.

Другие коллекции

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

Другие особенности

Итак, мы рассмотрели все основные функции, и вот еще кое-что, о чем я хотел рассказать, прежде чем мы закончим.

Массивы с предварительно заданным размером

Я уже говорил, что вы не сможете изменить размер массива после того, как он создан. Можно создать массив с предварительно заданным размером, вызвав его с помощью конструктора new($size).

$data = [Object[]]::new(4)
$data.count
4

Умножение массивов

Еще один интересный прием — массив можно умножить на целое число.

PS> $data = @('red','green','blue')
PS> $data * 3
red
green
blue
red
green
blue
red
green
blue

Инициализация с нулевыми значениями

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

PS> [int[]]::new(4)
0
0
0
0

Для этого также можно использовать умножение.

PS> $data = @(0) * 4
PS> $data
0
0
0
0

Особенно полезно в умножении то, что можно использовать любое значение. Поэтому если планируется по умолчанию использовать значение 255, это будет хорошим вариантом.

PS> $data = @(255) * 4
PS> $data
255
255
255
255

Вложенные массивы

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

Существует два способа создания двумерного массива.

$data = @(@(1,2,3),@(4,5,6),@(7,8,9))

$data2 = @(
    @(1,2,3),
    @(4,5,6),
    @(7,8,9)
)

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

Для вложенного массива нотация индексов имеет некоторые изменения. Мы получаем значение 3, используя $data выше.

PS> $outside = 0
PS> $inside = 2
PS> $data[$outside][$inside]
3

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

Write-Output -NoEnumerate

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

Обычно я передаю объекты в Get-Member, чтобы получить дополнительные сведения о них. Когда я передаю туда массив, выполняется его разворачивание, и Get-Member видит элементы массива, а не фактический массив.

PS> $data = @('red','green','blue')
PS> $data | Get-Member
TypeName: System.String
...

Чтобы запретить разворачивание массива, можно использовать Write-Object -NoEnumerate.

PS> Write-Output -NoEnumerate $data | Get-Member
TypeName: System.Object[]
...

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

PS> ,$data | Get-Member
TypeName: System.Object[]
...

Возврат массива

Такое разворачивание массивов также выполняется при выводе или возврате значений из функции. Для получения массива по-прежнему можно присвоить выходные данные переменной, что обычно не вызывает проблем.

Хитрость в том, что создается новый массив. Если это проблематично, можно решить проблему с помощью Write-Output -NoEnumerate $array или return ,$array.

Что-нибудь еще?

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

Здесь, кстати, я рекомендую ознакомиться с похожей публикацией, посвященной хэш-таблицам.

Массивы в Powershell: yu_xuan — LiveJournal

При написании скриптов массивы используются очень часто, поэтому необходимо хорошо понимать как работать с ними.

Создать массив в powershell можно просто перечислив его члены через запятую. Для примера создадим небольшой массив, состоящий из чисел:

PS C:\> 1,2,3,4
1
2
3
4
PS C:\> (1,2,3,4).GetType().FullName
System.Object[]

Как видно из предыдущего примера, массив имеет тип Object, то есть это означает, что членам массива может быть присвоен любой объект:

PS C:\> 1, 2.5, "apples", (Get-Process winword)
1
2,5
apples

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
   1333      86    47844      66728   350   581,15  10448 WINWORD
PS C:\> (1, 2.5, "apples", (Get-Process winword)).Count
4

В предыдущем примере создан массив объектов, содержащий число, число двойной точности с плавающей запятой, строку и объект Process, т.е. всего четыре объекта: int, double, string, System.Diagnostics.Process instance.

Для создания массива используется довольно свободный синтаксис, однако существует формальный способ, заключающийся в использовании конструкции @() :

PS C:\> @("one", "two")
one
two

Для создания пустого массива можно воспользоваться следующим способом:

PS C:\> (@()).Count
0
PS C:\> (@()).GetType().FullName
System.Object[]

Для удобства массив можно создавать, указывая необходимый диапазон чисел:

PS C:\> 5..1
5
4
3
2
1
PS C:\> 1..5
1
2
3
4
5
PS C:\> (0..255).Count
256

Такой синтаксис чрезвычайно удобно использовать для перечисления большого набора упорядоченных чисел таких как номера портов или адреса.

При создании массивов powershell умеет распознавать вложенные массивы и превращать их в один массив:

PS C:\> 1, (5, 6), 2
1
5
6
2
PS C:\> 1, (10..7), 2
1
10
9
8
7
2

Получить доступ к члену массива можно, как и во многих других языках, при помощи квадратных скобок:

PS C:\> $a = 2,3,4
PS C:\> $a[0]
2
PS C:\> $a[1]
3
PS C:\> $a[2] = 5
PS C:\> $a
2
3
5

Заметьте, что мы изменили член массива, присвоив ему новое значение.
Массивы powershell, также как .Net, начинаются с нуля, т.е. первый член массива всегда имеет индекс [0], а последний член [-1].
Интересно, что в квадратных скобках можно указать больше одного индекса. В таком случае мы получим массив, содержащий значения этих индексов. Такой массив называется срез массива (array slice). Вот как можно получить значения первого и последнего членов:

PS C:\> $a = 2,3,4
PS C:\> $a[0,2]
2
4

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

PS C:\> $a = 2,3,4
PS C:\> $a[0,-1]
2
4

Мы также можем делать срезы, указывая диапазон индексов. Вот, как можно получить пять членов массива, начиная с третьего:

PS C:\> $a = (1, 2, 3, 4, 5, 6, 7, 8)
PS C:\> $a[2..6]
3
4
5
6
7

Если одному из членов присвоить новый массив, существующий массив расширится. Таким образом можно вставить несколько значений в какое-то определенное место массива:

PS C:\> $a = 1,2,3
PS C:\> $a[1] = 10,11,12
PS C:\> $a
1
10
11
12
3

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

PS C:\> $a = 1,2,3
PS C:\> $a[1] = $a[1], 10, 11, 12
PS C:\> $a
1
2
10
11
12
3

Так же как и со строками, с массивами можно производить операцию конкатенации, добавляя новых членов или новые массивы к существующему массиву при помощи оператора плюс:

PS C:\> $a = 1,2
PS C:\> $a = $a + 3
PS C:\> $a
1
2
3

Предыдущуюю операцию можно немного упростить при помощи оператора += :

PS C:\> $a += 4
PS C:\> $a
1
2
3
4
PS C:\> $a += 5,6
PS C:\> $a
1
2
3
4
5
6

Очень часто приходится осуществлять поиск по массиву. Следующий пример показывает, как можно найти в массиве требуемое значение:

PS C:\> foreach ($item in (2,3,4)){if ($item -eq 3){echo "Found"}}
Found

Конечно, такой способ весьма неповоротлив, так как приходится перебирать в цикле весь массив, сравнивая по очереди каждое значение. Для облегчения этой муторной операции в powershell существуют операторы -contains и -notcontains:

PS C:\> (2,3,4) -contains 3
True
PS C:\> (2,3,4) -notcontains 3
False
PS C:\> (2,3,4) -notcontains 5
True

Эти операторы можно использовать для работы с переменными, содержащими различные типы данных:

PS C:\> (2, "some value", 4) -contains "some value"
True

Стоит быть внимательным, так как типы могут быть автоматически сконвертированны и, в результате, можно получить совсем не тот результат, которого вы ожидаете:

PS C:\> (2,3,4) -contains "3"
True
PS C:\> (2,3,4) -contains "3.0"
True

Понимаете, каким образом строка «3.0» превращается в число 3 и говорит True? Для того, чтобы жестко указать тип данных можно использовать команду Where-Object:

PS C:\> (2,3,4) | Where-Object {$_ -is [string] -and $_ -eq "3.0"}
PS C:\> (2,"3.0",4) | Where-Object {$_ -is [string] -and $_ -eq "3.0"}
3.0

слегка вольный перевод главы из книги «Pro Windows PowerShell»

Powershell. Как создать изменяемый массив

Немного теории

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

Powershell относят к языкам с динамической типизацией и таким образом, тип переменной определяется в момент присваивания  значения, в зависимости от типа самого этого значения.

И если заранее вручную не создать экземпляр нужного класса(объект), то по умолчанию, объект которому мы присваиваем ряд значений, будет принадлежать к классу System.Array.

В свою очередь, объект System.Array не имеет возможности использовать метод add, т.к. является фиксированным массивом.

Массив фиксированного размера

 

Подробно о том, почему у System.Array имеется метод add, но использовать его нельзя, читайте здесь

 

Классами, которые позволяют добавлять объекты в массив, являются:
[System.Collections.Generic.List]
или
[System.Collections.ArrayList]

Так как для класса List заявлена более высокая производительность, за счет возможности явно задать его тип данных, а ArrayList имеет те же самые методы,
то разбирать работу с массивом мы будем на примере класса List

Так же у метода add() массива List упразднен вывод индекса добавляемого элемента в консоль

Плюсы:
Массив имеет не фиксированный размер, что указывает на то, что в него можно добавлять, или же удалять из него элементы
Минусы:
Не сохраняется порядок объектов в массиве при выводе, в отличии от PSCustomObject
Но это не доставляет особых проблем, т.к. можно выполнить последующую сортировку, например средствами Sort-Object

Summary простыми словами:

  • Объекты содержащие ряд значений называется массивом
  • Массивы бывают разными
  • В зависимости от класса к которому относится массив, меняется его набор свойств и методов
  • Массив класса [System.Collections.Generic.List] позволяет добавлять элементы
Практическая часть

Пример создания массива

Сначала создадим экземпляр класса List

$List = New-Object ‘System.Collections.Generic.List[System.Object]’



$List = New-Object ‘System.Collections.Generic.List[System.Object]’

Чтобы проверить наличие у объекта нужного метода можно выполнив этот метод опустив скобки «()»

Показать перегрузки

Это вернуло нам определения перегрузок метода.
Если ничего не возвращает, то метод у объекта отсутствуют. 

Что из себя представляют перегрузки методов?

Перегрузка указывают на то, как один и тот же метод, в зависимости от количества и типа данных аргументов, может выдавать отличающиеся результаты.

Определения перегрузок(OverloadDefinitions) возвращают возможные варианты перегрузок.

После того как мы убедились в наличии метода add, мы можем  добавлять в массив элементы!

Добавление элементов в массив

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

$Computers = ( Get-ADComputer -f {Enabled -eq $true} ).Name
$List = New-Object ‘System.Collections.Generic.List[System.Object]’
foreach($Computer in $Computers ){
if( Test-Connection $Computer -Count 1){
$RAM = ( Get-WmiObject Win32_PhysicalMemory -ComputerName $Computer )
$TotalMemory = «{0:N0} GB»-f $( [math]::Truncate([math]::Round((Get-WmiObject Win32_ComputerSystem -ComputerName $Computer ).TotalPhysicalMemory / 1GB )))
$Count = $RAM.DeviceLocator.Count
$MaxSlots = ( Get-WmiObject win32_PhysicalMemoryArray -ComputerName $Computer ).MemoryDevices
$List.add( ( @{CompName=$Computer;TotalMemory=$TotalMemory;CountRAM=$Count;MaxSlots=$MaxSlots} | % { New-Object object | Add-Member -NotePropertyMembers $_ -PassThru }) )
}
}

$List | Sort-Object | select CompName,TotalMemory,CountRAM,MaxSlots



$Computers = ( Get-ADComputer -f {Enabled -eq $true} ).Name

$List = New-Object ‘System.Collections.Generic.List[System.Object]’

foreach($Computer in $Computers ){

    if( Test-Connection $Computer -Count 1){

            $RAM = ( Get-WmiObject Win32_PhysicalMemory -ComputerName $Computer )

            $TotalMemory = «{0:N0} GB»-f $( [math]::Truncate([math]::Round((Get-WmiObject Win32_ComputerSystem -ComputerName $Computer ).TotalPhysicalMemory / 1GB )))

            $Count = $RAM.DeviceLocator.Count

            $MaxSlots = ( Get-WmiObject win32_PhysicalMemoryArray -ComputerName $Computer ).MemoryDevices

            $List.add( ( @{CompName=$Computer;TotalMemory=$TotalMemory;CountRAM=$Count;MaxSlots=$MaxSlots} | % { New-Object object | Add-Member -NotePropertyMembers $_ -PassThru }) )

    }

}

 

$List | Sort-Object | select CompName,TotalMemory,CountRAM,MaxSlots

Инвентаризация RAM

По полученному результату можно сделать заключение о необходимости и возможности апгрейда RAM

Так же можно добавить объекты в коллекцию и с помощью оператора += , но известно что данный метод более медлителен, так как в каждой итерации перезаписывает массив:

$List += [PSCustomObject]@{CompName=$Computer;TotalMemory=$TotalMemory;CountRAM=$Count;MaxSlots=$MaxSlots}



$List += [PSCustomObject]@{CompName=$Computer;TotalMemory=$TotalMemory;CountRAM=$Count;MaxSlots=$MaxSlots}

Помимо более низкой производительности, после его использования, коллекция становится фиксированной.

Массив теперь фиксированного типа

Поэтому лучше сразу использовать ту же конструкцию для метода add:

$List.Add( [PSCustomObject]@{Motherboard=$SysInfo;User=$user} )



$List.Add( [PSCustomObject]@{Motherboard=$SysInfo;User=$user} )

Тем не менее, для простых скриптов оператор += может вполне пригодиться

Удаление элементов из массива

Есть несколько методов для удаления объектов из массива

Remove()

Для удаления нужно целиком  указать объект. Проще всего это сделать указав конкретный элемент нашего массива

RemoveAt()

Так же можно удалить элемент по его порядковому номеру в массиве

RemoveRange()

Как следует из названия, удаляет диапазон значений по их порядковым номерам

 

powershell — Как сравнить массивы один за другим с powershell

Как сравнить массивы один за другим с powershell.

Я пытался с EQ / Match /, как / содержит / в. Но все еще не работает нормально. Большое спасибо.

Вход 【 】 Массив :

$ array = @ (‘OK’, ‘OK’, ‘OK’, ‘OK’)

$ array1 = @ («ОК», «Сбой», «ОК», «ОК»)

$ array2 = @ («ОК»)

Ожидаемый выход:

$ Array сравнить выход Array 2 True

$ Array1 сравнить выход Array2 False

2

best singer

21 Фев 2020 в 17:38

3 ответа

Лучший ответ

Если порядок элементов (а не только значений) двух массивов имеет значение (т.е. оба массива должны иметь одинаковое количество элементов, значения элементов должны быть одинаковыми И порядок, в котором элементы появиться должно быть одинаково) можно использовать

@(Compare-Object $array1 $array2 -SyncWindow 0).Length -eq 0

Если порядок, в котором элементы появляются в массивах, не имеет значения:

@(Compare-Object $array1 $array2).Length -eq 0

Edit

С учетом вашего комментария «если все значения в массиве в порядке, то выведите true, если одно из них не в порядке, то выведите false» , вы можете просто сделать:

$array = 'OK','OK','OK','OK'
# test if all elements are 'OK'
($array | Where-Object { $_ -ne 'OK' }).Count -eq 0  # outputs True

Если один из элементов не ‘OK’, как с $array1

$array1 = 'OK','failed','OK','OK'
# test if all elements are 'OK'
($array1 | Where-Object { $_ -ne 'OK' }).Count -eq 0  # outputs False

«Хитрость» в том, что отдельные элементы массива передаются в предложение Where-Object. Это служит фильтром и пропускает все элементы, которые не в порядке. Наконец, мы просто используем свойство Count результирующего массива, и если там ничего нет, счетчик будет равен 0, что означает True

4

Theo
22 Фев 2020 в 11:44

Похоже, что Group-Object облегчит это.

@($array+$array2 | Group-Object).Count -eq 1
True
@($array1+$array2 | Group-Object).Count -eq 1
False

Если все входные массивы содержат одинаковые значения элемента, он вернет True.

Причина синтаксиса @() состоит в том, чтобы всегда создавать массив со свойством Count. Это переопределит конфликт свойств Count с Group-Object в случаях, когда возвращаются отдельные объекты. Если Group-Object находит только один вариант (в результате получается один объект), то выходным объектом будет объект Microsoft.PowerShell.Commands.GroupInfo со своим собственным свойством Count. Когда возвращается несколько объектов, тип объекта — System.Object[], у которого есть свойство Count, которое мы ищем.


В качестве альтернативы mklement0 упомянул об использовании автоматического свойства Length, которое дает несколько более краткое решение. Это решение более неясно, учитывая скрытую природу свойства Length.

($array+$array2 | Group-Object).Length -eq 1
($array1+$array2 | Group-Object).Length -eq 1

1

AdminOfThings
21 Фев 2020 в 21:55

Исходя из ожидаемого результата, я полагаю, что вы пытаетесь определить, все ли элементы исходного массива ($array and $array1 в вашем случае) равны значению в тестовом массиве ($array2 в вашем случае). Я думаю, что у меня есть похожий вариант использования при перемещении каталогов данных по моей сети. Мой сценарий перемещения создает файл CSV в виде файла журнала и содержит столбец «Успех», в котором указывается, была ли каждая копия файла успешной или нет. У меня есть подпрограмма, которая принимает один из этих файлов журнала в качестве входных данных и обрабатывает столбец «Успех» как массив значений «Истина / Ложь». Чтобы увидеть, является ли вся копия действительной, я должен определить, что все элементы «Success» для каждого отдельного файла являются «True», и свести это в единое «True / False» для всей копии.

Если это правда, вы бы сделали следующее:

$good = $true
$sourcearray | % {$good = $good -and ($_ -eq $testarray[0])}

Если все элементы $sourcearray равны $testarray[0], то $good останется $true. Так:

$array = @('OK','OK','OK','OK')
$array1 = @('OK','failed','OK','OK')
$array2 = @("OK")

$arraygood = $true
$array | % {$arraygood = $arraygood -and ($_ -eq $array2[0])}

$array1good = $true
$array1 | % {$array1good = $array1good -and ($_ -eq $array2[0])}

"`$arraygood = $arraygood"
"`$array1good = $array1good"

Запуск приведенного выше кода дает мне результаты:

$arraygood = True
$array1good = False

Надеюсь, это поможет. Если это так, пожалуйста, не забудьте принять ответ с галочкой в правом верхнем углу. Спасибо!

0

Matthew
21 Фев 2020 в 15:03

Все, что вы хотели знать о массивах — PowerShell

  • 24 минуты на чтение

В этой статье

Массивы — это фундаментальная функция большинства языков программирования. Они представляют собой коллекцию
ценности или объекты, которых трудно избежать. Давайте внимательно посмотрим на массивы и все, что они
предложить.

Что такое массив?

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

Массив — это структура данных, которая служит набором нескольких элементов. Вы можете перебирать
массив или доступ к отдельным элементам с помощью индекса. Массив создается как последовательный фрагмент
память, где каждое значение хранится рядом с другим.

Я коснусь каждой из этих деталей по ходу дела.

Основное использование

Поскольку массивы являются основной функцией PowerShell, существует простой синтаксис для работы с
их в PowerShell.

Создать массив

Пустой массив можно создать с помощью @ ()

  PS> $ data = @ ()
PS> $ data.count
0
  

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

  PS> $ data = @ ('Ноль', 'Один', 'Два', 'Три')
PS> $ data.count
4

PS> $ data
Нуль
Один
Два
Три
  

В этом массиве 4 элемента. Когда мы вызываем переменную $ data , мы видим список наших элементов. Если это
массив строк, то мы получаем по одной строке на строку.

Мы можем объявить массив на нескольких строках. Запятая в этом случае не обязательна и обычно оставляется
из.

  $ data = @ (
    'Нуль'
    'Один'
    'Два'
    'Три'
)
  

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

Другой синтаксис

Обычно понимают, что @ () — это синтаксис для создания массива, но списки, разделенные запятыми
работать большую часть времени.

  $ data = «Ноль», «Один», «Два», «Три»
  
Запись-вывод для создания массивов

Стоит упомянуть один интересный трюк: вы можете использовать Write-Output для быстрого создания строк.
на консоли.

  $ data = Запись-Вывод Ноль Один Два Три
  

Это удобно, потому что вам не нужно заключать строки в кавычки, когда параметр принимает
струны. Я бы никогда не сделал этого в сценарии, но в консоли это честная игра.

Доступ к элементам

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

Смещение

Для доступа к отдельным элементам мы используем скобки [] со значением смещения, начинающимся с 0.Это
как мы получаем первый элемент в нашем массиве:

  PS> $ data = 'Ноль', 'Один', 'Два', 'Три'
PS> $ data [0]
Нуль
  

Причина, по которой мы используем здесь ноль, заключается в том, что первый элемент находится в начале списка, поэтому мы используем
смещение 0 элементов, чтобы добраться до него. Чтобы перейти ко второму элементу, нам нужно будет использовать смещение от 1 до
пропустить первый пункт.

  PS> $ data [1]
Один
  

Это будет означать, что последний элемент находится по смещению 3.

  PS> $ data [3]
Три
  
Индекс

Теперь вы можете понять, почему я выбрал значения, которые использовал для этого примера.Я ввел это как смещение
потому что это то, что есть на самом деле, но это смещение чаще называют индексом. An
индекс, который начинается с 0 . В оставшейся части этой статьи я буду называть смещение индексом.

Специальные индексные трюки

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

  PS> $ данных [0,2,3]
Нуль
Два
Три
  

Элементы возвращаются в соответствии с порядком предоставленных индексов. Если вы дублируете индекс,
вы получите этот предмет оба раза.

  PS> $ данных [3,0,3]
Три
Нуль
Три
  

Мы можем указать последовательность чисел с помощью встроенного оператора .. .

  PS> $ data [1..3]
Один
Два
Три
  

Это тоже работает в обратном порядке.

  PS> $ data [3..1]
Три
Два
Один
  

Для смещения от конца можно использовать отрицательные значения индекса. Итак, если вам нужен последний элемент в списке,
вы можете использовать -1 .

  PS> $ data [-1]
Три
  

Одно предостережение по поводу оператора .. . Последовательности 0 ..- 1 и -1..0 вычисляют
значения 0, -1 и -1,0 . Легко увидеть $ data [0 ..- 1] и подумать, что он перечислит все элементы, если
вы забываете эту деталь. $ data [0 ..- 1] дает то же значение, что и $ data [0, -1] , давая вам
первый и последний элемент в массиве (и ни одно из других значений).

За пределами

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

  PS> $ null -eq $ data [9000]
Правда
  
Невозможно проиндексировать в нулевой массив

Если ваша переменная $ null и вы пытаетесь проиндексировать ее как массив, вы получите
Система .Management.Automation.RuntimeException исключение с сообщением
Невозможно проиндексировать в нулевой массив .

  PS> $ пусто = $ null
SP> $ пусто [0]
Ошибка: невозможно проиндексировать в нулевой массив.
  

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

Счетчик

Массивы и другие коллекции имеют свойство count, которое сообщает вам, сколько элементов находится в массиве.

  PS> $ data.считать
4
  

PowerShell 3.0 добавил свойство count для большинства объектов. у вас может быть один объект, и он должен
даст вам количество 1 .

  PS> $ date = Get-Date
PS> $ date.count
1
  

Даже $ null имеет свойство count, но возвращает 0 .

  PS> $ null.count
0
  

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

Отдельные ошибки

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

Первый заключается в том, чтобы мысленно подумать, что вы хотите второй элемент, использовать индекс 2 и действительно получить
третий пункт. Или думая, что у вас есть четыре предмета, и вам нужен последний предмет, поэтому вы используете счетчик
для доступа к последнему элементу.

  $ data [$ data.count]
  

PowerShell с радостью предоставит вам возможность сделать это и точно укажет, какой элемент существует в индексе 4:
$ null .Вы должны использовать $ data.count - 1 или -1 , о которых мы узнали выше.

  PS> $ data [$ data.count - 1]
Три
  

Здесь вы можете использовать индекс -1 для получения последнего элемента.

  PS> $ data [-1]
Три
  

Ли Дейли также указал мне, что мы можем использовать $ data.GetUpperBound (0) для получения максимального индекса
количество.

  PS> $ data.GetUpperBound (0)
3
PS> $ data [$ data.GetUpperBound (0)]
Три
  

Второй наиболее распространенный способ — повторять список и не останавливаться в нужное время. Больной
вернемся к этому, когда мы будем говорить об использовании для цикла .

Обновление предметов

Мы можем использовать тот же индекс для обновления существующих элементов в массиве. Это дает нам прямой доступ к
обновить отдельные элементы.

  $ data [2] = 'dos'
$ data [3] = 'tres'
  

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

  PS> $ data [4] = 'четыре'
Индекс находился вне границ массива.
В строке: 1 символ: 1
+ $ data [4] = 'четыре'
+ ~~~~~~~~~~~~~
+ CategoryInfo: OperationStopped: (:) [], IndexOutOfRangeException
+ FullyQualifiedErrorId: System.IndexOutOfRangeException
  

Я вернусь к этому позже, когда расскажу о том, как увеличить массив.

Итерация

В какой-то момент вам может потребоваться пройти или перебрать весь список и выполнить некоторые действия для каждого
элемент в массиве.

Трубопровод

Массивы и конвейер PowerShell предназначены друг для друга. Это один из самых простых способов
процесс над этими ценностями. Когда вы передаете массив в конвейер, каждый элемент внутри массива
обрабатывается индивидуально.

  PS> $ data = 'Ноль', 'Один', 'Два', 'Три'
PS> $ data | ForEach-Object {"Элемент: [$ PSItem]"}
Элемент: [Ноль]
Предмет: [Один]
Пункт: [Два]
Пункт: [Три]
  

Если вы раньше не видели $ PSItem , просто знайте, что это то же самое, что и $ _ .Вы можете использовать либо
один, потому что они оба представляют текущий объект в конвейере.

ForEach loop

Цикл ForEach хорошо работает с коллекциями. Используя синтаксис:
foreach (<переменная> в <коллекция>)

  foreach ($ node в $ data)
{
    "Предмет: [$ node]"
}
  
Метод ForEach

Я забываю об этом, но он хорошо работает для простых операций. PowerShell позволяет
звоните .ForEach () в коллекции.

  PS> $ data.foreach ({"Item [$ PSItem]"})
Пункт [ноль]
Пункт [Один]
Пункт [два]
Пункт [Три]
  

.foreach () принимает параметр, который является блоком сценария. Вы можете опустить круглые скобки и просто
предоставить блок сценария.

  $ data.foreach {"Item [$ PSItem]"}
  

Это менее известный синтаксис, но он работает точно так же. Этот метод foreach был добавлен в
PowerShell 4.0.

Для петли

Цикл для широко используется в большинстве других языков, но вы не часто видите его в PowerShell.Когда
вы видите это, часто это происходит в контексте обхода массива.

  для ($ index = 0; $ index -lt $ data.count; $ index ++)
{
    "Элемент: [{0}]" -f $ data [$ index]
}
  

Первое, что мы делаем, это инициализируем индекс $ как 0 . Затем мы добавляем условие, что $ index должен
быть меньше $ data.count . Наконец, мы указываем, что каждый раз, когда мы зацикливаем, я должен увеличивать
индекс на 1 . В этом случае $ index ++ является сокращением от $ index = $ index + 1 .

Каждый раз, когда вы используете петлю для , обращайте особое внимание на условие. я использовал
$ index -lt $ data.count здесь. Легко ошибиться в условии, если получится один за другим.
ошибка в вашей логике. Использование $ index -le $ data.count или $ index -lt ($ data.count - 1) всегда так
немного неправильно. Это приведет к тому, что ваш результат будет обрабатывать слишком много или слишком мало элементов. Это
классическая пошаговая ошибка.

Петля переключения

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

  $ data = «Ноль», «Один», «Два», «Три»
переключатель ($ data)
{
    'Один'
    {
        'Tock'
    }
    'Три'
    {
        'Tock'
    }
    По умолчанию
    {
        'Галочка'
    }
}
  
  Тик
Tock
Галочка
Tock
  

Есть много интересных вещей, которые мы можем сделать с помощью оператора switch. У меня есть другая статья
посвященный этому.

Обновление значений

Когда ваш массив представляет собой набор строк или целых чисел (типов значений), иногда вы можете захотеть
обновляйте значения в массиве по мере их перебора.В большинстве приведенных выше циклов используется переменная в
цикл, содержащий копию значения. Если вы обновите эту переменную, исходное значение в массиве будет
не обновляется.

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

  для ($ index = 0; $ index -lt $ data.count; $ index ++)
{
    $ data [$ index] = "Элемент: [{0}]" -f $ data [$ index]
}
  

Этот пример принимает значение по индексу, вносит несколько изменений, а затем использует тот же индекс для присвоения
обратно.

Массивы объектов

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

  $ data = @ (
    [pscustomobject] @ {FirstName = 'Kevin'; LastName = 'Marquette'}
    [pscustomobject] @ {FirstName = 'Джон'; LastName = 'Doe'}
)
  

Многие командлеты возвращают коллекции объектов в виде массивов, когда вы назначаете их переменной.

  $ processList = Get-Process
  

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

Доступ к недвижимости

Мы можем использовать индекс для доступа к отдельному элементу в коллекции точно так же, как с типами значений.

  PS> $ data [0]

Имя Фамилия
----- ----
Кевин Маркетт
  

Мы можем получить доступ и обновить свойства напрямую.

  PS> $ data [0] .FirstName

Кевин

PS> $ data [0] .FirstName = 'Джей'
PS> $ data [0]

Имя Фамилия
----- ----
Джей Маркетт
  
Свойства массива

Обычно вам нужно перечислить весь список следующим образом, чтобы получить доступ ко всем свойствам:

  PS> $ данные | ForEach-Object {$ _.Фамилия}

Маркетт
Лань
  

Или с помощью командлета Select-Object -ExpandProperty .

  PS> $ данные | Select-Object -ExpandProperty LastName

Маркетт
Лань
  

Но PowerShell предлагает нам возможность напрямую запрашивать LastName . PowerShell перечисляет их
все для нас и возвращает чистый список.

  PS> $ data.LastName

Маркетт
Лань
  

Перечисление все еще происходит, но мы не видим скрытой за ним сложности.

Фильтрация объектов где-то

Здесь появляется Where-Object , чтобы мы могли фильтровать и выбирать из массива то, что мы хотим.
исходя из свойств объекта.

  PS> $ данные | Where-Object {$ _. FirstName -eq 'Кевин'}

Имя Фамилия
----- ----
Кевин Маркетт
  

Мы можем написать тот же запрос, чтобы получить FirstName , которое мы ищем.

  $ данные | Где FirstName -eq Кевин
  
Где ()

Массивы имеют метод Where () , который позволяет указать блок сценария для фильтра.

  $ data.Where ({$ _. FirstName -eq 'Кевин'})
  

Эта функция была добавлена ​​в PowerShell 4.0.

Обновление объектов в циклах

Для типов значений единственный способ обновить массив — использовать цикл for, потому что нам нужно знать
index для замены значения. У нас есть больше вариантов с объектами, потому что они являются ссылочными типами. Здесь
это быстрый пример:

  foreach ($ человек в $ данных)
{
    $ person.FirstName = 'Кевин'
}
  

Этот цикл проходит по каждому объекту в массиве $ data .Поскольку объекты являются ссылочными типами,
Переменная $ person ссылается на тот же объект, что и в массиве. Итак, обновления его
свойства действительно обновляют оригинал.

Вы по-прежнему не можете заменить весь объект таким способом. Если вы попытаетесь присвоить новый объект
$ переменная человека , вы обновляете ссылку на переменную на что-то еще, что больше не указывает
к исходному объекту в массиве. Это не работает так, как вы ожидаете:

  foreach ($ человек в $ данных)
{
    $ person = [pscustomobject] @ {
        FirstName = 'Кевин'
        LastName = 'Маркетт'
    }
}
  

Операторы

Операторы в PowerShell также работают с массивами.Некоторые из них работают немного иначе.

-присоединиться к

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

  PS> $ data = @ (1,2,3,4)
PS> $ data -join '-'
1-2-3-4
PS> $ data -join ','
1,2,3,4
  

Одна из особенностей, которые мне нравятся в операторе -join , заключается в том, что он обрабатывает отдельные элементы.

  PS> 1 -соединение '-'
1
  

Я использую это в журналах и подробных сообщениях.

  PS> $ data = @ (1,2,3,4)
PS> "Данные - это $ ($ data -join ',')."
Данные 1,2,3,4.
  
— объединить массив $

Вот хитрый трюк, который мне подсказал Ли Дэйли. Если ты когда-нибудь захочешь присоединиться ко всему
без разделителя, вместо этого:

  PS> $ data = @ (1,2,3,4)
PS> $ data -join $ null
1234
  

Вы можете использовать -join с массивом в качестве параметра без префикса.Взгляните на этот пример, чтобы
смотри, о чем я говорю.

  PS> $ data = @ (1,2,3,4)
PS> -join $ data
1234
  

-заменить и -разбить

Другие операторы, такие как -replace и -split , выполняются для каждого элемента в массиве. Я не могу сказать
что я когда-либо использовал их таким образом, но вот пример.

  PS> $ data = @ ('ATX-SQL-01', 'ATX-SQL-02', 'ATX-SQL-03')
PS> $ data - заменить 'ATX', 'LAX'
LAX-SQL-01
LAX-SQL-02
LAX-SQL-03
  

-содержит

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

  PS> $ data = @ ('красный', 'зеленый', 'синий')
PS> $ data -contains 'зеленый'
Правда
  

— дюйм

Если у вас есть одно значение, которое вы хотите проверить, соответствует одному из нескольких значений, вы можете
используйте оператор -in . Значение будет слева, а массив — справа от
оператор.

  PS> $ data = @ ('красный', 'зеленый', 'синий')
PS> 'зеленый' - в $ data
Правда
  

Это может обойтись дорого, если список большой.(красный | зеленый | синий) $

PS> ‘зеленый’ — совпадение с шаблоном $
Правда

-eq и -ne

Равенство и массивы могут быть сложными. Когда массив находится слева, каждый элемент получает
по сравнению. Вместо того, чтобы возвращать True , он возвращает соответствующий объект.

  PS> $ data = @ ('красный', 'зеленый', 'синий')
PS> $ data -eq 'зеленый'
зеленый
  

Когда вы используете оператор -ne , мы получаем все значения, которые не равны нашему значению.

  PS> $ data = @ ('красный', 'зеленый', 'синий')
PS> $ data -ne 'зеленый'
красный
синий
  

Когда вы используете это в инструкции if () , возвращается значение True .Если значение не возвращается, то это значение False . Оба этих следующих утверждения оцениваются как True .

  $ data = @ ('красный', 'зеленый', 'синий')
если ($ data -eq 'зеленый')
{
    'Зеленый был найден'
}
если ($ data -ne 'зеленый')
{
    'А зеленого не нашлось'
}
  

Я вернусь к этому чуть позже, когда мы поговорим о тестировании для $ null .

— матч

Оператор -match пытается сопоставить каждый элемент в коллекции.

  PS> $ servers = @ (
    'LAX-SQL-01'
    «LAX-API-01»
    'ATX-SQL-01'
    'ATX-API-01'
)
PS> $ servers - соответствие 'SQL'
LAX-SQL-01
ATX-SQL-01
  

Когда вы используете -match с одним значением, специальная переменная $ Matches заполняется соответствием
Информация. Это не тот случай, когда массив обрабатывается таким образом.

Мы можем использовать тот же подход с Select-String .

  $ серверов | Выбрать строку SQL
  

Я более подробно смотрю на Select-String , -match и $ соответствует переменной в другом посте под названием
Многочисленные способы использования регулярных выражений.

$ пусто или пусто

Тестирование $ null или пустых массивов может быть сложной задачей. Вот общие ловушки с массивами.

На первый взгляд, это утверждение выглядит так, как будто оно должно работать.

  если ($ array -eq $ null)
{
    'Массив равен $ null'
}
  

Но я только что рассмотрел, как -eq проверяет каждый элемент в массиве. Таким образом, у нас может быть массив из нескольких
элементы с одним значением $ null, и оно будет оцениваться как $ true

  $ array = @ ('один', $ null, 'три')
если ($ массив -eq $ null)
{
    'Я думаю, что Array равен $ null, но я ошибаюсь'
}
  

Вот почему рекомендуется размещать $ null слева от оператора.Это делает
этот сценарий не проблема.

  if ($ null -eq $ массив)
{
    'Фактически массив $ null'
}
  

Массив $ null — это не то же самое, что пустой массив. Если вы знаете, что у вас есть массив, проверьте
количество объектов в нем. Если массив равен $ null , счет будет 0 .

  если ($ array.count -gt 0)
{
    «Массив не пустой»
}
  

Здесь есть еще одна ловушка. Вы можете использовать count , даже если у вас есть один
объект, если этот объект не является PSCustomObject .Это ошибка, исправленная в PowerShell 6.1.
Это хорошие новости, но многие люди все еще используют 5.1, и им нужно остерегаться этого.

  PS> $ object = [PSCustomObject] @ {Name = 'TestObject'}
PS> $ object.count
$ null
  

Если вы все еще используете PowerShell 5.1, вы можете обернуть объект в массив, прежде чем проверять счетчик на
получить точный подсчет.

  if (@ ($ array) .count -gt 0)
{
    «Массив не пустой»
}
  

Чтобы полностью перестраховаться, проверьте $ null , затем проверьте счет.

  if ($ null -ne $ array -and @ ($ array) .count -gt 0)
{
    «Массив не пустой»
}
  

Все -эк.

Недавно я видел, как кто-то спросил, как проверить, что каждое значение в массиве соответствует заданному значению.
У пользователя Reddit / u / bis было это умное решение, которое проверяет любые неправильные значения, а затем
переворачивает результат.

  $ results = Test-Something
if (-not ($ results -ne 'Passed'))
{
    "Все результаты пройдены"
}
  

Добавление в массивы

На этом этапе вы начинаете задаваться вопросом, как добавлять элементы в массив.Быстрый ответ: вы
не могу. Массив — это фиксированный размер в памяти. Если вам нужно вырастить его или добавить к нему один элемент, тогда
вам нужно создать новый массив и скопировать все значения из старого массива. Это звучит как
много работы, однако PowerShell скрывает сложность создания нового массива. PowerShell
реализует оператор сложения ( + ) для массивов.

Примечание

PowerShell не реализует операцию вычитания. Если вам нужна гибкая альтернатива
array, вам нужно использовать общий объект List .

Добавление массива

Мы можем использовать оператор сложения с массивами, чтобы создать новый массив. Итак, учитывая эти два массива:

  $ первый = @ (
    'Нуль'
    'Один'
)
$ секунда = @ (
    'Два'
    'Три'
)
  

Мы можем сложить их вместе, чтобы получить новый массив.

  PS> первый + второй $

Нуль
Один
Два
Три
  

Плюс равно + =

Мы можем создать новый массив на месте и добавить к нему элемент следующим образом:

  $ data = @ (
    'Нуль'
    'Один'
    'Два'
    'Три'
)
$ data + = 'четыре'
  

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

Назначение трубопровода

Вы можете присвоить результаты любого конвейера переменной. Это массив, если он содержит несколько
Предметы.

  $ массив = 1..5 | ForEach-Object {
    "ATX-SQL- $ PSItem"
}
  

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

  $ array = foreach ($ node in (1..5))
{
    "ATX-SQL- $ узел"
}
  

Типы массивов

По умолчанию массив в PowerShell создается как тип [PSObject []] . Это позволяет ему содержать
любой тип объекта или ценности. Это работает, потому что все унаследовано от типа PSObject .

Строго типизированные массивы

Вы можете создать массив любого типа, используя аналогичный синтаксис.Когда вы создаете строго типизированный массив,
он может содержать только значения или объекты указанного типа.

  PS> [int []] $ numbers = 1,2,3
PS> [int []] $ numbers2 = 'один', 'два', 'три'
ОШИБКА: невозможно преобразовать значение «один» в тип «System.Int32». Строка ввода была в неправильном формате. "

PS> [строка []] $ strings = 'один', 'два', 'три'
  

ArrayList

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

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

Вот как мы создаем ArrayList и добавляем в него элементы.

  $ myarray = [System.Collections.ArrayList] :: new ()
[void] $ myArray.Add ('Значение')
  

Мы вызываем .NET, чтобы получить этот тип. В этом случае мы используем конструктор по умолчанию для
создать это.Затем мы вызываем метод Add , чтобы добавить к нему элемент.

Причина, по которой я использую [void] в начале строки, заключается в подавлении кода возврата. Немного
Вызовы .NET делают это и могут создавать неожиданный результат.

Если единственные данные, которые у вас есть в вашем массиве, — это строки, также обратите внимание на использование
StringBuilder. Это почти то же самое, но есть некоторые методы, предназначенные только для работы с
струны. StringBuilder специально разработан для повышения производительности.

Часто можно увидеть, как люди переходят на ArrayList из массивов. Но это пришло из того времени, когда C # не
имеют общую поддержку. ArrayList устарел в связи с поддержкой общего List []

Общий список

Универсальный тип — это специальный тип в C #, который определяет обобщенный класс, а пользователь указывает
типы данных, которые он использует при создании. Итак, если вам нужен список чисел или строк, вы должны определить
что вам нужен список типов int или string .

Вот как вы создаете список для строк.

  $ mylist = [System.Collections.Generic.List [строка]] :: new ()
  

Или список номеров.

  $ mylist = [System.Collections.Generic.List [int]] :: new ()
  

Мы можем преобразовать существующий массив в список, подобный этому, без предварительного создания объекта:

  $ mylist = [System.Collections.Generic.List [int]] @ (1,2,3)
  

Мы можем сократить синтаксис с помощью , используя оператор пространства имен в PowerShell 5 и новее.В
с использованием оператора должна быть первой строкой вашего скрипта. Объявив пространство имен, PowerShell
позволяет вам не включать его в типы данных, когда вы на них ссылаетесь.

  с использованием пространства имен System.Collections.Generic
$ myList = [Список [int]] @ (1,2,3)
  

Это делает список List гораздо более удобным.

Вам доступен аналогичный метод Добавить . В отличие от ArrayList, на
метод Add , поэтому нам не нужно аннулировать его.

  $ myList.Add (10)
  

И мы все еще можем получить доступ к элементам, как и к другим массивам.

  PS> $ myList [-1]
10
  
Список [PSObject]

У вас может быть список любого типа, но если вы не знаете тип объектов, вы можете использовать
[Список [PSObject]] , чтобы их содержать.

  $ list = [Список [PSObject]] :: new ()
  
Удалить ()

ArrayList и общий List [] поддерживают удаление элементов из коллекции.

  с использованием пространства имен System.Collections.Generic
$ myList = [Список [строка]] @ ('Ноль', 'Один', 'Два', 'Три')
[void] $ myList.Remove ("Два")
Нуль
Один
Три
  

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

  [список [System.Management.Automation.PSDriveInfo]] $ drive = Get-PSDrive
$ диски.удалить ($ диски [2])
  
  $ delete = $ диски [2]
$ drive.remove ($ удалить)
  

Метод remove возвращает true , если ему удалось найти и удалить элемент из коллекции.

Еще коллекции

Есть много других коллекций, которые можно использовать, но это хорошая замена универсального массива.
Если вам интересно узнать о других вариантах, взгляните на этот
Суть что
Марк Краус вместе взятый.

Прочие нюансы

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

Массивы предустановленных размеров

Я упоминал, что вы не можете изменить размер массива после его создания. Мы можем создать массив
предварительно определенный размер, вызвав его с помощью конструктора new ($ size) .

  $ data = [Объект []] :: новый (4)
$ data.count
4
  

Умножающие массивы

Интересная маленькая уловка заключается в том, что вы можете умножить массив на целое число.

  PS> $ data = @ ('красный', 'зеленый', 'синий')
PS> $ data * 3
красный
зеленый
синий
красный
зеленый
синий
красный
зеленый
синий
  

Инициализировать с помощью 0

Распространенный сценарий состоит в том, что вы хотите создать массив со всеми нулями.Если у тебя будет только
целые числа, строго типизированный массив целых чисел, по умолчанию все нули.

  PS> [int []] :: новый (4)
0
0
0
0
  

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

  PS> $ data = @ (0) * 4
PS> $ data
0
0
0
0
  

Уловка умножения хороша тем, что вы можете использовать любое значение. Итак, если вы предпочитаете
укажите 255 в качестве значения по умолчанию, это будет хороший способ сделать это.

  PS> $ data = @ (255) * 4
PS> $ data
255
255
255
255
  

Вложенные массивы

Массив внутри массива называется вложенным массивом.Я не часто использую их в PowerShell, но у меня есть
использовал их больше на других языках. Рассмотрите возможность использования массива массивов, когда ваши данные помещаются в сетку
как шаблон.

Вот два способа создания двумерного массива.

  $ data = @ (@ (1,2,3), @ (4,5,6), @ (7,8,9))

$ data2 = @ (
    @ (1,2,3),
    @ (4,5,6),
    @ (7,8,9)
)
  

В этих примерах запятая очень важна. Я привел более ранний пример обычного массива на
несколько строк, в которых запятая была необязательной.Это не относится к многомерному массиву.

То, как мы используем индексную нотацию, немного изменилось теперь, когда у нас есть вложенный массив. Используя
$ data выше, это то, как мы могли бы получить доступ к значению 3.

  PS> $ снаружи = 0
PS> $ внутри = 2
PS> $ data [$ снаружи] [$ внутри]
3
  

Добавьте набор скобок для каждого уровня вложенности массивов. Первый комплект скоб для внешнего
самый массив, а затем вы продвигаетесь оттуда.

Запись-вывод - Нет числа

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

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

  PS> $ data = @ ('красный', 'зеленый', 'синий')
PS> $ data | Get-Member
Имя типа: System.String
...
  

Чтобы предотвратить разворачивание массива, вы можете использовать Write-Output -NoEnumerate .

  PS> Запись-вывод -Нет данных $ | Get-Member
Имя типа: System.Object []
...
  

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

  PS>, $ данные | Get-Member
Имя типа: System.Object []
...
  

Вернуть массив

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

Загвоздка в том, что у вас есть новый массив. Если это когда-либо проблема, вы можете использовать
Write-Output -NoEnumerate $ array or return, $ array , чтобы обойти это.

Что-нибудь еще?

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

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

массивов Powershell - PowerShell - SS64.com

массивов Powershell - PowerShell - SS64.com

Массив PowerShell содержит список элементов данных.
Элементы данных в массиве PowerShell не обязательно должны быть одного типа, если только тип данных не объявлен (строго типизирован).

Создание массивов

Чтобы создать массив, просто разделите элементы запятыми.

Создайте массив с именем $ myArray, содержащий элементы с разными типами данных:

$ myArray = 64, «Привет», 3.5, «Мир»

или используйте явный синтаксис приведения к массиву:

$ myArray = @ ( 64, «Привет», 3.5, «Мир» )

Использование синтаксиса приведения к массиву @ (...) позволяет все, что находится в скобках, обрабатывать как массив, это может быть один элемент, вывод других команд / выражений, они всегда будут обрабатываться как массив.

Чтобы распределить значения обратно по отдельным переменным:

$ var1, $ var2, $ var3, $ var4 = $ myArray

Создать массив, содержащий несколько числовых (int) значений:

$ myArray = 1,2,3,4,5,6,7

или с помощью оператора диапазона (..):

$ myArray = (1..7)

или строго типизированный:

[int []] $ myArray = 12,64,8,64,12

Если вы хотите ИЗБЕЖАТЬ создания массива, заключите строковое выражение в кавычки, PowerShell проигнорирует любые запятые, которые могут оказаться внутри строки:

$ notAnArray = "один, два, три"

Создать пустой массив:

$ myArray = @ ()

Создать массив из одного элемента:

$ myArray = @ ("Hello World")

Создать многомерный массив:

 $ myMultiArray = @ (
             (1,2,3),
             (40,50,60)
   ) 

Добавить значения в массив.

Это делается с помощью оператора + =

Добавить дополнительный элемент со значением "Индия" в массив $ Country:
$ Country + = "India"

Добавление элементов в большой массив может быть довольно медленным, переменная массива PowerShell неизменна - это означает, что в фоновом режиме она создает целый новый массив, который включает новое значение, а затем отбрасывает старый массив.
Более быстрая альтернатива использованию .Net ArrayList:

$ стран = Система новых объектов.Collections.ArrayList
$ country.Add ('Индия')> $ null
$ country.Add ('Черногория')> $ null

Получить элементы из массива

Чтобы получить элемент, укажите его номер, PowerShell автоматически нумерует элементы массива, начиная с 0.

Так, например, этот массив:

PS C: \> $ myArray = 64, «Привет», 3.5, «Мир», «Демо»

Будет иметь автоматические порядковые номера:

0 1 2 3 4
64 Привет 3.5 Мир Демо

Вернуть все элементы в массиве:

PS C: \> $ myArray

Вернуть первый элемент в массиве:

PS C: \> $ myArray [0]
64

Вернуть четвертый элемент в массиве:

PS C: \> $ myArray [3]
Мир

Вернуть с 5-го по 10-й элемент в массив:

PS C: \> $ myArray [4..9]

Вернуть последний элемент в массиве:

PS C: \> $ myArray [-1]

Вернуть первый элемент из первой строки в многомерном массиве:

PS C: \> $ myMultiArray [0] [0]

Вы также можете комбинировать именованные элементы с диапазоном, разделяя их знаком +
поэтому $ myArray [1,2 + 4..9] вернет элементы с индексами 1 и 2, а затем с 4 по 9 включительно.

Вернуть длину массива (сколько элементов в массиве):

$ myArray.длина

Перебирать элементы в массиве:

foreach ($ element в $ myArray) {$ element}

В PowerShell 4.0+ у массивов есть методы .Where () и .Foreach () - более быстрая альтернатива традиционному конвейеру за счет более высокого потребления памяти:
@ (Get-Service) .Where ( {$ _. Статус -eq «остановлен»} )
или
без скобок:
@ (Get-Service). Где {$ _. Status -eq 'Stopped'}

В случае с массивом операторы сравнения будут работать как фильтр, возвращающий все совпадающие значения.

PS C: \> $ a = 1,2,3,2
PS C: \> $ a -eq 2
2
2

Следует проявлять осторожность при сравнении значений NULL, поскольку это фильтр, вы должны поместить $ null в левой части сравнения.

PS C: \> $ a -eq $ null # сбой: возвращает $ null
PS C: \> $ null -eq $ a # работает: возвращает $ false

Многомерные массивы

Создать многомерный массив:

 PS C: \> $ MultiArray = @ (
             («кошки», «собаки», «вороны»),
             (40,50,60)
        ) 

PowerShell автоматически пронумерует элементы массива в сетке X-Y, начиная с 0.

0 1 2
0 кошек собак вороны
1 40 50 60

PS C: \> $ MultiArray [0] [2]
вороны

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

Типы данных

Когда вы создаете массив без указания типа данных, PowerShell создаст массив как массив объектов.
Чтобы определить тип данных массива:

$ myArray.gettype ()

Чтобы создать строго типизированный массив, который может содержать значения только одного определенного типа, приведите переменную как string [], long [], bool [], int32 [] или любой другой допустимый тип данных.
Чтобы преобразовать массив, поместите тип массива, заключенный в квадратные скобки, перед именем переменной.
например

[ int32 [] ] $ строго типизированный = @ (64,12,24,5000)

[ int32 [] [] ] $ multi = @ (
(64, 12, 24),
(65, 14, 48)
)

PowerShell не чувствителен к регистру, поэтому $ myArray обрабатывается так же, как $ Myarray

Если передать массив Get-Member по конвейеру, он отобразит информацию об объектах в массиве .Если вы используете Get-Member -InputObject, это отобразит информацию о самом массиве:

получить член -inputobject $ myArray

Изменить значения массива

Чтобы изменить значения в массиве после его создания, используйте оператор присваивания (=), чтобы указать новое значение.

$ myArray [4] = 64

В качестве альтернативы используйте метод SetValue:

$ myArray.SetValue (64,4)

$ myMultiArray [2] [4] = 128

Добавить один массив в другой.
Это создает новый массив, содержащий все значения из первых двух массивов:

$ марта = @ (2, 3, 4, 5, 6)
$ апрель = @ (7, 8, 9, 10, 11, 12)
$ all = $ март + $

за апрель

Удалить элементы из массива

Это должно быть сделано путем создания нового массива на основе исходного массива за вычетом элементов, которые вам не нужны:

# Создаем массив
$ demo = @ (2, 4, 6, 7)
# теперь копируем все элементы за исключением последнего и сохраняем в новом массиве

$ final =
$ демо | Where-Object {($ _ -ne 7)}

Для больших массивов намного быстрее пройти через массив с помощью Foreach - пример: удаление пустых элементов

Удалить массив
(удалив переменную массива)

Переменная Remove-Item: month_sales

«И не устрашишься своим присутствием, Зимородок, мечтательно смотрящий вниз, На свою великолепно одетую тень» - сэр Эдмунд Уильям Госсе

Связанные командлеты PowerShell:

get-help about_array
Хеш-таблицы - храните парные ключи и значения, а также оператор SPLAT.
Переменные - создание / чтение переменных.


Авторские права © 1999-2021 SS64.com
Некоторые права защищены.

Работа с массивами в PowerShell - Microsoft Certified Professional Magazine Online

Практическое руководство по PowerShell

Работа с массивами в PowerShell

Изучение того, как массив хранит объекты, поможет использовать их в вашем коде.

  • Автор: Адам Бертрам
  • 06.04.2017

PowerShell, как и другие языки программирования, имеет разные типы объектов.Эти типы позволяют определить своего рода схему поведения каждого объекта. Несколько общих типов, о которых вы, возможно, слышали, - это строки, целые числа, хэш-таблицы и массивы. Каждый из этих типов - заполнители для хранения вещей. У каждого типа свое поведение. В этой статье мы собираемся обсудить, как массивы работают в PowerShell.

Как и в других языках, массивы PowerShell хранят один или несколько элементов. Элементом может быть что угодно: строка, целое число, другой массив или общий объект.Массивы могут содержать любую комбинацию этих элементов. Работа с массивами в основном включает в себя три действия. Эти действия добавляют элементы и удаляют элементы. Хотя некоторые могут возразить, что изменение элементов - это еще одно действие, как вы увидите, обычно это просто скрытое удаление / добавление.

Каждый элемент в массиве имеет индекс. Это целые числа, присвоенные каждому элементу, который представляет его место в массиве.Индексы всегда начинаются с 0, что означает, что первый элемент в массиве всегда будет иметь индекс 0, за которым следуют 1, 2, до бесконечности. Эти индексы указывают на то, как элементы упоминаются в массиве.

Чтобы продемонстрировать это, давайте сначала определим массив. Поскольку PowerShell построен на основе .NET Framework, существует несколько способов определения массивов, но для простоты мы сосредоточимся на наиболее распространенном способе представления массива с помощью символа амперсанда, за которым следуют круглые скобки.

 @ ()
 

Вы создали свой первый пустой массив. Это структура массива, но как есть, она не слишком полезна. Мы должны добавить в него несколько предметов. Чтобы добавить элементы в массивы, мы можем сделать это либо при создании массива, либо после его создания. Допустим, я хочу сохранить в своем массиве несколько фруктов. Они будут представлены в виде строк.

 $ fruit = @ ('Яблоки', 'Апельсины', 'Бананы')
 

PS / Users / adam> $ fruit = @ ('Яблоки', 'Апельсины', 'Бананы')
PS / Users / adam> $ fruit
Яблоки
Апельсины
Бананы

Как видите, наш массив теперь представлен переменной $ fruit и содержит три строки.На этом этапе я мог бы добавить в массив еще одну строку, используя наиболее распространенный, сокращенный метод уничтожения нашего массива и создания еще одного за одно действие.

 PS / Users / adam> $ fruit + = 'Strawberries' 
PS / Users / adam> $ fruit
Яблоки
Апельсины
Бананы
Клубника

Вы можете видеть выше, что я «добавил» еще одну строку под названием Strawberries в наш массив $ fruit с помощью двух операторов, + и =.Похоже, что PowerShell просто добавляет элемент в конец массива, но на самом деле он уничтожает массив и создает новый с добавленным элементом. Добавление элементов в массив - самый распространенный процесс.

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

 [int []] $ числа = 1,2,3,4,5
 

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

 PS / Users / adam> $ numbers + = 'ffff' 
Невозможно преобразовать значение «ffff» в тип «System.Int32». Ошибка: «Входная строка
имеет неправильный формат».

Теперь я хотел бы получить доступ ко всем элементам в моем массиве. Я могу сделать это, используя индексы каждого элемента. Обратите внимание, что я могу узнать, сколько элементов находится в массиве, используя свойство Count, и могу ссылаться на каждый из них, используя его индекс, заключив каждый в квадратные скобки.

 PS / Users / adam> $ fruit.Count 
4
PS / Users / adam> $ fruit [0]
Apple
PS / Users / adam> $ fruit [1]
Апельсины
PS / Users / adam> $ fruit [2]
Бананы
PS / Пользователи / adam> $ fruit [3]
Клубника

Наконец, давайте удалим четвертый элемент с индексом три.Созданный нами массив является «фиксированным» массивом, и мы технически не можем удалить элемент. Помните, я только что говорил об уничтожении и создании нового массива? Здесь применима та же концепция. Возможно, я хотел бы удалить яблоки из своего массива. Чтобы удалить яблоки из массива $ fruit, я мог бы перечислить каждый элемент и исключить яблоки, как показано ниже.

 $ fruitNew = $ fruit | Where-Object {$ _ -ne 'Яблоки'}
 

Используйте массивы всякий раз, когда вам нужно сохранить набор общих элементов.Также имейте в виду, что существует множество других способов манипулирования массивами и другими подобными типами, которые мы не могли охватить. Дополнительные сведения см. В разделе справки PowerShell About_Arrays.

Об авторе

Адам Бертрам - ветеран ИТ с 20-летним стажем. Он инженер по автоматизации, блогер, консультант, писатель-фрилансер, автор курсов Pluralsight и советник по контент-маркетингу в нескольких технологических компаниях.Адам также основал популярную платформу электронного обучения TechSnips. В основном он специализируется на DevOps, технологиях системного управления и автоматизации, а также на различных облачных платформах, в основном в пространстве Microsoft. Он является MVP по Microsoft Cloud and Datacenter Management, он получает знания из области ИТ и объясняет их в простой для понимания форме. Следите за статьями Адама на adamtheautomator.com, подключитесь к LinkedIn или подпишитесь на него в Twitter на @adbertram или в учетной записи TechSnips Twitter @techsnips_io.

Управление массивами в PowerShell - Microsoft Certified Professional Magazine Online

Практическое руководство по PowerShell

Управление массивами в PowerShell

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

  • Автор: Адам Бертрам
  • 10.04.2019

В PowerShell и многих языках массив - это набор элементов, представленных одной переменной.Чтобы объяснить массивы и способы управления ими в PowerShell, давайте начнем с примера набора цветов. Если группа элементов связана друг с другом, всегда рекомендуется хранить их как «набор», помещая их все в массив.

Может быть, я создаю палитру цветов в более крупном скрипте и хочу ссылаться на каждый цвет в одной переменной. Для этого я мог бы создать массив с именем $ colorPicker. Я скажу PowerShell, что я собираюсь сделать это массивом и вставлю каждый цвет как элемент внутри, используя знак «at» и открывающие и закрывающие круглые скобки.

 PS C: \> $ colorPicker = @ ('синий', 'белый', 'желтый', 'черный')
PS C: \> $ colorPicker
синий
белый
желтый
черный 

Чтение элементов массива
Теперь у меня есть список всех цветов в одной переменной. Теперь я могу ссылаться на каждый из этих цветов по порядковому номеру, начиная с нуля. Только не пытайтесь указать номер индекса, который выше, чем на самом деле в массиве.

 PS C: \> $ colorPicker [0]
синий
PS C: \> $ colorPicker [2]
желтый
PS C: \> $ colorPicker [3]
чернить
PS C: \> $ colorPicker [4]
Индекс находился вне границ массива.
В строке: 1 символ: 1
+ $ colorPicker [4]
+ ~~~~~~~~~~~~~~~
    + CategoryInfo: OperationStopped: (:) [], IndexOutOfRangeException
    + FullyQualifiedErrorId: System.IndexOutOfRangeException 

Мы также можем изменять массивы на лету, присваивая новые значения номерам индексов.

 PS C: \> $ colorPicker [3]
чернить
PS C: \> $ colorPicker [3] = 'белый'
PS C: \> $ colorPicker [3]
белый 

Добавление элементов массива
Возможно, вы создали массив, подобный нашему примеру $ colorPicker, и вам нужно добавить к нему дополнительные цвета. Вместо того, чтобы полностью удалять существующий массив и создавать новый, мы можем добавлять элементы в один с помощью оператора +. Оператор + в PowerShell используется для добавления элементов в различные списки или для объединения строк вместе.

Чтобы добавить элемент в массив, мы можем заставить PowerShell перечислить все элементы в массиве, просто набрав его переменную, а затем включив + позади нее.

 PS C: \> $ colorPicker = $ colorPicker + 'оранжевый'
PS C: \> $ colorPicker
синий
белый
желтый
чернить
оранжевый 

Метод + работает, но у нас есть более короткий и распространенный способ сделать то же самое. Вместо того, чтобы просто использовать оператор +, мы можем использовать знаки плюса и равенства вместе, чтобы сформировать + =.

 PS C: \> $ colorPicker + = 'коричневый'
PS C: \> $ colorPicker
синий
белый
желтый
чернить
апельсин
коричневый 

Оператор + = - это ярлык, который указывает PowerShell добавить этот элемент в существующий массив. Этот ярлык избавляет вас от необходимости вводить имя массива дважды и встречается гораздо чаще, чем использование полного синтаксиса.

Изменение элементов массива
Изменить элементы массива очень просто. Нам просто нужно найти элемент, который мы хотели бы изменить, используя номер индекса, и присвоить ему новое значение.

В нашем примере с палитрой цветов, возможно, я хочу изменить белый элемент на розовый. Сначала мне нужно выяснить, под каким индексом определен белый элемент. Поскольку у нас есть небольшой массив, и я знаю, что порядковый номер белого равен 1, я могу просто установить другое значение так же, как я устанавливаю значение для простой строковой переменной.

 $ colorPicker [1] = 'розовый' 

Вот и все! Изменить элементы массива совсем несложно.

Не все массивы одинаковы
Вспомните ранее, что я говорил вам, что вы можете добавлять элементы в массив и что похоже, что я использовал оператор + =? Я соврал.PowerShell заставляет вас думать, что вы добавляете элементы в существующий массив, но технически вы все равно создаете новый; это просто не похоже.

Зачем поднимать это сейчас? Причина в том, что я только что провел вас через чтение, добавление и изменение элементов массива. С моей стороны было бы благоразумно показать вам, как их удалить. Но когда я это сделаю, вы увидите, что метод удаления элемента из типичного массива в PowerShell невозможен. Массивы PowerShell имеют фиксированный размер.Вот доказательство:

 PS C: \> $ colorPicker.Remove ('коричневый')
Исключение, вызывающее «Удалить» с аргументом (ами) «1»: «Коллекция имела фиксированный размер».
В строке: 1 символ: 1
+ $ colorPicker.Remove ('коричневый')
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo: NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId: NotSupportedException 

Когда вам нужно удалить элементы из массива, PowerShell уничтожает старый и создает новый.Обычно вы этого не замечаете, но когда вы начнете работать с огромными массивами с десятками или сотнями тысяч элементов, вы увидите значительное снижение производительности. Вместо этого мы можем использовать массив аналогичного типа, известный как ArrayList. ArrayList ведет себя почти так же, как и типичный массив PowerShell, но не имеет фиксированного размера.

Например, чтобы создать наш массив выбора цвета как ArrayList, нам просто нужно привести массив к типу System.Collections.ArrayList. Чуть позже мы узнаем намного больше о приведении типов и типах объектов.

 PS C: \> $ colorPicker = [System.Collections.ArrayList] @ ('синий', 'белый', 'желтый', 'черный') 

Теперь мы можем использовать методы этого объекта для добавления и удаления элементов из массива без его повторного создания. Когда у нас есть ArrayList, мы можем использовать методы Add () и Remove () для добавления или удаления элементов из массива. Здесь я использую термин «массив» в широком смысле. Отныне массив PowerShell и объект типа System.Collections.ArrayList для нас одно и то же.

Чтобы добавить элементы в массив сейчас, мы можем использовать метод Add () и передать элемент в качестве аргумента метода.

 PS C: \> $ colorPicker.Add ('серый')
4 

Обратите внимание, что он что-то вернул: число 4. Откуда это взялось? Метод Add () в ArrayList всегда будет возвращать порядковый номер только что добавленного элемента. Обычно нас не интересует это число, поэтому вы обычно видите, что метод Add () отправляется в $ null, чтобы ничего не возвращать.

 PS C: \> $ null = $ colorPicker.Add ('серый') 

Поскольку теперь у нас есть «более интересный» массив, с которым можно работать, мы можем использовать метод Remove () для удаления любых элементов, которые нам нужны.В предыдущем примере мы добавили элемент со значением серого, и из числа 4, которое было возвращено, мы знаем, что индекс равен 4. Давайте удалим его.

 PS C: \> $ colorPicker.Remove ('серый') 

Обратите внимание, что на этот раз нам совсем не нужно знать порядковый номер. Мы можем ссылаться на элемент по его фактическому значению. Этот «более продвинутый» массив действительно имеет несколько преимуществ по сравнению с типичным массивом PowerShell, такие как повышенная производительность при добавлении элементов, возможность удаления элементов из массива и некоторые другие вещи.Если вы хотите глубже изучить списки массивов, проверьте все его свойства и методы с помощью Get-Member.

 PS C: \>, $ colorPicker | Get-Member 

Работа с массивами в PowerShell - довольно простой процесс, если вы освоите его. Самая большая проблема для большинства новичков - определить , когда использовать массив. Как показывает опыт, если вам нужно выполнить какое-либо действие с одним или несколькими элементами, скорее всего, лучше всего использовать массив.

Об авторе

Адам Бертрам - ветеран ИТ с 20-летним стажем. Он инженер по автоматизации, блогер, консультант, писатель-фрилансер, автор курсов Pluralsight и советник по контент-маркетингу в нескольких технологических компаниях. Адам также основал популярную платформу электронного обучения TechSnips. В основном он специализируется на DevOps, технологиях системного управления и автоматизации, а также на различных облачных платформах, в основном в пространстве Microsoft.Он является MVP по Microsoft Cloud and Datacenter Management, он получает знания из области ИТ и объясняет их в простой для понимания форме. Следите за статьями Адама на adamtheautomator.com, подключитесь к LinkedIn или подпишитесь на него в Twitter на @adbertram или в учетной записи TechSnips Twitter @techsnips_io.

Создание лучших сценариев с помощью PowerShell ArrayLists и массивов

Часто при написании сценариев PowerShell вам нужен способ хранения набора элементов.Один из распространенных способов добиться этого - использовать массив или определенный тип, известный как ArrayList. Но что такое массив? Массив - это структура данных, предназначенная для хранения коллекции элементов. Сюда могут входить как одинаковые, так и разные типы предметов.

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

Предпосылки / Требования

Поскольку вы будете работать только с самим языком PowerShell, предварительных условий среды нет. Вам просто нужен ПК с Windows и PowerShell. Более конкретно:

  • Windows PowerShell 3 или более поздней версии
  • .NET Framework 4.5 или более поздней версии

Хотите еще подобных советов? Посетите мой личный блог PowerShell по адресу: https://nkasco.com/FriendsOfATA

Создание массивов с помощью PowerShell

Существует много разных способов создания массивов с помощью PowerShell.Предположим, у вас есть список имен, которые вам нужно как-то обработать, как показано ниже.

  Джон
Сюзи
Джим
Джонни
Кэрри  

Построение массивов с помощью элементов, разделенных запятыми

Самый простой способ создать массив - просто назначить известные входные данные, разделенные запятыми, переменной, как показано ниже.

  $ BasicArray = «Джон», «Сьюзи», «Джим», «Джонни», «Кэрри»  

Если вы запустите метод GetType () , доступный для всех объектов в PowerShell, вы увидите, что вы успешно создали массив, как указано в свойстве BaseType , показанном ниже.

  PS51> $ BasicArray.GetType ()

IsPublic IsSerial Имя BaseType
-------- -------- ---- --------
Истинный Истинный объект [] System.Array  

Использование оператора подвыражения

Вы также можете создавать массивы в PowerShell с помощью оператора подвыражения.Эта концепция обычно используется, когда вы не знаете, сколько элементов будет добавлено в ваш массив. Результат может содержать ноль или много элементов при создании.

Обратите внимание, что массив с именем $ MyArray был создан с нулевыми элементами внутри.

  # Создать пустой массив с помощью оператора подвыражения
PS51> $ MyArray = @ ()
PS51> $ MyArray.count
0  

Использование оператора диапазона

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

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

  PS51> $ NumberedArray = 2..5
PS51> $ NumberedArray
2
3
4
5  

Создание коллекций ArrayList PowerShell

Использование PowerShell ArrayList - это также способ хранения списка элементов с помощью PowerShell.Класс ArrayList является частью пространства имен System.Collections в .NET. Создавая новый объект этого типа, вы можете сохранять объекты в ArrayList.

Ниже вы можете видеть, что вам необходимо явно создать объект ArrayList с помощью командлета New-Object или путем преобразования стандартного массива в объект ArrayList.

Обратите внимание, что в этом случае BaseType является объектом, тогда как в приведенных выше примерах есть BaseTypes массивов, которые демонстрируют наследование от класса Object.В конечном итоге PowerShell предоставляет доступ к системе типов .NET.

  PS51> $ MyArrayList = New-Object -TypeName "System.Collections.ArrayList"
# Приведение массива как ArrayList также является жизнеспособным вариантом
PS51> $ MyArrayList = [System.Collections.ArrayList] @ ()
PS51> $ MyArrayList.GetType ()

IsPublic IsSerial Имя BaseType
-------- -------- ---- --------
Истинная Истинная Система ArrayList.Объект  

Добавление элементов в массив

При создании массива вы можете либо определить все элементы во время создания, либо добавить их по отдельности.

Чтобы добавить элементы в существующую коллекцию, вы можете использовать оператор + = или метод Add . Но знайте, что есть существенные различия в том, как они работают.

Когда вы создаете стандартный массив с помощью @ () , вы будете использовать оператор + = , но для добавления элементов в ArrayList вы будете использовать метод Add .Эти методы отличаются тем, что оператор + = фактически уничтожает существующий массив и создает новый с новым элементом.

Чтобы продемонстрировать, как вы увидите ниже, вы можете ссылаться на свойство IsFixedSize для массива или ArrayList, чтобы узнать, что является неизменяемым, а какое нет.

  PS51> $ BasicArray.IsFixedSize
Правда

PS51> $ MyArrayList.IsFixedSize
Ложь  

Поскольку базовый массив представляет собой набор фиксированного размера, вы не можете его изменять.

Попытка использовать метод Add () с массивом фиксированного размера приведет к ошибке из-за фиксированного размера. Ниже вы можете увидеть несколько примеров, в которых вы можете успешно добавлять элементы в массив.

  # НЕ работает
$ BasicArray.Add ("Нат")

#Работает
$ BasicArray + = "Нат"
$ MyArrayList.Add ("Нат")
$ MyArrayList + = "Nate"  

Удаление элементов из массива

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

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

  $ NewBasicArray = $ BasicArray -ne "Nate"  

Поскольку список ArrayList не является фиксированным, вы можете удалить из него элементы с помощью метода Remove () . Это один из сценариев, в котором использование ArrayList может принести вам пользу, если вы планируете часто добавлять / удалять элементы.

  $ MyArrayList.Remove ("Нейт")  

Получение определенных элементов из массива или списка массивов

Чтобы получить определенные элементы из массива или ArrayList, вы можете использовать множество различных методов. Как и другие объекты в PowerShell, вы можете получить доступ ко всем элементам массива, просто вызвав объект.

  PS51> $ BasicArray
Джон
Сюзи
Джим
Джонни
Кэрри  

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

  PS51> $ BasicArray [0]
Джон  

И наоборот, вы также можете ссылаться на индексы в обратном порядке, используя тире (отрицательный индикатор) для вызова последнего числа X элементов из массива. Обычный способ найти последний элемент в массиве - использовать -1 , как показано ниже.

  PS51> $ BasicArray [-1]
Кэрри  

Оператор диапазона, о котором вы узнали выше, также можно использовать для извлечения объектов массива, следуя тому же методу вызова элементов.Допустим, вы хотите получить первые четыре имени в массиве $ BasicArray .

Как видно ниже, вы можете указать диапазон индексов 0–3, который вернет первые четыре элемента.

  PS51> $ BasicArray [0..3]
Джон
Сюзи
Джим
Джонни  

Оптимизация массивов с помощью PowerShell

Теперь, когда у вас есть хорошая основа для создания массивов и управления ими, какой из них вам следует использовать? Чтобы ответить на этот вопрос, давайте рассмотрим несколько примеров с командлетом Measure-Command .Используя командлет Measure-Command , вы лучше поймете, сколько времени требуется командам для обработки элементов по мере их передачи по конвейеру.

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

Давайте применим то, что вы только что узнали в предыдущем разделе о разнице между + = и использованием метода Add () с циклом из 50 000 элементов.

Сначала создайте пустой массив и пустой список ArrayList, как показано ниже.

  PS51> $ MyArray = @ ()
PS51> $ MyArrayList = [System.Collections.ArrayList] @ ()  

Затем заполните 50 000 элементов в каждой коллекции, используя оператор диапазона и цикл foreach , как показано ниже.

  @ (0..50000) .foreach ({$ MyArray + = $ _})
@ (0..50000) .foreach ({$ MyArrayList.Add ($ _)})  

Наконец, оберните свои команды в выражение и передайте это выражение в командлет Measure-Command .Выполняя выражение с помощью команды Measure-Command , вы можете увидеть, сколько времени фактически требуется для выполнения каждого процесса.

Имейте в виду, что, как вы узнали ранее, + = фактически создает новый массив, а не добавляется к фиксированному.

  PS51> Measure-Command -Expression {@ (0..50000) .foreach ({$ MyArray + = $ _})}
Дней: 0
Часы: 0
Минут: 0
Секунды: 59
Миллисекунды: 58
Тиков: 5

963 Всего дней: 0.000683548568287037 Всего часов: 0,0164051656388889 Всего минут: 0,984309938333333 Всего секунд: 59.0585963 TotalMilliseconds: 59058.5963 PS51> Measure-Command -Expression {@ (0..50000) .foreach ({$ MyArrayList.Add ($ _)})} Дней: 0 Часы: 0 Минут: 0 Секунды: 0 Миллисекунды: 139 Тиков: 1399989 Всего дней: 1.62035763888889E-06 Полный час: 3.88885833333333E-05 Всего минут: 0.002333315 Всего секунд: 0.1399989 Всего миллисекунд: 139.9989

Результат? Почти 60 секунд против 139 миллисекунд !

Как видите, гораздо быстрее использовать ArrayList для больших коллекций, чем использовать массив фиксированного размера.

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

Если у вас есть какой-либо существующий сценарий, который может выиграть от использования ArrayList, а не массива, это предоставит фантастическую возможность сделать мгновенное улучшение!

Дополнительная литература

Хотите еще таких советов? Посетите мой личный блог PowerShell по адресу: https: // nkasco.com / FriendsOfATA.

Связанные

Изучение мощной оболочки PowerShell для сравнения массивов

С помощью некоторого кунг-фу PowerShell вы можете легко сравнить Powershell массивы всех типов объектов. Есть много разных сценариев, в которых вы можете оказаться, поэтому давайте углубимся и посмотрим, как мы можем создать PowerShell для сравнения массивов.

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

  • Оба массива содержат все объекты одного типа?
  • У обоих массивов одинаковое количество элементов?
  • Есть ли в каждом массиве разные типы объектов?

Вы должны знать ответ на каждый из этих вопросов, прежде чем сможете точно сравнивать массивы. Давайте рассмотрим каждый сценарий.

Сравнение массивов строк

Один из самых простых способов сравнить массивы с PowerShell - использовать два массива, содержащих только строки.Когда вы оказываетесь в таком положении, у вас есть несколько различных способов сравнения строк в массивах.

Использование операторов -Contains или -In

Оператор -contains - это оператор PowerShell, который позволяет вам проверять, находится ли объект в коллекции. Оператор -contains изначально не понимает коллекций, но y0u может создать код, чтобы заставить его выполнять ваши ставки.

Допустим, коллекция (массив) содержит четыре строки, как показано ниже.

  $ array = @ ('синий', 'красный', 'фиолетовый', 'розовый')  

Оператор -contains работает, проверяя, находится ли одна строка в этом массиве следующим образом:

  $ массив -содержит розовый  

Когда коллекция слева содержит эту строку, PowerShell вернет True. Если нет, он вернет False.

PowerShell -contains Operator

Мы можем сравнивать массивы с помощью оператора -contains , считывая каждую строку в массиве и проверяя, содержит ли другой массив эту строку.

Допустим, я хочу сравнить два массива, чтобы увидеть, какие строки в первом массиве существуют во втором массиве.

  $ array = @ ('синий', 'красный', 'фиолетовый', 'розовый')
$ array2 = @ ('коричневый', 'красный', 'черный', 'желтый')

$ массив | ForEach-Object {
    if ($ array2 -contains $ _) {
        Write-Host "` $ array2 содержит строку `$ array1 [$ _]"
    }
}  

В качестве альтернативы вы можете использовать оператор -in , который идентичен оператору -contains , но синтаксис противоположен.При использовании оператора -contains массив определяется слева. Используя оператор -in , массив определяется с правой стороны, как показано ниже:

  $ массив | ForEach-Object {
    if ($ _ -in $ array2) {
        Write-Host "` $ array2 содержит строку `$ array1 [$ _]"
    }
}  

Использование Where-Object

В качестве альтернативы вы также можете использовать командлет Where-Object для возврата всех строк из одного массива в другой, как показано ниже.

  $ массив | Where-Object -FilterScript {$ _ -in $ array2}  

Использование командлета Compare-Object

Вы также можете использовать PowerShell для сравнения массивов с помощью командлета Compare-Object . Этот командлет принимает ссылочный объект и объект различия и возвращает боковой индикатор, указывающий, какие элементы находятся, а какие нет в любом массиве.

  Сравнить-объект -ReferenceObject $ array -DifferenceObject $ array2  

Использование Compare-Object

Ниже показано, что командлет Compare-Object позволяет сравнивать оба массива одновременно.Если свойство SideIndicator имеет значение => , это означает, что возвращаемое свойство InputObject находится в значении DifferenceObject , а не в значении ReferenceObject , и наоборот для <= SideIndicator .

По умолчанию Compare-Object возвращает различия. Вы также можете вернуть все строки в каждом массиве, которые есть в обоих, с помощью параметра IncludeEqual .

Сравнение массивов с помощью Compare-Object

Сравнение массивов сложных объектов

Достаточно просто, правда? Теперь давайте добавим объекты в микс.Допустим, у нас есть поле в нашей базе данных HR, и мы хотели бы заполнить его в поле описания Active Directory. Перед этим нам сначала нужно иметь общий идентификатор. В моей среде номер сотрудника есть как в базе данных отдела кадров, так и в настраиваемом атрибуте Active Directory. Итак, давайте попробуем сопоставить это.

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

Вывод CSV

Вот как я получаю наши два набора данных.

  $ ad_users = Get-AdUser -Filter {enabled -eq $ true} -Properties employeeNumber | выберите номер сотрудника, имя учетной записи, описание
$ users_from_database = Import-CSV 'database_users.csv' | выберите номер сотрудника  

Что происходит, когда мы запускаем эти два массива по тому же сценарию, что и наши строки? Совершенно ничего. Почему?

Причина в том, что обычно нельзя сказать $ object1 -eq $ object2 , потому что объекты сложнее простой строки, логического или целого числа.Есть и другие обстоятельства, при которых это не так, но я стараюсь сделать привычкой сравнивать свойства объектов; не целые объекты. Итак, в этом случае мы должны сделать что-то вроде этого:

  $ ad_user [0] .employeeNumber -eq $ users_from_database [0] .employeeNumber  

Какое решение? В настоящее время у меня есть два решения. При работе с тысячами объектов это не быстро, но работает. Я хотел бы знать, есть ли у кого-нибудь еще какие-нибудь предложения.

  $ ad_employee_numbers = $ ad_users | % {$ _.количество сотрудников}

## Создайте массив строк только с номером сотрудника пользователя AD
$ users_from_database | Where-Object -FilterScript {$ ad_employee_numbers -contains $ _. EmployeeNumber}  

Мы также можем использовать Compare-Object , хотя это медленнее.

  $ ad_employee_numbers = $ ad_users | ForEach-Object {$ _. Employeeenumber}

## Создайте массив строк только с номером сотрудника пользователя AD
$ database_user_employee_numbers = $ users_from_database | ForEach-Object {$ _.количество сотрудников}

## Создайте массив строк только с номером сотрудника пользователя базы данных
(Сравнить-объект $ ad_employee_numbers $ database_user_employee_numbers -IncludeEqual | Where-Object -FilterScript {$ _. SideIndicator -eq '=='}). InputObject  

Заключение

Есть много разных способов использовать PowerShell для сравнения массивов. Массивы могут быть сложными, и тщательное изучение объектов внутри массивов очень поможет вам сравнить их.

Связанные

Массивы PowerShell для организации и обработки ваших данных

Переменные и массивы являются неотъемлемой частью любого языка программирования, поскольку они образуют строительные блоки вашего кода.Вы используете переменные для хранения значений, их обработки и даже, возможно, отображения или передачи их в любую другую часть программы. Переменные могут содержать только одно значение в любое время. Но в реальном мире вы, скорее всего, столкнетесь с несколькими переменными, учитывая сложность систем и проблемы, требующие решения. В таком случае вам нужна структура данных, которая будет хранить вместе ряд значений. Массивы PowerShell - это мощная структура данных, в которой вы можете хранить набор элементов любого типа в последовательном порядке.Каждый элемент в массиве идентифицируется индексом, который начинается с 0. Итак, первое значение в массиве находится в индексе 0, второе - в индексе 1 и так далее. В этом смысле массив - это набор последовательно расположенных элементов или переменных.

Создание массивов PowerShell

В качестве первого шага давайте посмотрим, как можно создавать массивы PowerShell.

$ myArray = 1,2,3,4,5,6

Этого простого объявления достаточно, чтобы сообщить PowerShell, что вы собираетесь создать массив с элементами от 1 до 6.

Теперь, если вы хотите проверить, действительно ли PowerShell создал массив, вы можете сделать это с помощью этой команды:

$ myArray.getType ()

Результатом будет:

System.Array

Звучит просто, правда?

Теперь, что произойдет, если вы хотите создать массив только с одной переменной на данный момент с возможностью добавления дополнительных значений позже?

Ваше первое предположение может быть таким:

$ myArray = 1

Достаточно честно.Теперь, если вы наберете:

$ myArray.getType ()

Результатом будет:

System.ValueType

Другими словами, PowerShell создал переменную вместо массива, потому что существует только одна переменная, и предполагается, что вы хотите создать переменную и присвоить ей значение.

Хорошая новость в том, что существует множество способов указать PowerShell создать массив с одной переменной в нем.

Самый простой вариант - использовать запятую «,», чтобы сообщить PowerShell, что вы хотите.

$ myArray =, 1

Теперь вывод для $ myArray.getType () будет System.Array .

Если это кажется запутанным, вы можете явно указать PowerShell, что вы хотите создать массив. Синтаксис для этого:

[объект []] $ myArray = 1

Когда вы вводите этот код, PowerShell знает, что вы хотите создать массив, и сделает это за вас с одной переменной в нем.

Третий способ создания массива:

$ myArray = @ ()

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

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

[int32 []] $ myArray = 1,2,3

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

Доступ к массиву PowerShell

Доступ к значениям из массива PowerShell тоже довольно прост.Например:

$ myArray = 1,2,3,4,5,6

Допустим, вы хотите получить доступ к первому объекту. Все, что вам нужно сделать, это:

$ myArray [0]

Это будет иметь доступ к первому элементу в вашем массиве, который равен «1».

Обычно ваш массив хранит такую ​​переменную:

$ myArray [0] - 1

$ myArray [1] - 2

$ myArray [2] - 3

$ myArray [3] - 4

$ myArray [4] - 5

$ myArray [5] - 6

Вы можете получить доступ к значению на основе этой последовательной нумерации.Если вы хотите, чтобы все элементы были напечатаны, просто используйте $ myArray.

 Запись-вывод («Все элементы в массиве:»)
$ myArray
 

Результат будет таким, как показано на следующем снимке экрана:

После создания массивов PowerShell вы можете назначать значения непосредственно в определенное место, хотя напрямую жестко кодировать значения не рекомендуется. Тем не менее, это вариант, который может пригодиться в некоторых ситуациях. Например, вы можете сказать:

$ myArray [3] = 8

Если вы напечатаете $ myArray, вы получите 1,2,3,8,5,6.

Обработка массивов PowerShell

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

Знание длины вашего массива PowerShell

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

$ myArray.Длина

Это даст вам количество элементов, которое в нашем примере равно 6.

Частичная обработка

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

$ SmallList = $ myArray (2..5)

Теперь массив $ SmallList будет содержать значения от $ myArray [2] до $ myArray [5], которые в нашем примере составляют 3,4,5,6.

Использование значений массива PowerShell в цикле

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

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

 $ я = 0
while ($ i - $ myArray.Length) {
$ myArray [$ i] = $ myArray [$ i] + 10;
$ i ++
}
 

Это напечатает эти значения: 11, 12, 13, 14, 15, 16, как показано на скриншоте ниже.

Как видите, это разные способы доступа к элементам в массиве PowerShell и их обработки.

Расширенное использование массивов PowerShell

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

ArrayList

PowerShell имеет класс под названием ArrayList, который упрощает добавление, удаление или поиск элементов в массиве.

Чтобы использовать этот класс, вы должны сначала преобразовать свой массив в класс ArrayList.Код для этого:

$ myArray = Новый объект System.Collections.ArrayList.

Когда вы выполняете этот код, ваш массив преобразуется в ArrayList. Если вы напечатаете $ myArray.getType (), на выходе будет System.Object.

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

Например, предположим, что значениями массива с именем $ namesArray являются Джон, Сэм, Бетти, Лаура.

Чтобы добавить другое имя, все, что вам нужно сделать, это:

$ namesArray.Добавить ("Сьюзи")

Когда вы печатаете значения $ namesArray, у него будет пять элементов, последним будет Susie. Обратите внимание, что значение будет добавлено только в конце.

Чтобы удалить значение:

$ namesArray.Remove ("Бетти")

На выходе будут Джон, Сэм, Лора, Сьюзи.

Вы также можете выполнить поиск в массиве, используя метод Contains:

$ namesArray.Contains ("Джон")

На выходе будет «True.”

Приведенные выше примеры показывают, насколько легко добавлять, удалять или искать элементы в массиве с помощью класса ArrayList.

Очистка массива PowerShell

Мы видели создание, доступ, добавление, удаление и множество других операций. Итак, как удалить массив?

К сожалению, в PowerShell нет простого способа удалить массив. Наверное, самый простой способ - присвоить ему значение $ null.

$ myArray = $ ноль

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

Использование методов

Есть много встроенных методов, которые облегчают вам жизнь. Например, если вы хотите отсортировать содержимое вашего массива, вам не нужно запускать его через цикл. Простая команда сортировки сделает всю работу за вас.

$ namesArray | сорт

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

Вы можете экспортировать свой массив в файл .csv с помощью этой команды:

$ namesArray | Экспорт-CSV-Путь C: \ studentnames.csv

Вы также можете записать эти значения в файл HTML с помощью этой команды:

$ namesArray | ConvertTo-Html> C: \ studentnames.html

Заключительные мысли о массивах PowerShell

Массивы

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

Рекомендуемое изображение: Piqsels

Просмотры сообщений:
992

Другие статьи об основах PowerShell


.

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

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