Проверка нескольких условий без перерыва в Powershell. Powershell where несколько условий


powershell - Проверка нескольких условий без перерыва в Powershell

Да, вы можете написать его без, if тесты, например,

$colors = @('Red', 'Green') $messages = @('[X] Failed -', '[√] Succeeded -') $username = "user.adm" $result = [bool](net user "$username") Write-Host "$($messages[$result]) Check user account exists" -ForegroundColor $colors[$result] $result = [bool]((uACADA "$username") -band 65536) Write-Host "$($messages[$result]) Check password never expires" -ForegroundColor $colors[$result] $result = [bool]((Get-ADGroupMember -Identity "Domain Admins").Name -contains "$username") Write-Host "$($messages[$result]) Check account is a domain admin" -ForegroundColor $colors[$result] $result = [bool]((uACADA "$username") -band 1048576) Write-Host "$($messages[$result]) Check Delegation Authority removed" -ForegroundColor $colors[$result]

NB. что если вы не используете if/else, вам понадобится другой способ выполнить тестирование true/false. Я привожу результаты в [bool] и используя 2-элементные массивы. $array[$false] casts $false → 0 и получает элемент 0, $array[$true] отличает $true → 1 и получает элемент 1. То, как результат превращается в соответствующие цвета и сообщения.

Другим разумным способом написать это было бы перемещение Write-Hosts в функцию.

Function Report-Result { param($Result, $Text) if ($Result) { Write-Host "Success - $Text" -Fore Green } else { Write-Host "Failure - $text" -Fore Red } } $result = [bool](...) report-result $result "Check password never expires" ... etc.

Результат выглядит так:

Что хорошо - он получает ваши 20 строк кода до ~ 10 и не имеет гнездования и запускает все тесты.

Но действительно кажется, что вы повторно изобретаете PowerShell DSC ("мое желаемое состояние - это то, что учетные записи с.adm в конце имеют свои пароли, которые никогда не истекают") или Pester - тестовую среду PowerShell ("проверьте, что все.adm у учетных записей есть пароли, которые никогда не истекают ").

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

1. Here are my tests, with self-explanatory names 2. Here is a loop which runs all tests, and reports on them

и это дает мне что-то вроде:

Function Validate-DCUserAccountShouldExist { param($Username) [bool](net user "$UserName") } Function Validate-DCUserAccountPasswordNeverExpireShouldBeSet { param($Username) [bool]((uACADA "$username") -band 65536) } Function Validate-DCUserAccountShouldBeADomainAdmin { param($Username) [bool]((Get-ADGroupMember -Identity "Domain Admins").Name -contains "$username") } Function Validate-DCUserAccountShouldHaveDelegationAuthorityRemoved { param($Username) [bool]((uACADA "$Username") -band 1048576) } # Search for all Validation functions and run them $tests = (gci function: |Where Name -Like 'Validate-DCUserAccount*').Name foreach ($test in $tests) { $result = try { & $test "user.adm" } catch { $false } if ($result) { Write-Host -ForegroundColor Green "[√] $test - succeeded" } else { Write-Host -ForegroundColor Red "[X] $test - Failed" } }

Который дает выход как:

Мой взгляд на мой второй код:

  • Это дольше
  • более сложно, менее легко следовать
  • гораздо меньше дублирования Write-Host
  • более структурированное, разделение определений тестов и результатов
  • имена функций объясняют, каково должно быть состояние, что делает выходные сообщения успешными/неудачными
  • Выходные сообщения в коде более аккуратные, но более уродливые для чтения в выходном файле (но могут быть скорректированы, например, при печати)
  • будет масштабироваться до большего количества тестов, просто добавив больше тестов

qaru.site

powershell - Операторы нескольких условий в Where-Object

#foo.csv Month, Name, First, Second, Third, Status 2015/01, 'Google', 02-02-2014, 03-02-2014, 03-02-2015, "Lost" 2015/01, 'Google', 03-01-2014, 03-01-2014, 03-02-2015, "Active" 2015/02, 'Google', 06-02-2013, 03-01-2014, N/A, "Lost" 2015/02, 'Yahoo', 07-02-2013, 06-01-2015, 03-02-2015, "Active" 2015/02, 'Google', 07-02-2013, 06-01-2015, 03-02-2015, "Lost" 2015/02, 'Yahoo', 03-01-2014, 06-01-2015, N/A, "Active" 2015/02, 'Google', 06-01-2015, 06-01-2015, 03-02-2015, "Lost" 2014/12, 'Yahoo', 03-01-2014, 06-01-2015, 03-02-2014, "Active" 2014/12, 'Google', 03-05-2014, 06-01-2015, N/A, "Active" 2014/12, 'Yahoo', 06-01-2015, 06-01-2015, 03-02-2014, "Active" Import-Csv "E:\foo.csv" | Where-Object {($_."Name" -eq "Google") ' -and ($_."Third" -gt (get-date).AddDays(-27).ToString("yyy-MM-dd") -or $_."C3 Date" -eq "N/A") ' -and # where month is last two months while Status is only Active ' -and # no current months (Feb) data/values of last years from First and Second column }

Заметка: Значения столбцов месяца в формате строки. (Так что проблем нет). Отдых находится в формате даты dd-mm-yyyy (например, 23-12-2014)

Я пытаюсь выбрать только нужные записи из выше csv файла, шаги выбора следующие:

  1. Сначала выберите только записи Google.
  2. Затем выберите только те записи, где указана дата третьего столбца текущего месяца или N/A.
  3. Затем возьмите только те записи, где значение месяца равно последним двум месяцам, и в то же время статус должен быть активным.
  4. И, наконец, пропустите те записи за текущие месяцы (февраль) за прошлый год (например, 2014/02, 2013/02, но не 2015/02) из первого и второго столбцов.

Я могу писать скрипт до, всего 2 шага. И выход соответствует желаемому счету. 3 и 4 шага содержат несколько, если условия/логика, которые я не могу написать и понять.

Примечание: 2-я и 9-я записи в foo.csv - это точные записи, которые мы ищем, которые удовлетворяют всем условиям.

Изменить: исправлена 9-я запись. Когда я попробовал код Мэтта, я получил следующую ошибку:

The operation '[System.Int32] - [System.DateTime]' is not defined. At line:8 char:29

В моей информации о культуре я могу видеть en-GB, но я хочу, чтобы она была независимой от культуры. Раньше это была логическая часть, с которой я боролся, но теперь ее дата (форматирование и сопоставление). Я читал о форматировании даты и времени за последние 2 дня. Я попытался изменить yyyy на yy или yyy, даже если это вызвало ошибку. Все еще пытаюсь понять это правильно только для 2-го условия относительно даты выпуска, но пока не удалась.

Изменить 2: Ниже приведен код POC, который содержит несколько частей, но я не могу контролировать формат даты здесь, потому что в будущем данные могут изменяться в csv dd-mm-yyyy до mm-dd-yy или что-то еще.

Import-Csv E:\foo.csv | Select-Object @{Label="Third"; Expression={[datetime]$_.Third}} | Where-Object { $_.Third -gt [datetime]'01-03-2015' } | Format-Table -Auto

Кроме того, есть ли вероятность, что при преобразовании даты в формат даты и времени N/A останется таким, какой он есть?

qaru.site

Удаление объектов из конвейера (Where-Object)

В оболочке Windows PowerShell часто создается и передается на конвейер большее количество объектов, чем требуется. Чтобы указать свойства конкретного объекта, которые требуется отобразить, можно воспользоваться командлетом Format, но это не позволяет решить проблему удаления с экрана всех объектов. Может возникнуть необходимость отфильтровать объекты до достижения конца конвейера, чтобы выполнить те или иные действия только на подмножестве объектов, созданных изначально.

В оболочке Windows PowerShell имеется командлет Where-Object, позволяющий проверить каждый объект в конвейере и передать его дальше по конвейеру, только если объект удовлетворяет условиям проверки. Объекты, не прошедшие проверку, удаляются из конвейера. Условия проверки передаются в виде значения параметра Where-Object FilterScript .

Выполнение простых проверок с командлетом Where-Object

Значение FilterScript представляет собой блок скрипта — одну или несколько команд Windows PowerShell, заключенных в фигурные скобки {}, — результатом которого могут быть значения TRUE или FALSE. Такие блоки скриптов могут быть очень простыми, но для их создания требуется понимание другого основного понятия Windows PowerShell, а именно операторов сравнения. Оператор сравнения сравнивает элементы, расположенные с обеих сторон оператора. Запись операторов сравнения начинается знаком "-", после которого следует имя оператора. Основные операторы сравнения работают, как правило, с любыми видами объектов. Более сложные операторы сравнения работают только с текстом или массивами.

Примечание.

По умолчанию при работе с текстом в оболочке Windows PowerShell операторы сравнения нечувствительны к регистру.

Исходя из соображений синтаксического анализа, знаки, такие как <,> или "=", не используются в качестве операторов сравнения. Вместо этого операторы сравнения записываются в буквенной форме. Основные операторы сравнения перечислены в таблице ниже.

Оператор сравнения Тип свойства Пример (возвращает значение TRUE)

-eq

равно

1 -eq 1

-ne

не равно

1 -ne 2

-lt

меньше, чем

1 -lt 2

-le

меньше или равно

1 -le 2

-gt

больше, чем

2 -gt 1

-ge

больше или равно

2 -ge 1

-like

сравнение на совпадение с учетом подстановочного знака в тексте

"file.doc" -like "f*.do?"

-notlike

сравнение на несовпадение с учетом подстановочного знака в тексте

"file.doc" -notlike "p*.doc"

-contains

содержит

1,2,3 -contains 1

-notcontains

не содержит

1,2,3 -notcontains 4

В блоках скриптов командлета Where-Object для обращения к текущему объекту конвейера используется специальная переменная $_. Ниже приведен пример использования этой переменной. Если в списке содержатся числа и требуется вернуть только меньшие 3, в командлете Where-Object можно настроить фильтр чисел:

PS> 1,2,3,4 | Where-Object -FilterScript {$_ -lt 3} 1 2

Фильтрация данных, основанная на свойствах объектов

Поскольку переменная $_ обращается к текущему объекту конвейера, для выполнения проверок можно получить доступ к ее свойствам.

Например, в WMI можно просмотреть класс Win32_SystemDriver. В какой-то конкретной системе могут содержаться сотни системных драйверов, но для проверки необходим определенный набор системных драйверов — таких, которые запущены в данный момент. Если для просмотра объектов класса Win32_SystemDriver использовать командлет Get-Member (Get-WmiObject -Class Win32_SystemDriver | Get-Member -MemberType Property), можно увидеть, что свойство State принимает значение Running, когда драйвер запущен. Таким образом, фильтровать системные драйверы и выбирать только запущенные можно с помощью строки:

Get-WmiObject -Class Win32_SystemDriver | Where-Object -FilterScript {$_.State -eq "Running"}

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

PS> Get-WmiObject -Class Win32_SystemDriver | Where-Object -FilterScript {$_.State -eq "Running"} | Where-Object -FilterScript {$_.StartMode -eq "Auto"} DisplayName : RAS Asynchronous Media Driver Name : AsyncMac State : Running Status : OK Started : True DisplayName : Audio Stub Driver Name : audstub State : Running Status : OK Started : True

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

PS> Get-WmiObject -Class Win32_SystemDriver | Where-Object -FilterScript {$_.State -eq "Running"} | Where-Object -FilterScript {$_.StartMode -eq "Manual"} | Format-Table -Property Name,DisplayName Name DisplayName ---- ----------- AsyncMac RAS Asynchronous Media Driver Fdc Floppy Disk Controller Driver Flpydisk Floppy Disk Driver Gpc Generic Packet Classifier IpNat IP Network Address Translator mouhid Mouse HID Driver MRxDAV WebDav Client Redirector mssmbios Microsoft System Management BIOS Driver

Приведенная выше команда содержит два элемента Where-Object, но их можно объединить в один элемент Where-Object, используя знак "-" и логический оператор:

Get-WmiObject -Class Win32_SystemDriver | Where-Object -FilterScript { ($_.State -eq "Running") -and ($_.StartMode -eq "Manual") } | Format-Table -Property Name,DisplayName

Стандартные логические операторы перечислены в следующей таблице.

Логический оператор Значение Пример (возвращает значение TRUE)

-and

Логическое И; возвращает значение TRUE, если оба операнда принимают значение TRUE

(1 -eq 1) -and (2 -eq 2)

-or

Логическое ИЛИ; возвращает значение TRUE, если один из операндов принимает значение TRUE

(1 -eq 1) -or (1 -eq 2)

-not

Логическое НЕ; изменяет значение (TRUE или FALSE) на противоположное

-not (1 -eq 2)

!

Логическое НЕ; изменяет значение (TRUE или FALSE) на противоположное

!(1 -eq 2)

winintro.ru

Проверка выполнения нескольких условий с помощью инструкции switch в PowerShell | Windows IT Pro/RE

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

Создание инструкций switch

Инструкция switch осуществляет сопоставление одного или нескольких значений с одним или несколькими условиями. Каждый раз, когда результатом такого сопоставления является значение true, инструкция выполняет блок сценария, ассоциированный с соответствующим условием. Чтобы лучше понять, как функционирует инструкция switch, рассмотрим ее синтаксис:

switch () {    {

Первая строка начинается с ключевого слова switch, за которым следует один или несколько параметров и коллекция. Инструкция switch допускает использование пяти параметров, которые дают возможность, к примеру, применять подстановочные символы и регулярные выражения. Коллекция заключается в скобки и содержит проверяемые объекты (скажем, события или файлы). Она может не включать ни одного элемента или произвольное их число.

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

Рассмотрим пример. Код в листинге 1 определяет переменную $event и задействует ее в инструкции switch. В первой строке используется команда Get-EventLog. С ее помощью из журнала регистрации системных событий локального компьютера извлекается последнее событие. Когда эта команда применяется для извлечения записей журнала регистрации системных событий, она возвращает объект Microsoft.NET Framework System.Diagnostics.EventLogEntry для каждого события, а этот объект возвращает сведения, которые обычно содержатся в записи журнала регистрации системных событий: когда произошло событие, каков его тип и каково сообщение этого события.

В листинге 1 команда Get-EventLog присваивает эти сведения, касающиеся последнего события, переменной $event в качестве ее значения. С помощью свойства EntryType объекта EventLogEntry инструкция switch считывает тип события и сопоставляет этот элемент с заданными условиями.

Листинг 1. Код, считывающий последнюю запись в журнале регистрации системных событий

В инструкции switch в качестве условия можно просто указать то или иное значение. Затем PowerShell автоматически сопоставляет это значение с каждым элементом коллекции. Как явствует из фрагмента A листинга 1, первое условие определяется как ошибка (error). Когда же это значение равно элементу коллекции (т. е. значению свойства EntryType), условие считается выполненным, и блок сценария запускается на выполнение. Иными словами, когда тип события — ошибка, блок сценария выдает слово ERROR:, за которым следует сообщение события; последнее считывается с помощью свойства Message объекта EventLogEntry.

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

Отметим, что по умолчанию инструкция switch нечувствительна к регистру символов. Так, первое условие можно выразить с помощью слов error, ERROR или Error; в любом случае результат будет один и тот же. Но эту принимаемую по умолчанию настройку можно переопределить, указав параметр -casesensitive, как в следующем примере:

switch -casesensitive ($event.EntryType)

Хочу сделать еще одно замечание, касающееся коллекции. Код в листинге 1 считывает значение свойства EntryType как часть коллекции. Однако это значение можно считать в условиях, как показано в листинге 2.

Листинг 2. Код, показывающий еще один способ считывания последней записи в журнале регистрации системных событий

Отметим, что теперь коллекция включает в себя только $event. В заданных условиях для ссылки на текущее значение $event используется встроенная переменная $_, а затем применяется свойство EntryType для считывания типа записи. При использовании этого подхода необходимо определять условие полностью и заключать его в скобки. К примеру, условие {$_.entrytype -eq «error»} явным образом указывает, что значением EntryType должна быть ошибка. листинг 2 возвратит те же результаты, что и листинг 1.

Имея дело с коллекцией, состоящей всего лишь из одного элемента, вы, вероятно, будете придерживаться первого подхода, потому что он проще. Но в случаях, когда коллекция включает в себя несколько элементов, придется применять второй подход, если инструкция switch не может работать с коллекцией «как есть». К примеру, если используется команда Get-EventLog для возвращения нескольких системных событий, нужно будет считывать значение EntryType в каждом условии, как видно из листинга 3. В этом коде коллекция указывает лишь имя переменной $events. Данная коллекция содержит 10 последних системных событий. В условиях для считывания типа записи используется свойство EntryType. В листинге 3 возвращаются результаты, подобные тем, что показаны на экране 1.

Листинг 3. Код, считывающий 10 последних записей в журнале регистрации системных событий

Если мы вновь обратимся к синтаксису инструкции switch, то увидим, что в последней строке блока сценария этой инструкции содержится применяемое по умолчанию предложение. Код в листинге 4 не определяет третье условие, а ограничивается применяемым по умолчанию предложением. Любое событие, не содержащее значение «ошибка» в EntryType или предупреждения, рассматривается как случай по умолчанию, а это значит, что возвращаемое сообщение будет начинаться со слов Info only:. листинг 4 возвращает те же результаты, что и листинг 3, но он несколько проще.

Листинг 4. Код, использующий предложение по умолчанию

Использование шаблонов и регулярных выражений

По умолчанию строковое значение, указанное в сценарном блоке инструкции switch, должно в точности соответствовать одному условию, а именно исходить из того, что данное условие выполнено. Это равнозначно использованию параметра -exact в инструкции switch. Но даже при том, что данный параметр необязательно предусматривает точные совпадения, администратор может включить его с тем, чтобы с определенностью выразить назначение кода; это будет полезно, если код придется просматривать другому человеку.

Кроме параметра -exact существуют параметры, позволяющие использовать в инструкциях switch шаблоны (параметр -wildcard) или регулярные выражения (параметр -regex). Если вы незнакомы с шаблонами или с регулярными выражениями, просмотрите разделы справочной системы PowerShell about_wildcard и about_regular_expression. Так, инструкция switch в листинге 5 использует шаблоны для перемещения файлов. Первая строка считывает список текстовых файлов и назначает их переменной $files, которая становится коллекцией. Обратите внимание, что перед ($files) указывается параметр -wildcard; тем самым PowerShell сообщается, что будет использоваться шаблон.

Так, в условии, приведенном во фрагменте A листинга 5, применяется шаблон *2007*; это значит, что имя файла должно содержать строку 2007 с любым числом знаков по левую или правую сторону. Если имя файла содержит строку 2007, инструкция switch перемещает этот файл в папку 2007 и отображает сообщение о том, что данный файл был перемещен. Коллекция содержит восемь файлов, поэтому PowerShell возвращает восемь сообщений, как показано на экране 2.

Так же, как в листингах 3 и 4, в листинге 5 используется только имя переменной ($files, $event) для коллекции. Но, в отличие от листингов 3 и 4, листинг 5 указывает в каждом условии только встроенную переменную $_, а не переменную $_.PropertyName (где PropertyName — это имя свойства, которое требуется получить). Иногда единственным способом для определения того, какой вариант сработает, является метод проб и ошибок.

Листинг 5. Код, использующий шаблоны для перемещения файлов

Когда нужно использовать регулярные выражения, применяется параметр -regex. Так, инструкция switch в Листинге 6 использует два регулярных выражения, первое из которых — условие во фрагменте A. В этом условии регулярное выражение archive.._200 [3–5].txt используется для удаления всех файлов, имена которых начинаются со строки archive и заканчиваются строкой _2003.txt, _2004.txt или _2005.txt. Условие во фрагменте B содержит регулярное выражение archive.._2006.txt, которое используется для перемещения в папку 2006 всех файлов, имена которых начинаются со строки archive и заканчиваются строкой _2006.txt. Применяемое по умолчанию предложение перемещает все прочие файлы в папку 2007. На экране 3 показаны сообщения, отображаемые при выполнении кода листинга 6.

Листинг 6. Код, обеспечивающий удаление и перемещение файлов с помощью регулярных выражений

Я уже отмечал, что инструкция switch допускает применение параметра -casesensitive, который позволяет выполнять сопоставление с учетом регистра символов. Как показано в листинге 7, этот параметр можно использовать с другими параметрами. Обратите внимание, что в данном фрагменте вместо строки -casesensitive я использую строку -case. Краткая версия имени параметра допускается в тех случаях, когда PowerShell может распознать корректный параметр.

Листинг 7. Код, в котором используются параметры -regex и -casesensitive

При использовании параметра -casesensitive имена файлов должны в точности соответствовать заданному образцу. Так, второе условие (archive.._2006.txt) выполняется для файла archive05_2006.txt, но не для файла Archive05_2006.txt. Поскольку все восемь файлов начинаются с прописной буквы, в данном случае применяется используемое по умолчанию условие, и все восемь файлов перемещаются в папку 2007, как показано на экране 4.

Работа с содержимым файла

Еще один полезный параметр — это -file. Он применяется, когда нужно использовать содержимое файла в качестве коллекции. Каждая строка файла представляет элемент коллекции. Например, следующая инструкция switch считывает содержимое файла Archive08_2007.txt:

switch -regex -file ` C:ArchivedFilesArchive08_2007.txt {    "line 1)$" {«Line 1: $_"}    "line 2)$" {«Line 2: $_"}    "line 3)$" {«Line 3: $_"}    "line 4)$" {«Line 4: $_"}    default {"Other line: $_"} }

Как видно из этого примера, после ключевого слова -file необходимо указывать имя маршрута к файлу. В блоке сценария инструкции switch первое условие гласит, что строка должна заканчиваться символами line 1). Если это условие выполняется, на печать выводится фраза Line 1:, а после нее следует сама строка ($_). Если ни одно из четырех условий не выполняется, запускается предложение по умолчанию, как показано на экране 5.

Следующие шаги

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

Роберт Шелдон ([email protected]) — технический консультант и автор книг по технологиям Microsoft Windows и базам данных

Экран 1. Считывание 10 последних записей в журнале регистрации системных событий

Экран 5. Использование содержимого файла в качестве коллекции

www.osp.ru