Глава 6. Администрирование Windows и Linux
Содержание
- Глава 6. Администрирование Windows и Linux
- Технические требования
- Включение свойств Windows
- Установка групп пакетов Linux
- Создание учётных записей Windows
- Создание учётных записей Linux
- Изменение реестра Windows
- Изменение файлов настроек Linux
- Регистрация новой службы Windows
- Включение нового демона Linux
- Планирование расписания Windows
- Планирование заданий Cron Linux
- Создание пула хранения Windows
- Создание программного RAID устройства Linux
- Доступ к журналу событий Windows
- Работа с системными журналами в Linux
Администраторы совершенно обычно пользуются PowerShell в Windows для управления своей операционной системой. Однако, PowerShell также полезный инструмент в Linux для управления и этой операционной системой. Хотя и не все функции Linux реализованы в выделенных модулях PowerShell, мы всё же можем применять мощные возможности обработки PowerShell для управления этой ОС.
Данная глава может выглядеть как базовое сопоставление в пользу Windows, но это не так. Она просто иллюстрирует необходимость в большем числе cmdlet PowerShell, которые работают как с операционными системами Linux, так и с Windows.
В этой главе мы рассмотрим следующие рецепты:
-
Включение свойств Windows
-
Установку групп пакетов Linux
-
Создание учётных записей Windows
-
Создание учётных записей Linux
-
Изменения в реестре Windows
-
Изменения файлов настройки Linux
-
Регистрацию новой службы Windows
-
Включение нового демона Linux
-
Планирование расписания задач Windows
-
Создание задания Cron Linux
-
Создание пула хранения Windows
-
Создание программного RAID устройства Linux
-
Доступ к журнналу событий Windows
-
Работа с регистрацией системы в Linux
Чтобы проследовать по всем рецептам, вам потребуется одна система Windows и одна система Linux. Все рецепты Linux были выполнены в CentOS 7.4. Чтобы установить обе одним махом отыщите один из рецептов AutomatedLab с названием ALLovesLinux для создания некой среды домена с Windows Server 2016 and CentOS.
Файлы кода для данной главы можно отыскать по ссылке на GitHub.
Одной из наиболее основных задач в сервере Windows является включение некого свойства (feature) Windows. К сожалению,
сам модуль ServerManager
не поддерживается в PowerShell Core. Существуют
зависимости для полного .NET Framework, которые могут приводить к проблемам даже при установленном Windows Compatibility
Pack.
Конечно же, имеются способы обхода этого.
Установите и запустите в сервере Windows PowerShell Core.
Выполните, пожалуйста, следующие шаги:
-
В PowerShell Core установите модуль
WindowsCompatibility
, как это показано в нашем следующем примере:# Сейчас он поставляется пустым Get-Module -ListAvailable -SkipEditionCheck -Name ServerManager # Тем не менее, преданные люди, такие как Брюс Пайетт, Стив Ли и Марк Краус сделали это возможным Install-Module -Name WindowsCompatibility -Scope CurrentUser -Force -AllowClobber
-
Чтобы всё заработало, вам необходимо импортировать такой желаемый модуль. В нашем случае,
ServerManager
, как это показано в следующем примере:# При помощи данного модуля для несовместимых модулей применяется неявное удалённое взаимодействие # Одним из них является ServerManager Import-WinModule -Name ServerManager
-
Обнаружьте все экспортированные cmdlet обычными методами, как это показывается в следующем примере:
# Теперь также работают и cmdlet обнаружения Get-Command -Module ServerManager
-
Все cmdlet теперь работают и ведут себя просто отлично, что показано в примере далее:
# Внезапно всё заработало просто отлично Get-WindowsFeature Get-WindowsFeature -Name powershell-v2
-
Избавление от дыры в безопасности теперь простое снова, как мы это можем видеть в своём очередном примере:
# естественно при неявном удалённом взаимодействии конвейерная обработка повержена и утрачена # В данном случае, однако, она работает прекрасно Get-WindowsFeature -Name powershell-v2 | Remove-WindowsFeature
-
Это касается и инструментов управления установкой или включения прочих свойств, как видно из приводимого примера:
# само собой разумеется, что добавление свойств тоже делается просто Get-WindowsFeature -Name RSAT-AD-Tools | Install-WindowsFeature
Даже несмотря на то, что это выглядит как некий модуль сценария, если вы испробуете ServerManager
в имеющемся модуле пути, он потребует дополнительных компоновок, которые далеко не всегда совместимы.
Наш модуль WindowsCompatibility
является важным когда дело касается простого
администрирования сервером. Хотя многие модули являются так называемыми модулями CDXML
(Cmdlet Definition XML, XML определения cmdlet), которые работают
сразу после установки, некоторые важные ими не являются, и никогда ими не будут. Модули CDXML, по существу, обёртывают
cmdlet вокруг взаимодействия CIM и, тем самым, просто работают как это было предусмотрено.
-
Learn PowerShell Core 6.0 и Jan-Hendrik Peters удалённо
-
Для ознакомления с документацией по
WindowsCompatibility
, посетите GitHub
Многие инструменты управления пакетами Linux поддерживают установку групп пакетов для соответствующих пакетов. Это не совсем сопоставимо со свойствами Windows. К примеру, некой группой пакетов может быть некий базовый веб сервер и он будет содержать такие пакеты как Apache2, Perl и Python.
Установите и запустите PowerShell Core.
Выполните, пожалуйста, следующие шаги:
-
Прежде всего, нам требуется ознакомиться с самой системой и опросить все установленные группы пакетов, что показано в следующем коде:
# Давайте для начала определимся на месте yum groups list
-
Фильтрация вывода команд в Linux через PowerShell очень простая, даже для пришедших из Windows администраторов, что мы можем обнаружить по следующему примеру:
# Так как команды ОС всегда возвращают текст,мы можем применять PowerShell для # получения именно тех сведений, которые нам требуются yum groups list | Select-String 'Web Server' (yum groups list) -match 'Web Server'
-
Обратите внимание, что получаемый вывод не отфильтрован целиком; наша команда
yum
, как оказывается, пишет предупреждающие сообщения в свой поток ошибок. Мы запросто можем избавиться от них с помощью таких операторов перенаправления:# Подавляем имеющийся поток ошибок (yum groups list 2>$null) -match 'Web Server'
-
Теперь, когда у нас есть то что нам требуется, мы можем и дальше применять команды
yum
и реагировать на их состояние при помощи встроенных переменных, как это делается в ещё одном примере:$groupname = ((yum groups list 2>$null) -match 'Web Server').Trim() yum groups install $groupname -y # Не применяя Start-Process, всё что мы получаем, так это значение кода самого последнего выхода if ($LASTEXITCODE -ne 0) { Write-Warning "Installing $groupname failed" }
-
Применение
Start-Process
, хотя и не так натурально выглядит, по сравнению с обычным запуском команды, предлагает больше контроля и понимания, что видно из такого примера:# Попробуйте это снова в процессе - будьте внимательнее при использовании отметки двойными кавычками $process = Start-Process -FilePath yum -ArgumentList groups,install, "`"$groupname`"", '-y' -Wait -PassThru if ($process.ExitCode -ne 0) { Write-Warning "Installation with the following command line failed: $($process.StartInfo.FileName) $($process.StartInfo.Arguments)" }
-
Для перечисления всех установленных пакетов мы можем вновь положиться на PowerShell для надлежащей обработки возвращаемой текстовой информации, как это демонстрирует следующий пример:
# Теперь наши инструменты отображают вывод как следует # Получение правильного текста очень простое благодаря потрясающим возможностям PowerShell (yum groups list 2>$null | Out-String) -match "Installed Environment Groups:\s+(?<PackageName>[\w\s]+)`n" $Matches.PackageName
Это всего лишь простой Linux - мы применяем cmdlet управления пакетами для имеющегося RPM интерфейса YUM. Вместо того чтобы
применять для обработки возвращаемых строк данных такие команды как grep
,
sed
и awk
, мы используем таике полезные
cmdlet PowerShell, как Select-String
, а также операторы подобные match.
Одной из типичных задач, которую должны осуществлять системные администраторы, даже применяя службы каталогов наподобие AD DS (Active Directory Domain Services), это создание локальных пользователей и групп, а также управления ими. В некой системе Windows с PowerShell Core это всё ещё запросто можно делать. В данном рецепте вы создадите и измените локальные учётные записи в некой системе Windows.
Установите и запустите PowerShell Core.
Будьте, пожалуйста, любезны выполнить такие шаги:
-
Мы имеем дело с неким модулем PowerShell Windows, который, к счастью, может целиком использоваться в PowerShell Core. В самых последних версиях Windows этот модуль в вопросах помечен как совместимый с PowerShell Core, избавляя нас от Шага 1. Начните с включения модулей Windows, как это показано в коде ниже:
Add-WindowsPSModulePath
-
Теперь мы можем обнаруживать все требуемые модули и применять их так:
Import-Module Microsoft.PowerShell.LocalAccounts -SkipEditionCheck
-
С помощью cmdlet
New-LocalUser
вы можете просто создать некую локальную учётную запись следующим образом:New-LocalUser -AccountExpires (Get-Date -Year 2020 -Month 1) -Description 'A test user' -Name JHP -Password (Read-Host -AsSecureString)
-
Добавление этого пользователя в некую локальную группу также не составляет проблем, что демонстрирует такой пример:
Add-LocalGroupMember -Group Administrators -Member JHP
-
Помимо локальных учётных записей вы также можете добавлять доменные учётные записи (включая Azure AD), а также учётные записи Microsoft для локальных групп, что отображает следующий пример:
Add-LocalGroupMember -Group users -Member "MicrosoftAccount\username@Outlook.com"
-
Для удаления некого пользователя нам снова достаточно вызвать cmdlet, как это показывает ещё один пример:
Get-LocalUser -Name *JHP* | Remove-LocalUser
Наш модуль LocalAccounts
представляет собой типичный бинарный модуль, состоящий
из некой библиотеки 'Microsoft.Powershell.LocalAccounts.dll'
и манифеста модуля.
После проверки на совместимость с .NET Standard, свойство CompatiblePSEditions
было исправлено, что демонстрирует следующий код:
CompatiblePSEditions = @('Desktop', 'Core')
В данном рецепте вы воспользовались обёрнутыми в cmdlet методами операционной системы для создания новых пользователей, изменения локальных групп и, наконец, удаления пользователей. Применяя имеющийся конвейер делает выполнение этих задач очень простым. Подробный синтаксис PowerShell превращает такой код в обладающий достаточной самостоятельной документацией. {Прим. пер.: подробнее, например, в нашем переводе PowerShell и Python сообща Чета Хосмера.}
В Linux у нас снова нет доступных естественных cmdlet PowerShell для создания локальных учётных записей и упралвения ими. Тем не менее, PowerShell всё ещё может применяться для безопасной передачи прав доступа в команды ОС, вырабатывая хэшированные пароли пользователя и тому подобное. В данном рецепте вы воспользуетесь PowerShell Core в помощь созданию учётных записей в Linux, а также для для начала разработки cmdlet когда нет никакого cmdlet.
Установите и запустите PowerShell Core.
Выполните, пожалуйста, следующие шаги:
-
Прежде всего давайте убедимся есть ли уже доступные команды:
# Поиск подходящих команд - все они внешние Get-Command -Name *user*
-
В системах Linux обычно для создания на лету локальных учётных записей применяются
useradd
иadduser
, как это показывает такой пример:# При помощи useradd мы можем передавать некий пароль - но его следует хэшировать man useradd
-
Эти команды, тем не менее, ожидают какого- то хэшированного неким образом пароля. А потому давайте начнём с получения безопасным образом полномочий, как это показано в нашем примере:
$credential = Get-Credential -UserName notImportant
-
Хотя наш текущий пользователь всё ещё может осуществлять доступ с паролем в открытом виде, как того требуют команды Linux, наши полномочия всё ещё защищены, что демонстрирует такой пример:
$credential.GetNetworkCredential().Password
-
Поскольку сам формат для пароля в Linux достаточно особый, мы применяем в помощь себе прочие средства автоматизации, такие как Perl или Python, что показывает следующий пример:
$hashedPassword = python -c ('import crypt; print(crypt.crypt(\"{0}\", crypt.mksalt(crypt.METHOD_SHA512)))' -f $credential.GetNetworkCredential().Password)
-
Теперь будет легко создать некую учётную запись пользователя с надлежащим паролем таким манером:
useradd -G wheel -p $hashedPassword john
-
Не имея в качестве альтернативы способа выработки хэшированных паролей для Linux, вы могли бы создать соответствующего пользователя и установить его пароль позднее как в этом примере:
# Это могло бы быть неуклюжей альтернативой useradd jim $credential.GetNetworkCredential().Password | passwd --stdin jim
Работа с PowerShell Core в данном контексте может не показаться естественной, но, опять же, PowerShell делает возможной работу с вводом данных и переменными слегка более простой. Его более многословный стиль может быть не совсем тем, к чему привыкли администраторы Linux, но он предоставляет ясные преимущества когда речь заходит о читаемости кода.
В этом рецепте вы создали некого пользователя и добавили его в группу. То как обрабатывались учётные данные всё ещё
далеко от идеала, демонстрируя тот факт, что для PowerShell в Linux ещё много чего предстоит сделать. У нас и сама
команда Python для выработки некого хэша пароля, и соответствующая команда passwd
применяли пароль в открытом тексте для вашего пользователя. Это ни в коем случае не является хорошим подходом.
Реестр Windows хранит множество настроек конфигураций для своей операционной системы. Посредством множества хранилищ, имеющих название ульев (hive), относящиеся к пользователю и машине настройки могут сохраняться и быстро выбираться. Как правило, реестра не касаются очень часто вручную, вместо этого изменяя его через групповые политики.
Может случиться так, что вам потребуется изменять параметры рееста в реально времени для изменения настроек как для операционной системы, так и для приложений.
Установите и запустите PowerShell Core.
Осуществите, пожалуйста, такие действия:
-
Необходимый реестр делается доступным через поставщика
Registry
таким образом:Get-PSProvider -PSProvider Registry Get-PSDrive -PSProvider Registry
-
Итак, для просмотра полученного реестра вы можете применять cmdlet
Item
,Location
иContent
, что показано в примере ниже:Get-ChildItem -Path HKCU:\Software Get-Location -path HKCU:\Software Get-ItemProperty -Path HKCU:\Software\Classes -name EditFlags
-
Изменение некого значения очень просто выполнять локально, как мы это можем наблюдать в таком примере:
# Изменение имеющегося локального реестра достаточно простое # например, отключаем UI Server manager при входе в систему Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ServerManager" -name "DoNotOpenServerManagerAtLogon" -Value 1
-
Вспомните полученный вывод Шага 1 - поставщик
Registry
не способен монтировать ульи удалённого реестра. Итак, как же нам получать доступ к реестру удалённых машин с локального хоста? Давайте рассмотрим следующий код:# Применение встроенных cmdlets не допускает работу с удалённым реестром (Get-PSProvider -PSProvider Registry).Capabilities # Тем не менее, при помощи .NET, нет ничего невозможного $remoteHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', 'DSCCASQL01')
-
Получив открытым необходимый улей, мы можем открыть подчинённый ключ с доступом на запись таким образом:
# Применим булево значение для открытия некого ключа с доступом на запись: $key = $remotehive.OpenSubKey('SoFTWarE\microsoft\servermanager', $true)
-
Теперь мы способны считывать данные так:
# Сейчас мы также можем пользоваться и необходимым удалённым ключом $key.GetValue('DoNotopenServerManagerAtLogon')
-
Мы также способны изменять данные следующим образом:
# А имея доступ на запись, мы также можем и выполнять запись в него $key.SetValue('DoNotopenServerManagerAtLogon', 0)
Хотя мы и можем просто работать локально с имеющимися поставщиками, как мы это наблюдали в своих предыдущих главах, не все поставщики способны работать удалённо. Одним из них является реестр. Поэтому для взаимодействия с удалёнными реестрами мы можем применять либо удалённый PowerShell, либо .NET.
Данный рецепт позволяет вам создавать и изменять ключи и значения локального реестра при помощи имеющегося поставщика реестра, что очень комфортно делать. С другой стороны, вы видели как это было сложно для удалённого доступа к необходимому реестру; это существенно намного сложнее.
При использовании для доступа к реестру .NET, мы применяем Distributed COM (Распределённую Component Object Model) и
RPC
(Remote Procedure Calls, Удалённые вызовы процедур) -
иными словами, естественную удалённую работу ОС. При удалённой работе с PowerShell мы, конечно же, применяем WSMan и его
порт TCP 5985
. Тем не менее, в случае удалённых манипуляций с реестром это
невозможно пока вы не обернёте свой локальный код в вызов Invoke-Command
.
Тем, чем для Windows выступает реестр, тем же в точности ещё и выступают файлы конфигурации Linux. Многие компоненты этой операционной системы могут управляться через файлы настроек.
Хотя для PowerShell Core и нет никаких cmdlet управления Linux, мы всё ещё способны пожинать преимущества имеющейся гибкости системы, а также мощных элементов языка и cmdlet.
Установите и запустите PowerShell Core.
Выполните, пожалуйста, такие шаги:
-
Следующий пример отображает наиболее распространённую точку входа,
/etc
:# Всё начинается здесь Get-ChildItem -Path /etc -File
-
Для изменения таких настроек системы как максимальное число оболочек на группу пользователей мы можем пожелать изменить
/etc/security/limits.conf
, как это показано в нашем примере:# Для управления установленными пределами pam, загляните в limits.conf Get-Content -Path /etc/security/limits.conf # Попробуйте отфильтровать наиболее важные части Get-Content -Path /etc/security/limits.conf | Where-Object {-not $_.StartsWith('#')}
-
Все записи в относящемуся к PAM
limits.conf
и все файлы конфигурации вlimits.d
, все они следуют одному и тому же синтаксису, для которого PowerShell очень хорошо проводит синтаксический разбор, что показано в нашем следующем примере:# Для этих элементов проявляется некий шаблон... Значения, разделяемые пробелами man limits.conf # И естественно, просмотр страниц man page выявляет <domain> <type> <item> <value> $limits = Get-Content -Path /etc/security/limits.conf | Where-Object {-not $_.StartsWith('#')} | ForEach-Object { $null = $_ -match "(?<Domain>[\w@]+)\s+(?<Type>hard|soft|-)\s+(?<Item>\w+)\s+(?<Value>\d+)" # Удаляем всё соответствие целиком - на самом деле оно нам не требуется $Matches.Remove(0) # Соответствия являются неким словарём. Который, кстати, может использовать PSCustomObject [pscustomobject]$Matches } # Обычные переменные, которые можно изменить и сохранить снова $limits[0].Type = 'Soft' $limits[0].Item = 'nproc' $limits[0].Value = 10
-
При наличии
Add-Content
запись обратных значения очень проста, что показано ниже:# Добавляем некий новый предел подобный приводимому, т.е. ограничить конкретного пользователя MyUser 20 процессами Add-Content -Value 'MyUser hard nproc 20' -Path /etc/security/limits.conf
-
PowerShell обладает рядом существенных возможностей RegEx, поэтому мы можем просто заменять содержимое в файлах, что демонстрирует такой пример:
# PowerShell также исключительно подходит для быстрого изменения значения в конфигурации # администраторы Linux по- прежнему могут применять неудобочитаемые регулярные выражения - благодаря подробному # языку PowerShell, новички получают возможность хотя бы лучше понимать преследуемую цель $newPort = 4729 (Get-Content -Path /etc/ssh/sshd_config) -replace "^Port\s+\d+" | Set-Content -Path /etc/ssh/sshd_config -Whatif
И снова мы пользуемся PowerShell лишь для лучшего механизма обработки текста. Отличным моментом в PowerShell Core является его подробный язык. Хотя несомненно, вы имеется возможность запутать сценарии PowerShell с тем, чтобы они походили на некие знаменитые уродливостью сценарии Perl - всякий достаточно решительно настроенный разработчик способен превратить даже самый красивый язык в безобразный - PowerShell поддерживает удобный для чтения стиль.
Данный рецепт начинается с типичной обработки текста в PowerShell Core в Linux. Поскольку множество элементов настройки хранится в конфигурационных файлах, требуется обработка текста.
Для работы с текстом в PowerShell часто применяются регулярные выражения. Они чрезвычайно универсальны, но в них трудно разобраться. Применённый нами на Шаге 3 шаблон содержал множество элементов:
-
Классы символов:
-
\w
означает любые словарные (word) символы, a-z, A-Z, 0-9 и _ -
\d
означает любую десятичную цифру -
\s
означает любой символьный пробел, например, отдельную табуляцию
-
-
Квантификаторы {определители количественного значения}:
-
+
означает в результате 1 - n -
*
означает в результате 0 - n -
{n, m}
означает в результате n - m, где m может быть опущен, указывая на снятие ограничения сверху
-
-
Группы:
-
(?<Name>)
обозначает так называемую захватывающую группу со значением названия, определяемого в угловых скобках
-
-
Логические операторы:
-
|
означает логическое или
-
-
Экранирующий (escape) символ:
-
\
применяется для экранирования любого специального символа
-
Наш шаблон замены порта в самом последнем шаге, ^Port\s+\d+
, заменяет
некую строку, которая начинается с P
, за которой следуют
ort
, по крайней мере один пробельный символ и по крайней мере одна цифра.
Поэтому можно заменять такие образцы: Port 80
,
Port 7
.
Будь вы разработчиком или оператором, регистрация некой новой службы это один из тех моментов, который вы выполняете достаточно часто. И снова, PowerShell делает очень простым создание некой новой службы с параметрами или без них, при этом, если это требуется, применяя различные полномочия.
Установите и запустите PowerShell Core.
Будьте добры выполнить такую последовательность:
-
Для некой новой службы нам вначале требуется некий исполняемый файл, который взаимодействует с имеющимся контроллером служб (service controller) - того приложения, с которым вы взаимодействуете при исполнении освящённого веками
sc.exe
, как в следующем примере:# Посторим шаблон макета службы dotnet build .\project1
-
Данный образец макета службы принимает запросы от диспетчера управления службами, например
Start-Service
иStop-Service
, что показано в примере ниже:# Данная простейшая служба лишь реагирует на запросы и не делает более ничего .\project1\bin\debug\project1.exe
-
С помощью cmdlet
New-Service
вы имеете возможность зарегистрировать свою службу следующим образом:# Применяя наш макет службы мы даже реагируем на прочие cmdlets служб # Требуется разрешение пути, ибо New-Service не осуществляет разрешение относительного пути New-Service -Name Dummy1 -BinaryPathName (Resolve-Path -Path .\project1\bin\debug\project1.exe).Path Start-Service Dummy1 Stop-Service Dummy1
-
Конечно же,
New-Service
, также как иSet-Service
допускает различные полномочия, что можно наблюдать в нашем следующем примере:$credential = [pscredential]::new('LocalUserJohn', ('Somepass1!' | ConvertTo-SecureString -AsPlainText -Force)) New-LocalUser -Name $credential.UserName -Password $credential.Password Set-Service -Name Dummy1 -Credential $credential -StartupType AutomaticDelayedStart
-
Некий cmdlet, которого очень не хватает в PowerShell Windows, даже после всех лет его эксплуатации, это
Remove-Service
. К счастью, в PowerShell Core он имеется, что показывается в нашем примере ниже:# Один из cmdlet который упущен всё ещё в Windows PowerShell даже в наши дни Remove-Service -Name dummy1 -Verbose
Наши cmdlet Service применяют .NET и тот класс ServiceController
, который
предоставляет доступ к службам Windows. Будете ли вы взаимодействовать с ними или нет, зависит тех прав, которые имеются
у вас для установленного диспетчера управления службами или индивидуальных служб. Как правило, это задаётся групповыми
политиками.
В то время как cmdlet Get-
и Set-Service
поддерживают параметр ComputerName
и тем самым способны к удалённой работе, они
будут использовать DCOM и RPC вместо WinRM
(Windows Remote Management).
Данный рецепт позволяет вам создать некую новую службу с каким- то исполняемым файлом, которая способна осуществлять
реакцию самого диспетчера управления службами Windows. Вы также можете видеть как изменять имеющиеся службы с помощью
cmdlet Set-Service
. При помощи таких cmdlet, как
Get-Credential
или Read-Host -AsSecureString
вы способны безопасно запрашивать полномочий некого пользователя, которые применяются в
Set-Service
.
Для удаления имеющихся служб при помощи PowerShell Core используется cmdlet Remove-Service
.
Он относительно новый, так как PowerShell Windows никогда не поддерживал удаление какой бы то ни было службы.
Вы также можете примерять удалённую работу через CIM и класс Win32_Service
для
надлежащего изменения удалённой службы, что показано в приводимом примере:
$cimsession = New-CimSession somehost
$service = Get-CimInstance -Query 'SELECT * FROM Win32_Service WHERE Name = "wuauserv"' -CimSession $cimsession
$service | Invoke-CimMethod -MethodName StopService
Те cmdlet служб которые имеются в Windows, совсем не представлены в Linux. Основная проблема для этого состоит в
фрагментации доступных систем init. Данная глава сосредоточена на systemd
,
который включён, к примеру, по умолчанию для CentOS.
{Прим. пер.: для справки, краткий перечень версий различных дистрибутивов Linux, начиная
с которых они поддерживают systemd по умолчанию:
Arch Linux 12.11,
CentOS 7.14.04+,
CoreOS v94.0.0+,
Debian GNU/Linux: 8+,
Fedora 15+,
Mageia 2+,
Mandriva 2011+,
openSUSE 12.2+,
RHEL 7+,
Ubuntu 15.04+
.}
Загрузите дистрибутив Linux с применением systemd
, установите и запустите
PowerShell Core.
Выполните, пожалуйста, такие шаги:
-
Запустите поиск доступных cmdlet - на момент написания их не было. Этот отображает следующий пример:
# Пока нет cmdlets служб Get-Command -Noun Service
-
В CentOS, Fedora и Red Hat, помимо прочего, в качестве системы init применяется
systemd
, что демонстрирует такой пример:New-VM -Name VM01 -Generation 2
-
Хотя он может применяться и для логических элементов, отличных от служб, мы сосредоточимся на части, относящейся к службам, что показано в примере ниже:
# Systemd является некой системой init, которая, естественно применяется не только для служб (daemons - демонов) systemctl status sshd service sshd status # deprecated with systemd
-
Прежде всего мы можем применять PowerShell для создания приятных функций, относящихся к
systemd
, которые будут назватьсяGet-Service
. Для этого обратите внимание на получаемый шаблон в выводеsystemctl
для такого примера:# Мы всё ещё можем применять PowerShell systemctl list-units --type service --no-pager
-
Мы можем применять его для улучшения получаемого вывода создавая новые объекты, которые могут форматироваться. Начнём прежде всего с некой пустой функции и параметров по умолчанию, что показано в приводимом коде:
function Get-Service { [CmdletBinding()] param ( [string[]] $Name, [string] $ComputerName ) }
-
Естественно,
Get-Service
способен запускаться удалённо. Или ещё лучше:systemctl
имеет возможность через SSH удалённо опрашивать хосты. Вот команда, которая применяет такие изменения:$results = if ($ComputerName) { systemctl list-units --type service --no-pager -H $ComputerName } else { systemctl list-units --all --type service --no-pager }
-
Теперь мы можем применить некое простое регулярное выражение для создания нового объекта, что показано в нашем следующем примере:
$services = foreach ($result in $results) { #UNIT LOAD ACTIVE SUB DESCRIPTION if ($result -match '(?<Name>\w+)\.service\s+(?<LoadedState>\w+)\s+(?<UnitStatus>\w+)\s+(?<Status>\w+)\s+(?<Description>\w[\w\s]*)') { $tmp = $Matches.Clone() $tmp.Remove(0) [pscustomobject]$tmp } }
-
После всего этого нам требуется выполнить фильтрацию, если наш пользователь решит применять параметр
Name
, таким образом:if ($Name) { Write-Verbose -Message "Applying like-filter for $Name" return $services | Where-Object -Property Name -like $Name } $services
-
Теперь мы можем применять все виды полезных cmdlet, что показывает наш следующий пример:
# Например, с целью форматирования Get-Service | Format-Table -Property Status, Name, Description Get-Service | Where-Object -Property Status -eq 'Running' # Или сортировки Get-Service | Sort-Object -Property Name # Или группирования Get-Service | Group-Object -Property Status
-
Новая служба также может быть очень быстро создана, что демонстрирует такой пример:
# Создание какого- то нового демона требует тех же самым базовых компонентов, что и для службы Windows: # Нечто для исполнения. # Давайте возьмём сценарий Polaris из "Learn PowerShell Core"! Get-Content ./LinuxDaemon/polaris.ps1 # В PowerShell мы также можем создать соответствующее определение службы # Для этого исключительно подходит строка "с этого места" (here-string). @" [Unit] Description=File storage web service [Service] ExecStart=$((Get-Process -Id $pid).Path) $((Resolve-Path -Path ./startpolaris.ps1).Path) [Install] WantedBy=multi-user.target "@ | Set-Content /etc/systemd/system/polaris.service -Force systemctl daemon-reload systemctl start polaris
-
Вместо создания файлов мы также можем следующим образом создать некий новый cmdlet с названием
New-Service
:function New-Service { param ( [Parameter(Mandatory)] [string] $BinaryPathName, [Parameter(Mandatory)] [string] $Name, [string] $Description, [string] $User = 'root', # один из systemctl list-units --type target --no-pager [string] $Target = 'multi-user' ) }
-
New-Service
просто добавляет соответствующие значения параметра в сам файл определения службы, что показывает наш пример:@" [Unit] Description=$Description [Service] ExecStart=$BinaryPathName User=$User [Install] WantedBy=$Target.target "@ | Set-Content "/etc/systemd/system/$Name.service" -Force # Выполняем daemon-reload для указания на файл новой службы systemctl daemon-reload Get-Service -Name $Name
-
После регистрации вашей новой службы вы можете создать ешё один новый cmdlet или применить:
systemctl start polaris
К сожалению, класс System.Service.ServiceController
, который применяет наш
cmdlet Service
применяет только Windows. Тем не менее, PowerfShell Core всё
ещё способен сильно упрощать вашу жизнь и делать намного более сносной миграцию из Windows в Linux, делая возможным
создание своих собственных cmdlet.
И снова, так как Linux преимущество применяет строки, для синтаксического разбора вывода получаемых команд мы применяем
регулярные выражения, либо просто преобразовываем их в соответствующие объекты. Посмотрите как здесь применяется оператор match
- значение переменной $Matches
клонируется, удаляется группа 0, а получаемая в результате
хэш- таблица применяется в качестве параметра для вашего нового объекта.
Данный рецепт показал вам как использовать функции для создания повторно применяемого кода, который обёртывается вокруг
функциональности операционной системы. Часто требуется расширять имеющиеся функции, либо создавать в PowerShell новые,
раз уж нет ничего подходящего. Повторно применяемый код подобный Get-Service
и
New-Service
способен содействовать вашей производительности как в Windows, так и в
Linux.
Запланированные задачи выступают основным материалом в мире Windows. И вновь cmdlet упрощают всё что связано с планируемыми задачами. Начиная с PowerShell 3 Windows, для планирования заданий и соответствующих задач может применяться имеющийся планировщик задач.
Хотя некое запланированное задание по существу является неким фоновым заданием PowerShell, исполняемым имеющимся планировщиком задач, какой- то задачей по расписанию может быть что угодно. Планируемые задания сохраняют свои результаты и могут выбираться при помощи cmdlet заданий, в то время как некая запланированная задача не способна на это.
Установите и запустите PowerShell Core.
Выполните, пожалуйста, следующие шаги:
-
Отыщите cmdlet
ScheduledTask
следующим образом:Get-ScheduledTask
-
Прежде всего мы бы хотели перечислить все зарегистрированные в системе задачи:
Get-ScheduledTask -TaskName *Cache* Get-ScheduledTask -TaskPath \Microsoft\Windows\Wininet\
-
Удалённое исполнение может быть достигнуто с помощью удалённого CIM, что показывает такой пример:
Get-ScheduledTask -TaskName *Cache* -CimSession (New-CimSession -ComputerName host1)
-
Чтобы зарегистрировать какую- то новую задачу, следует воспользоваться некими компонентами. Прежде всего, самим действием для исполнения, как в следующем примере:
$action = New-ScheduledTaskAction -Execute pwsh -Argument '-Command " & {"It is now $(Get-Date) in task land"}'
-
Далее полезен также некий переключатель, например:
$trigger = New-ScheduledTaskTrigger -At (Get-Date).AddMinutes(5) -Once
-
Наконец, и это совершенно не обязательно, это настройки самой задачи, как показано здесь:
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -RunOnlyIfNetworkAvailable
-
При помощи cmdlet
New-ScheduledTask
создаётся некий объект задачи. Этот объект всё ещё не функционален, что показывает такой пример:task = New-ScheduledTask -Action $action -Description "Says hello" -Trigger $trigger -Settings $settings
-
Регистрация этого объекта задачи применяет необходимый трюк, показанный в коде ниже:
$registeredTask = $task | Register-ScheduledTask -TaskName MyTask -TaskPath \MyTasks\
-
Теперь мы можем взаимодействовать со своей задачей как нужно. Это показывает такой пример:
# Для взаимодействия с нашей можно применять соответствующий cmdlet $registeredTask | Start-ScheduledTask $registeredTask | Stop-ScheduledTask # Наконец, отменяем регистрацию задачи $registeredTask | Unregister-ScheduledTask
Для взаимодействия через CIM с имеющимся планировщиком задач Windows применяются cmdlet
ScheduledTask
. Применение CIM и удалённого CIM делает очень гибкой аутентификацию.
При помощи удалённого CIM, вы можете зарегистрировать одну и ту же задачу, запрашивать пачку машин и тому подобное
на множестве удалённых машин.
Применяя различные строительные блоки задач вы можете, например, создать всё что необходимо для экспорта необходимого
определения в CliXML. Для регистрации самой задачи в системе можно применять весь объект целиком при помощи
ScheduledTask
.
Linux имеет службу планирования, именуемый cron, который применяется для повторяющихся заданий. Для планирования
задач сама служба расписаний, crond, работает с файлами с названием CronTab
.
Как вы могли догадаться, это вновь очень сильно основывается на тексте. К счастью, команда PowerShell создала некий
демонстрационный модуль, который очень полезен в этом. Он называется CronTab
.
Установите и запустите PowerShell Core.
Будьте добры выполнить такую последовательность:
-
Запустите как показано здесь обнаружение всех имеющихся cmdlet:
# И снова - собственные cmdlet отсутствуют Get-Command *ScheduledTask*
-
Нам вновь требуется поработать над пропущенным кодом. Однако на этот случай команда PowerShell кое- что имеет в загашнике, что демонстрирует наш пример:
# Download the CronTab module from GitHub $null = New-Item -ItemType Directory -Path /usr/local/share/powershell/Modules/CronTab -ErrorAction SilentlyContinue Invoke-WebRequest -Uri https://raw.githubusercontent.com/PowerShell/PowerShell/master/demos/crontab/CronTab/CronTab.psm1 -OutFile /usr/local/share/powershell/Modules/CronTab/CronTab.psm1
-
Только что выгруженный модуль может быть импортирован автоматически, как только мы сохраним его в своём
PSModulePath
. Однако, отличной мыслью будет для начала проверить содержимое самого модуля, что показывает наш следующий пример:cat /usr/local/share/powershell/Modules/CronTab/CronTab.psm1
-
Теперь, когда у нас имеется модуль, выявление cmdlet работает так:
# Выявляем имеющееся содержимое Get-Command -Module CronTab
-
попробуйте вначале опросить имеющийся
CronTab
, как это сделано в нашем примере:# Давайте посмотрим есть ли какие- то задания Get-CronTab # Get-Crontab отображает имеющееся содержимое, Get-CronJob слегка дружелюбнее: Get-CronJob
-
Чтобы добавить некую новую запись (зарегистрировать новую задачу) мы можем воспользоваться
New-CronJob
, как это показывает наш следующий пример:# Создать новое задание очень просто New-CronJob -Minute 5 -Hour * -DayOfMonth * -Command "$((Get-Process -Id $pid).Path) -Command '& {Add-Content -Value awesome -Path ~/taskfile}'"
-
Поиск имеющихся заданий слегка более изощрённое, так как нет имён или путей, как это имеется при планировании в Windows. Это демонстрирует такой код:
# Поскольку у заданий cron нет имён как у запланированных задач, их поиск может быть достаточно хитроумным Get-CronJob | Where-Object -Property Command -like '*awesome*' Get-CronJob | Where-Object -Property Minute -eq 5
-
Убедитесь что вы установили местоположение верного задания, прежде чем удалять что бы то ни было, как это сделано в приводимом коде:
# This is especially important when trying to remove a job Get-CronJob | Where-Object -Property Command -like '*awesome*' | Remove-CronJob -WhatIf Get-CronJob | Where-Object -Property Command -like '*awesome*' | Remove-CronJob -Confirm:$false
И снова, тот cmdlet, который выставляет необходимый модуль очень простой. Применяя незамысловатый оператор расщепления,
имеющееся содержимое CronTab
разделяется по его полям и преобразуется в
индивидуальные объекты CronJob
, которые обслуживаются как соответствующие
повторяющиеся множества.
Вы запросто можете расширить данный модуль чтобы, например, допустить создание записей для прочих пользователей.
Пулы хранения Windows, по существу, являются программно определяемыми устройствами RAID, которые применяются в Storage Spaces {Пространствах хранения} и Storage Spaces Direct (S2D - Непосредственно подключаемых Пространствах хранения) чтобы предоставлять для различных целей виртуальные диски. Для создания некого пула хранения можно применять любые хранилища, подключённые к серверу с запущенным Windows Server 2012, или более поздней версией.
Как вы можете догадаться, некий отдельный диск может быть лишь частью одного пула хранения.
Для подготовки к данному рецепту настоятельно рекомендуется воспользоваться лабораторным оборудованием. Чтоы сздать некую лабораторную среду в машине Hyper-V вы можете воспользоваться таким фрагментом кода:
New-LabDefinition -Name PoolParty -DefaultVirtualizationEngine HyperV
$disks = foreach ($count in 1..10)
{
Add-LabDiskDefinition -Name d$count -DiskSizeInGb 5 -SkipInitialize -PassThru
}
Add-LabMachineDefinition -Name PoolNoodle -DiskName $disks.Name -Memory 8GB -OperatingSystem 'Windows Server 2016 Datacenter (Desktop Experience)'
Install-Lab
Данный фрагмент кода создаст некую базовую виртуальную машину с какими- то подключёнными пустыми дисками. AutomatedLab требует выгрузки по крайней мере пробной версии Windows Server или некой активной подписки Azure для создания такой ВМ.
Выполните, пожалуйста следующие этапы:
-
Начните с получения представления о своём пуле хранения, который всегда имеется - самого изначального пуа - как это показывает наш код:
Get-StoragePool
-
Как и обычный первичный бульон, наш первичный пул просто содержит необходимые элементы для всех новых пулов хранения. На диски, которые могут быть добавлены в некий пул, указывает некое свойство
CanPool
, как это показано в следующем примере:Get-StoragePool -IsPrimordial $true | Get-PhysicalDisk | Where-Object -Property CanPool
-
Попробуйте добавить самую первую половину из имеющихся дисков в один пул, как в нашем примере:
$disks = Get-StoragePool -IsPrimordial $true | Get-PhysicalDisk | Where-Object -Property CanPool | Select -First 5 # Теперь мы можем создать некий новый виртуальный диск и в конечном счёте какой- то новый том Get-StorageSubSystem New-StoragePool -PhysicalDisks $disks -FriendlyName 'Splish splash' -StorageSubSystemFriendlyName 'Windows Storage*'
-
Теперь мы можем создать некий новый виртуальный диск и в конечном счёте какой- то новый том, как в следующем примере:
Get-StoragePool -FriendlyName 'Splish Splash' | New-VirtualDisk -FriendlyName Accounting -UseMaximumSize $volume = Get-VirtualDisk –FriendlyName Accounting | Get-Disk | Initialize-Disk –Passthru | New-Partition –AssignDriveLetter –UseMaximumSize | Format-Volume $largefile = [System.IO.File]::Create("$($Volume.DriveLetter):\largefile") $largefile.SetLength($volume.SizeRemaining - 1kB) $largefile.Close()
-
Вы можете замечать, что доступное вам хранилище становится всё меньши и меньшим. Чтобы расширить некий пул, вы просто можете добавить набор способных подключаться к пулу дисков в него, что показывает наш следующий пример:
Get-StoragePool -FriendlyName 'Splish Splash' | Add-PhysicalDisk -PhysicalDisks (Get-StoragePool -IsPrimordial $true | Get-PhysicalDisk | Where-Object -Property CanPool)
-
Теперь, когда этот пул вырос, наши виртуальный диск и том также могут быть увеличены, что можно увидеть из нашего следующего примера:
Get-VirtualDisk -FriendlyName Accounting | Resize-VirtualDisk -Size 16GB $volume | Get-Partition | Resize-Partition -Size 15GB
Пространства хранения являются функциональностью Windows Server 2012 и последующих версий и позволяют вам создавать так называемые пулы хранения или иначе, программно определяемые устройства RAID. Пулы можно создавать при помощи простых cmdlet PowerShell, что также доступно и в PowerShell Core.
В пулах можно вырезать виртуальные диски, и применять их как хранилища в приложениях, для разделения и тому подобного. Как и прочие программно определяемые RAID, пулы хранения могут расширяться и сжиматься в реальном режиме времени.
Дополнительную информацию о пулах хранения можно прочесть в https://docs.microsoft.com/en-us/windows-server/storage/storage-spaces/deploy-standalone-storage-spaces.
Linux предоставляет множество разнообразных способов создания программно определяемых RAID, причём, естественно,
ни один из них не снабжается никакими посвящёнными этому cmdlet PowerShell. В этом рецепте мы рассмотрим
mdadm
для создания некого очень простого RAID.
Для подготовки к данному рецепту настоятельно рекомендуется некая лрборторная среда. Чтобы создать в машине Hyper-V лабораторную среду, вы можете воспользоваться таким фрагментом кода:
New-LabDefinition -Name PoolParty -DefaultVirtualizationEngine HyperV
Add-LabVirtualNetworkDefinition -Name 'Default Switch' -HyperVProperties @{ SwitchType = 'External'; AdapterName = 'Ethernet' }
$disks = foreach ($count in 1..10)
{
Add-LabDiskDefinition -Name linuxd$count -DiskSizeInGb 5 -SkipInitialize -PassThru
}
Add-LabMachineDefinition -Name PoolNoodle -DiskName $disks.Name -Memory 8GB -OperatingSystem 'CentOS 7.4' -Network 'Default switch'
Install-Lab
Этот фрагмент кода потребует от вас выгрузить CentOS. Если вы готовы применять иной листрибутив Linux, будьте добры установить его как обычно и подключите дополнительные хранилища к этой виртуальной машине.
Выполните, пожалуйста, следующие шаги:
-
Все начинается с изучения имеющихся в наличии томов. Так как такие cmdlet как
Get-PhysicalDisk
ограничены лишь Windows, нам придётся вновь применить CLI на основе текста, как в следующем примере:lsblk -io KNAME,TYPE,SIZE,MODEL
-
Как и cmdlet
Get-Disk
,lsblk
перечисляет все блочные устройства, которые могут применяться для нашего программно определяемого RAID. Создание некого устройства RAID является более сложным нежели создание какого- то пула хранения. Тем не менее, давайте слегка очистим наши данные при помощи PowerShell. Прежде всего, мы можем создать очень простое множество элементов как в приводимом ниже примере:class BlockDevice { [string] $Name [string] $Type [int64] $Size }
-
Теперь нам нужно создать для некого повторяемого кода функцию,отображаемую в примере:
function Get-Disk { lsblk -ibo KNAME,TYPE,SIZE,MODEL | Select-Object -Skip 1 | ForEach-Object { if ($_ -match '(?<Name>\w+)\s+(?<Type>\w+)\s+(?<Size>[\w\d.]+)\s') { $tmp = $Matches.Clone() $tmp.Remove(0) [BlockDevice]$tmp } } }
-
Теперь мы можем отфильтровать свои диски как в приводимом далее примере - мы также можем воспользоваться соответствующей командой
Get-ChildItem
, в предположении что нам известно как именуются наши дисковые устройства:Get-Disk | Where-object -Property Type -ne 'part'
-
Команда
mdadm
в Linux способна создавать некое RAID устройство - но мы желаем для своих достижений воспользоваться PowerShell. На ум приходит новая функция. Начните с перечисления и некого нового класса:enum RaidLevel { RAID0 = 0 RAID1 = 1 RAID4 = 4 RAID5 = 5 RAID6 = 6 RAID10 = 10 } class RaidDevice { [string] $DeviceName [string[]] $MemberDevice [RaidLevel] $Level }
-
Теперь мы можем воспользоваться своими новыми типами данных в новой функции с названием
Get-SoftwareRaid
, прежде чем начнём создавать некое новое, как это показывает наш пример:function Get-SoftwareRaid { [CmdletBinding()] param ( $DeviceName ) $devices = foreach ($line in (Get-Content -Path /proc/mdstat)) { if ($line -match '(?
[\w\d]+)\s+:\s+active\s+raid(? [\d])\s+') { $tmp = $Matches.Clone() $tmp.Remove(0) $device = [RaidDevice]$tmp $deviceString = $line -replace ".*raid\d{1,2}\s+" $device.MemberDevice += $deviceString -split "\s" -replace "\[\d+\]" $device } } if ($DeviceName) { $devices = $devices | Where-Object -Property DeviceName -eq $DeviceName } $devices } -
Теперь, когда мы можем получить имеющуюся конфигурацию RAID, почему бы нам не создать некий cmdlet, который применяет
mdadm
неким упорядоченным манером? Вот пример этого:function New-SoftwareRaid { ... process { if (($MemberDevice | Test-Path) -contains $false) { Write-Error -Message "One or more member devices not found." return } $devices += $MemberDevice.FullName $deviceCount += $MemberDevice.Count } end { ... Start-Process -FilePath (Get-Command mdadm).Path -ArgumentList $arguments -Wait -NoNewWindow } }
-
Великолепно. Опробуйте свой новый cmdlet в соответствующем конвейере, как показано в следующем коде:
Get-ChildItem -Path /dev/sd[cd] | New-SoftwareRaid -DeviceName md0 -Level Raid0 -Verbose
-
Теперь для очистки создайте свою новую функцию
Remove-SoftwareRaid
, сочетая необходимые команды ОС с PowerShell, что плказывает такой пример:function Remove-SoftwareRaid { ... begin { $memberDisks = @() } process { ... $raid = Get-SoftwareRaid -DeviceName $DeviceName.BaseName umount $DeviceName.FullName mdadm --stop $DeviceName.FullName mdadm --zero-superblock /dev/$memberDisk } }
-
Попробуйте следующим образом свой новый cmdlet:
Get-Item -Path /dev/md0 | Remove-SoftwareRaid -WhatIf Get-Item -Path /dev/md0 | Remove-SoftwareRaid -Confirm:$false
То, как работает mdadm
, хорошо задокументировано в man
mdadm
. То что мы сделали в данном рецепте, так это было медленное добавление
новых cmdlet для управления теми командами, которые в ином случае основывались на тексте. Имея надлежащие типы данных
и перечисления мы способны управлять всеми данными наших cmdlet, с которыми мы работаем. Более того, мы запросто можем
разрешать завершающую табуляцию и IntelliSense.
Применяя атрибут CmdletBinding
, мы можем добавлять важную функциональность,
например, такую как снижение последствий рисков. Надлежащим образом связанный cmdlet
SupportsShouldProcess
указывает что мы бы хотели получать некие дополнительные
параметры, такие как WhatIf
и Confirm
.
Значение свойства ConfirmImpact
сообщает вызывающему что наш cmdlet оказывает
высокое воздействие на саму операционную систему - мы удаляем некое устройство RAID.
Приспосабливая наилучшие практические приёмы PowerShell для сценариев и повторно применяемых функций, вы можете потихоньку начинать свой арсенал cmdlet Linux. Что ещё лучше: вы можете упаковывать свои cmdlet в некий модуль и публиковать его в PowerShell Gallery для популярности и славы! {Прим. пер.: нет принципиальных трудностей в построении ZFS, подробнее в Мастерство FreeBSD: ZFS и Мастерство FreeBSD: ZFS для профессионалов Майкла В. Лукаса и Аллана Джуда.}
Всякий раз когда дела идут не так, либо ваша операционная система ведёт себя не так как планировалось или представлялось, администраторы Windows привыкли обращаться к журналу событий. К сожалению, многие администраторы всё ещё применяют для этого графический интерфейс.
Основной компромисс UI управления состоит, конечно же, в том, что он не масштабируется. Как вы намерены собирать все искомые вами события в сотнях серверов? Как вы можете действенно выполнять синтаксический разбор для тех частей информации, которая скрывается в неком событии? Конечно же при помощи PowerShell.
Данный рецепт введёт вас в курс дела cmdlet Get-WinEvent
и его возможностей
фильтрации для очень типичных задач: синтаксического разбора журналов безопасности для регистраций одного конкретного
пользователя.
Установите и запустите PowerShell Core в некой операционной системе Windows.
Выполните, пожалуйста, следующую последовательность:
-
Как и для большинства рецептов, для начала ознакомимся с вашим окружением, например, так:
# Давайте сначала озакомимся с cmdlet first - приготовьтесь к удару! Get-WinEvent -ListLog * -ErrorAction SilentlyContinue | Format-Wide -Property LogName -Column 4
-
Каналы ETW (Event Tracing for Windows) это гигантские объёмы информации. Давайте взглянем на такую команду:
Get-WinEvent -ListProvider *Security* | Format-Wide -Property Name -Column 4
-
Однако нас интересует журнал
Security
; в особенности отказы в регистрации, что показывает такой пример:Get-WinEvent -LogName Security -MaxEvents 1
-
Мы можем выработать нужные нам события отказов в регистрации подобно такому примеру:
# Чтобы это сработало, не забудьте воспользоваться неверным паролем ;) runas /user:$($env:COMPUTERNAME)\$($env:USERNAME) pwsh
-
Для получения такого события имеются два способа. А именно: эффективный и недейственный Начнём с показанного ниже недейственного, чтобы более просто разобраться с улучшениями:
# Мы можем получать данное событие не самым лучшим способом. Выполняя подобные приглашения Get-WinEvent для объединения # по ВСЕМУ журналу безопасности - а вы знаете насколько он велик. Get-WinEvent -LogName Security | Where-Object -Property ID -eq 4625
-
Лучший вариант состоит в применении одного из имеющихся параметров фильтрации - помните: фильтруйте как можно раньше - как это показано в следующем примере:
# Вот екий лучший способ Get-Command Get-WinEvent -Syntax # Давайте начнём с FilterHashtable по причине его простоты - огненно быстро $failedLogin = Get-WinEvent -FilterHashtable @{LogName = 'Security'; ID = 4625} -MaxEvents 1
-
Выбрав такие события мы можем изучить их слегка подробнее, например:
# Теперь мы можем изучить их - куча сведений $failedLogin | Get-Member -MemberType Properties # В особенности важный фрагмент сведений - имеющиеся свойства. Но увы, они не имеют названий # но мы рассмотрим их $failedLogin.Properties
-
Поскольку мы не желаем работать с неструктурированной информацией, такой как массив строк, мы можем взглянуть на имеющуюся структуру XML самого события. Некий образец демонстрирует следующий код:
# Как мы знаем, в естественном виде всякое событие представлено некой структурой XML $failedLogin.ToXml() # Мы можем воспользоваться XML $xmlEvent = [xml]$failedLogin.ToXml() # Ну, тогда пошли :) $xmlEvent.Event.EventData.Data # Что более важно, мы теперь способны отфильтровать в точности то что нам необходимо ($xmlEvent.Event.EventData.Data | Where Name -eq TargetUserName).InnerText
-
Великолепным свойством
Get-WinEvent
является то, что мы можем фильтровать свои события даже больше - например, по интересующему нас значениюTargetUserName
- как это показывает наш следующий пример:# Введём фильтр XPATH. $filter = '*[System[EventID=4625]] and *[EventData[Data[@Name = "TargetUserName"] = "japete"]]' Get-WinEvent -FilterXPath $filter -LogName Security
-
А если
XPATH
это нечто что вы не можете легко запомнить, попробуйте сноваFilterHashtable
. Существует единственный ключ с названием'*'
, возможно мы можем им воспользоваться, как показано в примере ниже:Get-Help Get-WinEvent -Parameter FilterHashtable Get-WinEvent -FilterHashtable @{LogName = 'Security'; ID = 4625; TargetUserName = 'japete'}
-
Имейте ввиду, что удалённая работа с соответствующим параметром
ComputerName
крайне неэффективна. Может применяться за раз лишь одна машина. Вместо этого применяйте удалённый PowerShell, как показано в нашем примере:# Естественно, всё что мы здесь делаем, мы можем выполнять удалённо в десятках машин. $filterTable = @{LogName = 'Security'; ID = 4625; TargetUserName = 'japete'} Invoke-Command -ComputerName (Get-Content .\thousandsOfMachines.txt) -ScriptBlock { Get-WinEvent -FilterHashtable $using:filterTable }
Журналы событий Windows и каналы событий могут фильтроваться гораздо эффективнее, чем это позволяет делать UI. В
особенности при фильтрации множества скрытых частей тех событий, которые вы обычно не можете запросто увидеть в своём UI,
к примеру, записи раздела EventData
.
Для выработки с лёгкой подсказкой запросов XPATH
, вы можете попытаться
спроектировать некий индивидуальный обзор в просмотрщике событий. Такое представление всегда обладает некой закладкой
XML, которой можно пользоваться для целей фильтрации, что
демонстрирует такой снимок экрана:
-
Для дополнительных сведений относительно ETW посетите, пожалуйста, следующую ссылку
-
{Прим. пер.: более подробно об обработке журналов событий в нашем переводе PowerShell и Python сообща Чета Хосмера.}
Linux, конечно же, также работает с событиями. Однако, в отличии от журнала событий Windows, системы Linux, как правило, для регистрации событий применяют syslog. Syslog задокументирован в RFC 5424 и хорошо структурирован, что упрощает автоматизацию протоколирования. Отличным моментом в PowerShell является то, что мы можем получать структурированные данные в объекты, с которыми очень просто работать. И, конечно же, мы делаем эту работу лишь раз, а затем выгружаем всю функциональность в некий модуль.
Установите и запустите PowerShell Core в некой системе Linux.
Выполните, пожалуйста, следующие шаги:
-
Прежде всего нам требуется ознакомиться с азами. Давйте рассмотрим такую команду:
# В отличии от Windows Linux не работает с журнаами событий Get-ChildItem /var/log # Что ещё хуже, его файлы журнала по умолчанию совершенно в ином формате Get-ChildItem -Path /var/log -File | foreach {$_ | Get-Content | Select -First 1 -Skip 5 }
-
Давайте взглянем на один очень общий журнал,
/var/log/messages
, как это показано в следующей команде:Get-Content /var/log/messages
-
В зависимости от вашего дистрибутива заботу о регистрации проявляет некий демон, такой как
rsyslogd
, причём он может быть настроен на регистрацию разнообразных средств syslog в различные файлы журнала, как для такого образца:cat /etc/rsyslog.conf
-
Подобные logger инструменты могут записывать разнообразные регистрации, как это показано в нашем следующем примере:
# Теперь для регистрации нет необходимости в каком- то cmdlet. Вмето этого нам следует воспользоваться logger. # Настроенная конфигурация, например, rsyslogd будет определять как сообщения SYSLOG записываются # когда их регистрирует logger logger -p local0.emergency "Oh god, it buuuurns"
-
Для упрощения чтения некого файла регистраций мы можем, опять, создавать свои собственные функции, начав с некого класса для хранения регистрационных записей, что показано в следующем коде:
class LogEntry { [string] $Message [datetime] $TimeWritten [string] $ComputerName [string] $Source [uint32] $ProcessId }
-
Для выполнения синтаксического разбора своего текста мы снова можем воспользоваться регулярными выражениями. Для получения дополнительных сведений отсылаем к рецепту Изменение файлов настроек Linux из этой главы. Давайте рассмотрим такой код:
# \d matches decimals, \w alphanumeric characters # Для определения числа символов определяются квантификаторы + и {n,m} $logpattern = "(?
\w{3}\s+\d{1,2}\s+\d{2}:\d{2}:\d{2})\s+" # Квантификатор ? означает появление 0 или 1 раз. Это отлично должно соответствовать нашему ProcessID $logpattern += "(?\w+)\s+(? # Итак, а что делать с никуда не годным форматом даты? К примеру: Mar 6 20:30:01 # при помощи DateTime мы запросто можем преобразовать его статичным методом ParseExact [datetime]::ParseExact('Mar 6 20:30:01', 'MMM d HH:mm:ss', [cultureinfo]::InvariantCulture) -
Обёртывая это код в небольшую функцию и добавляя некую логику мы превращаем его в повторно применяемый и гибкий, что показывает такой пример:
New-VM -Name VM01 -Generation 2function Import-SystemLog { ... Get-Content -Path $PAth | ForEach-Object { if ($_ -match $logpattern) { $logEntry = [LogEntry]::new() $logEntry.TimeWritten = [datetime]::ParseExact(($Matches.TimeWritten -replace '\s+',' '), 'MMM d HH:mm:ss', [cultureinfo]::InvariantCulture) $logEntry.Message = $Matches.Message $logEntry.Source= $Matches.Source $logEntry.ComputerName = $Matches.ComputerName $logEntry } } } Import-SystemLog -Path /var/log/messages Import-SystemLog -Path /var/log/cron
-
К счастью, для записи сообщений syslog уже имеется подобающий модуль
Posh-SYSLOG
. Хотя этот модуль и содержит лишь один cmdlet, он очень полезен для переправки сообщений изнутри сценариев PowerShell, что отображено в следующем примере:Install-Module Posh-SYSLOG # Хотя этот cmdlet и предназначен для слива в SYSLOG, его применение # с переключателем Verbose пказывает какое сообщение вы отсылаете Send-SyslogMessage -Server localhost -Message hello -Severity Emergency -Hostname localhost -Facility local0 -Verbose
Сообщения из ядра, очереди печати, электронной почты и прочих средств обрабатываются различными демонами регистрации.
К примеру, аварийные сообщения, вне зависимости от его источника, по умолчанию, будут отображаться на экране при первом
же обновлении консоли. Средства электронной почты, по умолчанию, будут выполнять сохранение в
/var/log/maillog
.
При помощи PowerrShell, регистрируемые события вне зависимости от их формата могут синтаксически разбираться при помощи регулярных выражений. Применяя классы PowerrShell, регистрируемые сообщения могут в явном виде преобразовываться в более полезный формат, который опять же можно обрабатывать в ваше свободное время.