Запуск windows powershell с помощью wmi kaspersky

Kaspersky Security для Windows Server поддерживает интеграцию с инструментарием управления Windows (Windows Management Instrumentation, WMI): вы можете

Содержание

  1. Запуск windows powershell с помощью wmi kaspersky
  2. Запуск windows powershell с помощью wmi kaspersky
  3. 1000++ способ запуска команд на удаленном компьютере
  4. Способы старые, временем проверенные
  5. Psexec
  6. Групповые политики и скрипты
  7. Назначенные задания
  8. Через реестр
  9. Способы новые или куда же без PowerShell
  10. Вирус (Возможно) использует PowerShell
  11. Рекомендуемые сообщения
  12. Присоединяйтесь к обсуждению
  13. Похожий контент
  14. Запуск программы из PowerShell
  15. Прямой запуск
  16. Оператор &
  17. Invoke-Expression
  18. Start-Process
  19. Invoke-Command
  20. Invoke-Item

Запуск windows powershell с помощью wmi kaspersky

Kaspersky Security для Windows Server поддерживает интеграцию с инструментарием управления Windows (Windows Management Instrumentation, WMI): вы можете использовать клиентские системы, которые получают с помощью WMI данные по стандарту Web-Based Enterprise Management (WBEM), для получения данных о статусе программы Kaspersky Security для Windows Server и ее компонентов.

В момент установки Kaspersky Security для Windows Server регистрирует в системе собственный модуль для создания пространства имен Kaspersky Security для Windows Server на защищаемом устройстве. Пространство имен Kaspersky Security для Windows Server позволяет работать с классами, экземплярами классов и их свойствами в Kaspersky Security для Windows Server.

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

Непериодические задачи – это задачи программы, которые не имеют ограниченного срока действия и либо постоянно выполняются, либо остановлены. Для таких задач невозможно указать прогресс выполнения. Результаты выполнения таких задач фиксируются непрерывно в ходе выполнения и представляют собой отдельные события (например, обнаружение зараженного объекта одной из задач постоянной защиты сервера). Задачами такого типа можно управлять с помощью политик Kaspersky Security Center.

Периодические задачи – это задачи программы, срок выполнения которых ограничен, а прогресс выполнения может быть отображен в виде количества процентов. Результаты выполнения таких задач фиксируются по завершении задачи и представляют собой отдельный элемент или факт изменения состояния программы (например, завершение Обновления баз программы, сформированные конфигурационные файлы для задач автоматического формирования правил). На одном защищаемом устройстве одновременно может быть запущено несколько периодических задач одного типа (например, три задачи проверки по требованию с разными областями проверки). Вы можете управлять периодическими задачами с помощью групповых задач Kaspersky Security Center.

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

Данные о состоянии программы

Свойство экземпляра класса

Название установленной программы.

Полное название программы без номера версии.

Источник

Запуск windows powershell с помощью wmi kaspersky

Kaspersky Embedded Systems Security поддерживает интеграцию с инструментарием управления Windows (Windows Management Instrumentation, WMI): вы можете использовать клиентские системы, которые получают с помощью WMI данные по стандарту Web-Based Enterprise Management (WBEM), для получения данных о статусе программы Kaspersky Embedded Systems Security и ее компонентов.

В момент установки Kaspersky Embedded Systems Security регистрирует в системе собственный модуль для создания пространства имен Kaspersky Embedded Systems Security на защищаемом устройстве. Пространство имен Kaspersky Embedded Systems Security позволяет работать с классами, экземплярами классов и их свойствами в Kaspersky Embedded Systems Security.

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

Непериодические задачи – это задачи программы, которые не имеют ограниченного срока действия и либо постоянно выполняются, либо остановлены. Для таких задач невозможно указать прогресс выполнения. Результаты выполнения таких задач фиксируются непрерывно в ходе выполнения и представляют собой отдельные события (например, обнаружение зараженного объекта одной из задач постоянной защиты компьютера). Задачами такого типа можно управлять с помощью политик Kaspersky Security Center.

Периодические задачи – это задачи программы, срок выполнения которых ограничен, а прогресс выполнения может быть отображен в виде количества процентов. Результаты выполнения таких задач фиксируются по завершении задачи и представляют собой отдельный элемент или факт изменения состояния программы (например, завершение Обновления баз программы, сформированные конфигурационные файлы для задач автоматического формирования правил). На одном защищаемом устройстве одновременно может быть запущено несколько периодических задач одного типа (например, три задачи проверки по требованию с разными областями проверки). Вы можете управлять периодическими задачами с помощью групповых задач Kaspersky Security Center.

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

Данные о состоянии программы

Свойство экземпляра класса

Название установленной программы.

Полное название программы без номера версии.

Источник

1000++ способ запуска команд на удаленном компьютере


В наше время даже для собак придумали удаленное управление.

Возвращаясь к циклу «Конспект Админа», мне хотелось бы рассказать о вариантах запуска исполняемых программ на удаленных компьютерах. Эта статья будет интересна тем, у кого еще нет систем централизованного управления, но уже есть понимание утомительности ручного обхода рабочих станций и серверов. Либо тем, кому решения «под ключ» не интересны ввиду неспортивности.

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

Когда-то давно я устроился работать в организацию в период эпидемии KidoConficker. Наиболее простым способом выяснить, все ли хорошо в ИС компании, была славная утилита от Касперского под названием Kido Killer, которая проверяла наличие вируса и устраняла его. Запускать программу на доброй сотне машин руками было невесело, поэтому пришлось знакомиться с автоматизацией.

Если в операционных системах *nix для удаленного запуска, как правило, используется SSH, то у Windows способов запуска программ и скриптов воистину как песка в пустыне. Я разберу основные варианты, как общеизвестные, так и экзотические. Таких очевидных вещей как telnet-сервер касаться не буду, тем более Microsoft уже убрала его из современных ОС.

Способы старые, временем проверенные

Psexec

Пожалуй, это первое, что приходит на ум, когда идет речь об удаленном запуске программ. Утилита от Марка Руссиновича используется еще со времен Windows NT и до сих пор применяется. Помимо основной функции, можно использовать ее и как Runas, и для запуска программ в пользовательской сессии терминального сервера. Psexec также позволяет задавать ядра процессора, на которых будет запускаться программа, и ее приоритет в системе.

В качестве примера посмотрим, установлено ли обновление, закрывающее нашумевшую уязвимость SMB на списке компьютеров:

В файле computers.txt находится список компьютеров. Для запуска по всему домену можно использовать \*. В файле \serversharelog.txt будут появляться имена рабочих станций или серверов без обновления. Если в домене существуют компьютеры с *nix на борту или нет доступа к административному сетевому ресурсу Admin$ ― команда на этой машине не выполнится, но обработка продолжится. Чтобы скрипт не зависал при каждой попытке подключения, можно задать тайм-аут с помощью ключа -n.

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

К минусам Psexec можно отнести то, что она из-за своего удобства и популярности часто используется вирусописателями. Поэтому антивирусные системы могут обнаруживать утилиту как опасность вида remote admin.

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

Для управления системами Windows с помощью разных графических утилит часто используется WMI (Windows Management Instrumentation) ― реализация объектно-ориентированного стандарта управления WBEM. В качестве утилиты с графическим интерфейсом для работы с WMI можно использовать wbemtest.exe.

Для работы с WMI из консоли создана wmic.exe. Например, для проверки установленных обновлений вместо жутковатой конструкции из предыдущего примера можно использовать простую команду:

Использовать список компьютеров также можно командой /node:»@computers.txt».

Еще при помощи WMI можно запускать программы – синтаксис предельно прост:

К сожалению, в отличие от Psexec, получить вывод в консоли не получится ― придется выводить результаты команды в файл.

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

Групповые политики и скрипты

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


Скрипты, выполняющиеся при старте и завершении системы.

qnt3h7eayd52yhnhdspqrmyuzm8
Скрипты, выполняющиеся при входе и выходе пользователя из системы.

Скрипты, настраиваемые в пользовательском разделе, выполняются от имени пользователя, а в разделе компьютера ― под аккаунтом SYSTEM.

Назначенные задания

Довольно интересный способ, заслуживающий право на жизнь. Назначенные задания можно создавать из командной строки при помощи утилиты schtasks.exe, выполнять их, затем удалять. Подробнее с синтаксисом можно ознакомиться в документации, я же разберу пример использования назначенных заданий в доменной среде. Предположим, нам нужно выполнить команду как можно быстрее вне зависимости от того, выключен компьютер или нет. Для этого используются так называемые предпочтения групповых политик (Group Policy Preference).

Искать установку назначенных заданий следует в конфигурации компьютера или пользователя ― «Настройка ― Параметры панели управления ― Назначенные задания».


Создание нового назначенного задания.

Для выполнения команды или скрипта ASAP понадобится создать «Немедленную задачу (Windows 7 и выше)». Если вдруг в инфраструктуре остались машины под управлением Windows XP, то подойдет «Очередное задание (Windows XP)».

Стоит сделать несколько политик с соответствующими WMI-фильтрами или создать два разных назначенных задания в одной политике с нацеливанием ― например, при помощи того же WMI-фильтра. Это поможет избежать конфликтов в разнородной среде со старыми и новыми Windows.

Пример WMI-фильтра для применения политики только на компьютерах с Windows XP:

В остальном процедура создания назначенного задания тривиальна. Единственное, не забывайте отметить пункт «Применить один раз и не применять повторно», если задача не требует повторного запуска.

uscmvzbrejl157j p9zupsphwp8
Запускаем немедленную задачу только один раз.

При использовании таких назначенных заданий программа запустится, как только компьютер получит обновление групповой политики. Это удобно: не нужно проверять доступность компьютеров в случае Psexec и wmic и заставлять пользователей перезагружать машины, как в случае скриптов групповых политик. При необходимости можно скопировать файл скрипта локально в разделе «Настройка ― Конфигурация Windows ― Файлы».

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

Через реестр

Модификация реестра на пользовательских машинах ― странный вариант, лишь на случай крайней необходимости. Можно использовать ветки Run или RunOnce. Подробнее о них ― в документации. Сама модификация реестра может проводиться через групповые политики или из командной строки ― например, такой командой:

В зависимости от ветки реестра, процесс будет выполняться или под пользователем, выполнившим вход в систему, или под аккаунтом SYSTEM.

Есть и другие способы, такие как правка ярлыков в папке «Автозагрузка» или добавление в ярлык к популярной программе && script.cmd, но эти методы уже из серии «можно, но не нужно».

Теперь перейдем к новым инструментам.

Способы новые или куда же без PowerShell

PowerShell, оправдывая свое название, может подключаться к удаленным компьютерам при помощи WMI, RPC и WS-Management (WSMan). Использование последнего метода требует предварительной настройки.

Командлеты, не требующие предварительной настройки, как правило, имеют параметр ComputerName, но не имеют параметра Session. Посмотреть список таких командлетов можно командой:

Для настройки WSMan в общем случае достаточно выполнить команду Enable-PSRemoting-Force. Она запустит службу удаленного управления WinRM и пропишет исключения в фаерволе ― в принципе, это можно сделать для всего домена при помощи групповых политик. Подробнее настройка описана в документации.

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


Проверка возможности подключения.

Для того чтобы выполнить определенную команду или скрипт, используется командлет Invoke-Command со следующим синтаксисом:

Где COMPUTER ― имя компьютера, COMMAND ―– имя команды, а USERNAME ― имя пользователя, если оно нужно.

q71e0p5kcsi5orbzpfjomiw2nq4
Смотрим содержимое диска С удаленного компьютера.

Если же нам нужно получить полноценную консоль ― не автоматизации ради, а ради управления конкретным компьютером, ― то можно использовать командлет Enter-PSSession.


Работаем в консоли удаленного компьютера.

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

Конечно, кроме встроенных средств и небольших утилит, существует множество программ для управления структурой. Помимо взрослых решений, для управления конфигурациями вроде Chef, Ansible и MS SCCM можно использовать и средства мониторинга вроде Zabbix, и даже консоль управления антивирусом Касперского.

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

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

Источник

Вирус (Возможно) использует PowerShell

Рекомендуемые сообщения

Присоединяйтесь к обсуждению

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

Похожий контент

imported photo 62471.thumb.jpeg.72cfbcbb3c666d15e1dde08b32b1961b

В защитнике Вигдовс в списке «разрешенные» трояны Trojan:script/Wacatac.B1ml, Trojan:win32/Wacatac.B1ml, Trojan:script/Casur.A!cl, никакие антивирусы их не видят.

При борьбе с вирусом в соседнем разделе (https://forum.kasperskyclub.ru/topic/83139-winmonsys-windefenderexe-csrss) пришли к выводу, что необходимо установить хотфиксы для успешного излечения. Однако, служба Центра обновлений Windows отсутствует в списке служб, а при попытке включить центр обновлений windows через панель управления, выскакивает ошибка: Центр обновлений Windows в настоящее время не может выполнить поиск обновлений, поскольку эта служба не запущена. При попытке установить скачанные хотфиксы выскаивает ошибка 0х80070424.

После Repair с помощью Tweaking и перезагрузки в безопасный режим служба всё-таки появилась в списке, но отсутствует возможность ее запустить или же остановить, статус отключена. При попытке попробовать поставить тип запуска исполняемого на «Автоматический» выскакивает ошибка:

Не удалось сбросить флажок отложенного автоматического запуска. Ошибка 1072: Данная служба была отмечена для удаления.

Источник

Запуск программы из PowerShell

Задача запустить из PowerShell какой либо исполняемый файл (программу или утилиту командной строки) встречается достаточно часто. PowerShell предлагает для этого несколько различных способов, которые мы и рассмотрим далее в этой статье. Начнем с самого простого…

Прямой запуск

Самый простой способ запустить исполняемый файл в PowerShell — это перейти в директорию с файлом и стартовать его напрямую. Для примера возьмем простенькую программку, выводящую приветствие, и выполним ее командой:

Set-Location ″C:Program Files″
.Hello.exe

Обратите внимание, что даже находясь в нужном каталоге, требуется указывать относительный путь к исполняемому файлу. Исключение составляют файлы из директорий, перечисленных в переменной окружения (path). Например различные встроенные программы и утилиты (notepad, calc, ping и т.п.), находящиеся в директории WindowsSystem32, можно запускать без указания пути.

Оператор &

Если необходимо указать полный путь к исполняемому файлу, то можно воспользоваться оператором & (оператор вызова). Он позволяет выполнить строку текста, указанную в кавычках, как единую команду. Например:

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

& ′C:Program FilesHello.exe′ ′Hello, world′

При желании можно указать нескольких аргументов через запятую:

& ′C:Program FilesHello.exe′ ′Hello,′, ′ world′

Для удобства команду и аргументы можно поместить в переменные:

Ну и если аргументов много, то их можно объединить, воспользовавшись такой конструкцией:

Invoke-Expression

Командлет Invoke-Expression работает примерно так-же, как и оператор & — берет текстовую строку и выполняет ее в виде команды. Например:

Однако у него есть один большой недостаток, а именно — неумение работать с пробелами. К примеру, следующая команда вызовет ошибку:

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

Start-Process

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

Также Start-Process позволяет передать в процесс дополнительные аргументы:

из которой можно затем можно узнать многие полезные вещи, такие как статус:

или код выполнения:

Такой способ достаточно неудобен и громоздок (на мой взгляд), но чуть более гибок в использовании. Для примера запустим нашу программу в текущем окне, передадим в нее аргументы и заберем результат выполнения:

С помощью WMI можно сделать практически все, в том числе и запустить программу. Для этого вполне подойдет метод Create WMI-класса Win32_Process. Этот метод запускает процесс на локальном или удаленном компьютере через RPC. Например, для выполнения программы на локальном компьютере можно воспользоваться такой командой:

А для выполнения на удаленном компьютере команда будет выглядеть так:

Как вариант, можно воспользоваться командлетом Invoke-WmiMethod:

Либо командлетом Invoke-CimMethod:

WMI запускает процесс в отдельном окне и возвращает объект, содержащий идентификатор процесса (ProcessID) и результат выполнения (ReturnValue). ReturnValue может принимать следующие значения:

— Sucsessful Completiom
2 — Access Denied
3 — Insufficient Privilege
8 — Uncnown Failure
9 — Path Not Found
21 — Invalid Parameter

Invoke-Command

Командлет Invoke-Command умеет выполнять команды на локальном или удаленном компьютере, используя WinRM. Например, для запуска нашей программы на локальном компьютере используем команду:

При необходимости в программу можно передать аргументы:

Обратите внимание, что Invoke-Command не очень дружит с пробелами, поэтому во избежании ошибок приходится исхитряться с кавычками. Впрочем, подобных проблем можно избежать, например комбинируя использования командлета с оператором &:

В основном Invoke-Command применяется для удаленного управления, его главное достоинство — это возможность одновременного выполнения на нескольких компьютерах. Например:

Invoke-Item

Командлет Invoke-Item предназначен для применения к файлу действия по умолчанию. Так запустить исполняемый файл можно командой:

Однако наиболее удобно использовать Invoke-Item для открытия определенного типа файлов. Например так мы откроем текстовый файл:

А так все текстовые файлы в папке:

Ну и в завершение еще один способ запуска программы из PowerShell — с помощью оболочки cmd. Способ достаточно ″непрямой″, но тем не менее работающий. Следующая команда запускает новый экземпляр cmd, выполняет в нем указанную программу, завершает работу cmd и возвращает результат:

cmd /c ″C:Program FilesHello.exe″

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

Кстати, статья написана по мотивам PowerShell: Deep Dive and Best Practice. Рекомендую почитать, там еще много интересного.

Источник

Содержание

Курс в «Специалисте»

get-service | get-member
# или
get-service | gm

7. Форматирование результатов

get-command -verb format -module *util*
 
dir c:windows | ft BaseName,Extension,Length -Autosize -GroupBy Extension
 
# Выравнивание по правому краю:
Get-Service | ft @{n="Name-right"; e={$_.Name}; align="right"},Status,CanStop,CanShutdown -AutoSize
 
# Список:
Get-Service | fl Name,Status
 
# Широкий - несколько колонок:
Get-Service | sort status | format-wide Name -Column 4 -GroupBy status

8. Начало и конец конвейера

Конец — обычно выгрузка куда-то, начало — запрос или импорт.

Get-Command -Verb Export,ConvertTo -Module *utility
ConvertTo-Csv    
ConvertTo-Html   
ConvertTo-Json   
ConvertTo-Xml    
Export-Alias     
Export-Clixml    
Export-Csv       
Export-FormatData
Export-PSSession
 
# Результаты в окошке с фильтрами
get-service | Out-Gridview
 
Get-Service | ConvertTo-Html -Title "Список служб" -PreContent "<h1>Службы на локальном компьютере</h1>" | Out-file .services.html

9. Привязка параметров в конвейере

Одно и то же:
dir c:windows | format-wide
Format-Wide -InputObject (dir c:windows)

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

10. Переменные

Жизненный цикл переменной: объявление, инициализация (запись), использование.

get-command -noun variable
 
# Есть диск с именем Variable:
Get-PSDrive
# список переменных
dir variable:

Свойства вызываются через точку, методы — добавляются скобки

$test1.length
$test1.gettype()
$test1.Substring(2, 2)
# Менять тип переменной можно на ходу, но можно задать тип жёстко:
[int]$test5 = 100
# можно записать туда дробное число,
$test5 = 100.25
# но значение всё равно будет целочисленным, с округлением.
# Строку и т. п. записать туда не получится.

Вывести количество символов имени самого большого файла в c:Windows

$test1 = dir c:windows |sort Length -Descending | select -ExpandProperty Name -First 1
$test1.length
 
# Массив переменных
$test1 = 10, 20, 30, 40, 50
 
# Нумерация - с нуля:
$test1[2] #выведет 30
$test1.count #кол-во элементов
$test1[$test1.count - 1] # последний элемент массива
$test1.gettype() # тип данных - массив (array)

Если в массиве изменить какие-то данные на другой тип, то тип данных всего массива превратится в строку (в 5-й версии powershell — нет).

$test1[2] = "word"
 
$s = get-service
$s[5].status.tostring().length

11. Программные конструкции

Цикл.

С предусловием — выполнять цикл, пока условие верно:

$i=8
while ($i -gt 0)
{
$i; # Полезная нагрузка
$i = $i - 1;
}

С проверкой в конце цикла, а не в начале. Цикл в любом случае выполняется один раз:

$i=8
Do
{
$i;
$i = $i - 1;
}
while ($i -gt 0) # условие продолжения цикла
# если условие верно, цикл продолжается

Выполнять цикл, пока не наступит условие:

$i=8
Do
{
$i;
$i = $i + 10;
}
until ($i -gt 1000) # условие окончания цикла
# если условие верно, цикл останавливается

Цикл FOR — все условия задаются вне самого цикла, внутри — только полезная нагрузка.

for (
$i=8; # выполняется один раз при входе в цикл
$i -GT 0; # условие продолжения цикла
$i = $i - 1 # выполняется после каждого повторения
)
{
$i;
}

Перебор (foreach) — для перебора существующего массива.

Чтобы не городить конструкцию типа

$srv=get-service
for (
$i=0; # выполняется один раз при входе в цикл
$i -LT $srv.count; # условие продолжения цикла
$i = $i + 1 # выполняется после каждого повторения
)
{
$srv[$i].Name;
}

пишем

$srv = get-service
foreach ($s in $srv)
{
$s.Name
}

Условие (IF).

Простой случай:

$t = 8
if ($t -gt 3)
{
Write-Host "Больше трёх"
}

Выполнить что-то другое, если условие не выполнено (if-else):

cls
$t = 2
if ($t -gt 3)
{
Write-Host "Больше трёх"
}
else
{
Write-Host "Не больше трёх"
}

Несколько условий (if-elseif-else)

$t = 1
if ($t -gt 3)
{
Write-Host "Больше трёх"
}
elseif ($t -eq 3)
{
Write-Host "Равно трём"
}
elseif ($t -eq 2)
{
Write-Host "Равно двум"
}
else
{
Write-Host "Меньше двух"
}

Найти каталог на C:, в котором больше всего вложенных каталогов.

$folder = c:
$dirs = dir $folder -Directory
foreach ($d in $dirs)
{
$subd = $d.GetDirectories().Count
if ($subd -gt $max) {$max = $subd; $dirname = $d.Name}
}
 
Write-Host $dirname
Write-Host $max

13. Запуск сценария с параметрами

Вместо задания переменной в коде вынести её в начало скрипта таким образом:

Param(
[string]$folder
)
# После этого можно передавать путь как параметр к скрипту.
.script.ps1 C:
# Также, табом можно перебирать эти параметры, если их несколько:
.script.ps1 -folder C: -extension exe

Обязательные параметры:

# Перед блоком Param() написать
[CmdletBinding()]
# Также, перед параметром поставить
[Parameter(Mandatory=$True)]

Для необязательных параметров можно задать значение по умолчанию:

[string]$extension = "*"

Для заданной папки создать в каждой подпапке вложенную папку с названием «Специалист»:

param(
$parent = ""
)
 
# Создать
gci $parent -Directory | foreach {New-item -path ($_).FullName -Name Специалист -ItemType Directory}
# А можно вызывать метод напрямую:
gci $parent -Directory | foreach CreateSubDirectory Специалист

15. Обработка ошибок

try { code }
catch { errors handling }

Try и Catch должны идти последовательно друг за другом. Если в try всё в порядке, catch пропускается, если ошибка — try прерывается и переходит в catch.

# Удалить
gci $parent -Directory -Recurse | where Name -like Специалист |Remove-Item
 
write-output
write-warning
write-error
write-verbose
write-debug
 
[CmdletBinding()] # даёт возможность показывать отладочную информацию write-verbose и write-debug.
# По умолчанию, эта информация не выводится.
 
Param(
[int]$a,
[int]$b,
[switch]$c # такого типа нет, но если не указывать его как параметр скрипта,
# то будет false, если указывать - true.
)
 
Write-Verbose ("A = " + $a)
Write-Verbose ("B = " + $b)
Write-Verbose ("C = " + $c)
 
# $error - переменная, отвечающая за вывод ошибок, вставляется в catch {}
# $error |gm
# $error.categoryinfo
# $error.errordetails
 
$a = 0
try {
$a + 1
$a * 2
10 / $a
$a - 1
Write-Output "Ошибок нет"
}
catch {
Write-Output "Ошибка!"
$error
}

16. Удалённое исполнение команд

На удалённой машине должен работать сервис WinRM.

Для настройки удалённого доступа выполнить команду winrm quickconfig на целевой машине.

Удалённый запуск команды:

Будут работать команды, где есть параметр -ComputerName, например,

Get-Service -ComputerName DC1,DC2,Serv3
 
# Запуск оболочки на удалённом компьютере:
Enter-PSSession DC1
Exit-PSSession
 
# Для одновременного запуска на большом кол-ве машин:
Invoke-Command -ComputerName DC1,DC2,Serv3 -ScriptBlock {Get-Service; Get-Process}

17. Фоновое выполнение команд

Start-Job {dir c: -recurse |measure-object}
# Каждой задаче присваивается ID, узнать их состояние можно командой
Get-Job
# Получить результат задачи, который можно, например, отправить дальше по конвейеру.
Receive-Job -Id 2
# Можно добавить его в переменную и использовать в дальнейшем
$s = Receive-Job -Id 2 | select -first 5
 
get-command -noun Job

18. Планировщик задач

get-command -noun scheduledjob

19. Функции, модули

Function set-myinfo
{
[cmdletbinding()]
Param(
[parameter(mandatory=$true)]
[string]$filename,
[parameter(mandatory=$true)]
[string]$text
)
set-content -path $filename -value $text
}
 
Function get-myinfo {
[cmdletbinding()]
Param(
[parameter(mandatory=$true)]
[string]$filename
)
get-content -path $filename
}
 
##################################
# Вызов функции
set-myinfo -filename "c:tempmyfile.txt" -text "test text"
get-myinfo -filename "c:tempmyfile.txt"

Из скрипта с функциями можно сделать модуль — расширение .psm1. Там нужно оставить только функции.

Каталоги с модулями PS по умолчанию ($env:PSModulePath):

$env:userprofileDocumentsWindowsPowerShellModules # для каждого юзера

В ней создать папку с именем модуля, и скопировать туда модуль С ТЕМ ЖЕ ИМЕНЕМ, что и папка. Для каждого модуля — своя папка, т. е.,

$env:userprofileDocumentsWindowsPowerShellModulesmodulenamemodulename.psm1
 
import-module -listavailable
import-module modulename

Далее можно вызывать функции в модуле как стандартные командлеты, будет работать также

get-command -noun myinfo

Добавить справку в модуль: после Function get-myinfo { вставить спецкомментарий:

<#
.SYNOPSIS
	Краткое описание
.DESCRIPTION
	Подробное описание
.PARAMETER filename
	Описание параметра
.PARAMETER text
	Описание параметра
.EXAMPLE
	примеры
#>

Запуск функции удалённо

# will NOT work:
Invoke-Command -ScriptBlock { Get-Software -DisplayName *Office* } -ComputerName server01
# will work (provided server01 exists and is set up for remoting):
Invoke-Command -ScriptBlock ${function:Get-Software} -ArgumentList '*Office*' -ComputerName server01

https://powershell.one/code/12.html

21. AD

get-command -module activedirectory
dir ad: # список разделов
get-item "cn=user,dc=domain,dc=com" | get-member

080 Параметр Verbose

Чтобы не городить огород с логическими операторами и циклами типа

Function List-Service {
[cmdletbinding()]
Param(
[string]$ServiceName = "*",
[parameter(mandatory=$true)]
[int]$Top
[switch]$Protocol
)
if ($Protocol) { Write-Host "Вывод списка служб" }
get-service -name $servicename | select -first $top
if ($Protocol) { Write-Host "Вывод списка служб окончен" }
}
 
# Запуск:
List-Service -Top 2 -Protocol

имеется встроенный параметр -Verbose с подсветкой вывода, т.е. параметр $Protocol можно вообще убрать.

Function List-Service {
[cmdletbinding()]
Param(
[string]$ServiceName = "*",
[parameter(mandatory=$true)]
[int]$Top
)
Write-Verbose "Вывод списка служб"
get-service -name $servicename | select -first $top
Write-Verbose "Вывод списка служб окончен"
}
 
# Запуск:
List-Service -Top 2 -Verbose

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

090 Синонимы для параметров

Синоним (алиас) задаётся непосредственно перед каждым целевым параметром.

Function mynewfunc {
[cmdletbinding()]
Param(
[Alias('str', 'ms')]
[string]$MyString
)
 
Write-Host $MyString
 
}
 
mynewfunc -str "Test string"
mynewfunc -ms "Test string"

100 Проверка параметров

Function mynewfunc {
[cmdletbinding()]
Param(
[Alias('str', 'ms')]
[ValidateLength(3, 5)]
[string]$MyString
)
 
Write-Host $MyString
 
}
 
mynewfunc -ms "Test string" # вызовет ошибку
mynewfunc -ms "Test" # сработает
# Валидатор для числовых параметров:
[ValidateRange(3, 5)]
# Список вариантов:
[ValidateSet('Create', 'Delete', 'Modify')]

Сделать свой валидатор:

[ValidateScript({if ($_ -gt 10) {$True} else {$False}})]
[int]$MyInt
mynewfunc -MyInt 9 # ошибка
mynewfunc -MyInt 11 # сработает
 
[ValidatePattern('Myd')] # значение должно соответствовать шаблону My+число.
[ValidateLength(3, 5)] # доп. проверка на длину
[string]$MyString
 
mynewfunc -MyString "Myd" # ошибка
mynewfunc -MyString "My1234" # ошибка
mynewfunc -MyString "My123" # сработает

110. Приём списков в качестве параметров

Function mylistfunc {
[cmdletbinding()]
Param(
[string[]]$FolderList
)
  foreach ($Folder in $FolderList) {
    dir $Folder -Directory | measure
  }
}
 
mylistfunc -folderlist "C:WindowsSystem32", "C:Users", "C:Program Files"

Если указать, что принимается массив строк [string[]] без цикла foreach, будет подсчитано общее количество.

120. Приём параметров из конвейера

Function mylistfunc {
[cmdletbinding()]
Param(
[parameter(ValueFromPipeline=$True)]
[string[]]$FolderList
)
BEGIN {}
PROCESS {
  foreach ($Folder in $FolderList) {
    dir $Folder -Directory | measure
  }
}
END {}
}
 
gc .folderslist.txt | mylistfunc

Если просто добавить [parameter(ValueFromPipeline=$True)] без конструкции BEGIN-PROCESS-END и цикла, то будет выведено только последнее значение из конвейера. Дело в том, что процесс передачи по конвейеру разбит на эти три этапа, где перечисление собственно данных из конвейера выполняется в блоке PROCESS. Блоки BEGIN и END выполняются один раз, а PROCESS — столько раз, сколько строк в конвейере.

130. Создание объектов

PSObject — универсальный тип объекта

function MyFunc1 {
$Properties = @{'Name' = "MyName"; 'Size' = 10; 'Color' = "Yellow"}
New-Object -TypeName PSObject -Property $Properties
}
 
cls
MyFunc1

140. Работа с объектами .NET

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

$test = New-Object -TypeName System.Net.HttpWebRequest
$test |gm
 
$d = New-Object -TypeName datetime
$d
$d = [datetime]'12.03.2005'
$d
$d.AddDays(10)
$d.Year
$d.Month
$d.DayOfWeek
 
# 1 января 0001 г. 0:00:00
# 3 декабря 2005 г. 0:00:00
# 13 декабря 2005 г. 0:00:00
# 2005
# 12
# Saturday

150. Инструменты и управляющие сценарии

При усложнении сценария целесообразно разбивать его на части. Рекомендуется делить программу на две группы — инструменты и управляющие сценарии. Инструменты решают конкретную задачу, например, заведение пользователя в AD. Инструменты могут собирать данные (Get-, Import-, ConvertFrom-), выполнять действия (Send-, New-, Set-, Remove-, Save-), выводить результат (Export-, ConvertTo-, Format- Out-). Управляющие сценарии решают более сложные, бизнес-задачи, вызывая различные инструменты. Также в них делается интерфейс общения с пользователем, который должен выбирать из каких-то пунктов и т. п.

160. Директива Requires

Проверка необходимых компонентов и условий для работы скрипта. Оформляется как комментарий.

#Requires -Version 2.0
#Requires -Module ActiveDirectory
#Requires -RunAsAdministrator
 
Get-Service

170. Взаимодействие с пользователем

write-host # выводит информацию на экран
read-host # захватывает ввод пользователя
clear-host # очистка экрана (cls)
Write-Host "Выберите действие:"
Write-Host "1. Установить"
Write-Host "2. Удалить"
Write-Host "3. Запилить"
 
$r = Read-Host
if ($r -eq 1) {
Write-Host "Выберите вариант установки:"
Write-Host "1. Полный"
Write-Host "2. Минимальный"
Write-Host "3. Отмена"
 
$r2 = Read-Host "Введите цифру"
 
Write-Host "Вы выбрали $r -> $r2"
}

180. Организация работы с главным меню

Do {
Clear-Host
 
Write-Host "Выберите действие:"
Write-Host "1. Установить"
Write-Host "2. Удалить"
Write-Host "3. Запилить"
 
$r = Read-Host
if ($r -eq 1) {
Write-Host "Выберите вариант установки:"
Write-Host "1. Полный"
Write-Host "2. Минимальный"
Write-Host "3. Выбор компонентов"
Write-Host "4. Отмена"
 
$r2 = Read-Host "Введите цифру"
 
Write-Host "Вы выбрали $r -> $r2"
 
Read-Host "Нажмите любую клавишу"
    }
}
while ($r2 -ne 4)

190. Генерация отчётов в HTML

У ConvertTo-Html есть параметр -Fragment, который генерирует только содержимое без открывающих и закрывающих тэгов.
Таким образом, с помощью Out-File -Append можно сначала добавить тэги, затем нужную информацию (можно несколько запросов сгенерировать) добавить в файл, затем закрывающие тэги.
При добавлении запрошенной информации в переменные полезно использовать команду Out-String, чтобы данные были одной строкой, а не массивом.

200. Обработка нештатных ситуаций

2 типа ошибок — останавливающая, при которой обработка прерывается, и неостанавливающая, когда валятся ошибки, но обработка продолжается.
Имеется системная переменная $ErrorActionPreference со значением Continue по умолчанию, можно поменять её значение на

$ErrorActionPreference = "SilentlyContinue"
# ошибки выводиться не будут, но это плохая практика.
 
$ErrorActionPreference = "Inquire"
# спрашивать пользователя, что делать дальше.
 
$ErrorActionPreference = "Stop"
# остановка обработки, все неостанавливающие ошибки превращаются в останавливающие.
# Также, это позволяет перехватывать ошибки.

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

Для обработки ошибок используется конструкция

try { code }
catch { errors handling }
finally { code }

Try и Catch должны идти последовательно друг за другом. Если в try всё в порядке, catch пропускается, если ошибка — try прерывается и переходит в catch. Finally выполняется в любом случае после Catch.

try { dir C:WindowsSystem32*.exe -Recurse -ErrorAction Stop }
catch { Write-Warning "Ошибка!" }
finally { Write-Host "Конец" }

Без указания -ErrorAction Stop блок catch выполняться не будет.

Неплохо бы знать также, что за ошибка произошла и в каком месте.

try { dir C:WindowsSystem32*.exe -Recurse -ErrorAction Stop -ErrorVariable $err1}
catch {
Write-Warning "Ошибка!"
$_ | gm # переменная с ошибкой, можно использовать методы для получения информации
$Error[0] # массив, куда пишутся ошибки. 0 - последняя
}
finally { Write-Host "Конец" }

-ErrorVariable может создавать переменную ошибки для каждой команды, что удобно, т. к. в блоке catch{} можно управлять разными ошибками разных команд.

210. Работа с XML

XML удобен тем, что хранит и данные, и структуру, как БД.

<> # элемент, внутри может быть атрибут, типа
<lan>
<computer name="comp1">Компьютер</computer>
<addr ip="192.168.0.10" mask="255.255.255.0" />
</lan>

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

Getting Started with Microsoft PowerShell

Don’t fear the shell

The help system

update-help # обновить справку
get-help get-service # справка по get-service
get-help get-service -online # открыть онлайн-справку в браузере
get-help get-service -detailed # более подробная справка
get-help get-service -examples # примеры
get-help get-service -showwindow # открыть справку в отдельном окне
man get-service # то же самое
get-verb # глаголы, используемые в PS

Синтаксис:

Get-Service [[-Name] <String[]>] [-ComputerName <String[]>] [-DependentServices] [-Exclude <String[]>] [-Include <String[]>] [-RequiredServices] [<CommonParameters>]
 
# Всё, что начинается с дефиса (-Name) - параметр
# <> - значение (аргумент)
# [] вокруг параметров и аргументов - это опциональный параметр
# [] вокруг самого параметра - можно писать сразу аргументы к командлету, параметр будет подразумеваться, например,
Get-Service bits
# или
gsv bits
# [] внутри <> - значение может быть множественным (разделённым запятыми)
Get-Service -Name b*, c*
Get-Service -DisplayName *bit*
get-eventlog -logname system -newest 3 -entrytype error -computername dc1,server2,server5
get-help about* # список разъяснительных статей о разных вещах
get-help -Category CmdLet # вывести список статей по категории командлетов

; — разделитель типа && в линуксе (сделай это и потом сделай то)

The pipeline: getting connected & extending the shell

get-service | export-csv -Path c:service.csv
import-csv c:/service.csv
 
get-service | export-clixml -Path c:service.xml
 
Compare-Object -ReferenceObject (Import-Clixml c:service.xml) -DifferenceOject (Get-Process) -Property name
 
get-service | Out-file -filepath c:services.txt
get-content c:services.txt
 
get-service | Convertto-html -Property Name,Status | out-file c:service.htm
 
get-service -DisplayName *bi* | stop-service -whatif # А что будет если (без реального выполнения)
get-service -DisplayName *bi* | stop-service -confirm # подтверждение выполнения каждого совпадения
 
get-module -ListAvailable # доступные модули
get-module # уже загруженные модули

Objects for the Admin

get-process | where {$_.handles -gt 900} # gt - greater than | sort handles
get-process | where handles -gt 900 # то же самое, но упрощённая версия без скобок
get-service | get-member # получить список методов и свойств командлета
get-eventlog -logname system -newest 5 | select -property eventid, timewritten, message | sort -property timewritten | convertto-html | out-file C:eventlog.htm
 
# Пример парсинга xml (Ромео и Джульетта)
# https://www.ibiblio.org/xml/examples/shakespeare/r_and_j.xml
# прочитать содержимое и задать переменную
$x = [xml](get-content .r_and_j.xml)
# Вывести все реплики из 1 акта 1 сцены
$x.PLAY.Act[0].scene[0].SPEECH
# Подсчитать количество реплик, сгруппировав по герою, от больших значений к меньшим
$x.PLAY.Act.scene.SPEECH | group speaker | sort count -descending
 
get-history # история команд
 
get-service | where {$_.status -eq "Running"}
# То же самое, $PSItem - это $_
get-service | where {$PSItem.status -eq "Running"}
get-service | where {$PSItem.status -eq "Running" -and $_.Name -like "b*"}
 
# Разница в концепциях
# Плохо из-за того, что фильтрация после сортировки - бессмысленная работа
get-stuff | sort | where -somestuff | out-file
# Сортировка после фильтрации - гораздо лучше
get-stuff | where -somestuff | sort | out-file

The pipeline: deeper

Что передаётся через пайп (конвейер): ByValue, ByPropertyName.

# посмотреть, какие параметры принимают данные конвейера
get-help get-service -full
 
-InputObject <ServiceController[]>
    Specifies ServiceController objects representing the services to be retrieved. Enter a variable that contains the objects, or type a command or expression that gets the objects. You can also pipe a service object to this cmdlet.
 
    Требуется?                   false
    Позиция?                     named
    Значение по умолчанию                None
    Принимать входные данные конвейера? True (ByValue)
    Принимать подстановочные знаки? false
 
-Name <String[]>
    Specifies the service names of services to be retrieved. Wildcards are permitted. By default, this cmdlet gets all of the services on the computer.
 
    Требуется?                   false
    Позиция?                     0
    Значение по умолчанию                None
    Принимать входные данные конвейера? True (ByPropertyName, ByValue)
    Принимать подстановочные знаки?false
 
# благодаря совпадению имён параметров в разных командлетах возможны такие сочетания, как
get-service | stop-process -whatif # когда имена сервисов передаются как имена процессов
get-process calc | dir # показать местонахождение calc.exe
 
# если параметры не совпадают, например, в случае
get-adcomputer -filter * | get-service -name bits # это не сработает
# можно задать параметр, который будет совпадать, т. е., ComputerName задаётся равным Name
get-adcomputer -filter * | select -property @{name='ComputerName';expression={$_.name}} | get-service -name bits
 
# Иногда бывает так, что командлет вообще не принимает параметров по конвейеру
# Это не сработает, т. к. get-wmiobject на вход ничего не принимает:
get-adcomputer -filter * | get-wmiobject -class win32_bios
# Тем не менее, у get-wmiobject есть параметр -ComputerName, которому нужно скормить строки из Get-ADComputer. Чтобы получить строки, нужно использовать параметр -ExpandProperty, чтобы убрать заголовок в столбце Name.
get-wmiobject -class win32_bios -ComputerName (get-adcomputer -filter * | Select -expandproperty name)
# Начиная с 3-ей версии Powershell, можно написать ту же команду короче:
get-wmiobject -class win32_bios -ComputerName (get-adcomputer -filter * ).name
# А можно и так ({} обозначает скрипт для выполнения), некий обход ограничений:
get-adcomputer -filter * | get-wmiobject win32_bios -computername {$_.name}
# Также, существует более новый аналог get-wmiobject - get-ciminstance, который умеет принимать параметры по конвейеру

The PowerShell in the shell: remoting

Как подключиться

Enter-PSSession server1
[Server1]: PS c:UsersAdministrator.SERVER1Documents>

Включить возможность удалённого подключения

Enable-PSRemoting

Включить в политике:

Computer configuration/Policies/Administrative templates/Windows Components/Windows remote management

В Windows 2012 это включено по умолчанию.

invoke-command -computername dc,server1,server2 {get-eventlog -logname system -new 3} | sort timewritten | format-table -property timewritten, message -Autosize
invoke-command -computername dc,server1,server2 {restart-computer}
icm dc,server1,server2 {get-volume} | sort sizeremaining | select -last 3

Установить веб-доступ к powershell на удалённой машине

install-windowsfeature WindowsPowershellWebAccess
get-help *pswa*
install-pswawebapplication
add-pswaauthorizationrule -computergroupname # какая группа машин имеет доступ
add-pswaauthorizationrule -usergroupname # какая группа пользователей имеет доступ

http://video.ch9.ms/ch9/f33b/15dcc7ae-ff1c-4e1d-9200-be3f132bf33b/GetStartedPowerShell3M06_high.mp4?600

Getting prepared for automation

AllSigned — абсолютно все скрипты должны быть подписаны

RemoteSigned — должны быть подписаны все скрипты, кроме созданных локально (значение по умолчанию с Windows Server 2012 R2)

# сделать самоподписанный сертификат
New-SelfSignedCertificate
# вывести все диски (в т. ч. поставщиков Powershell)
get-psdrive
# показать все сертификаты подписи кода и создать переменную $a
dir Cert:Currentuser -Recurse -CodeSigningCert -outvariable a
# тут не понял
$cert = $a[0]
# посмотреть текущую политику выполнения
get-executionpolicy
# изменить её на AllSigned
set-executionpolicy "allsigned"

После этого обычный скрипт (test.ps1) не выполнится

# Подписать скрипт test.ps1
Set-AuthenticodeSignature -Certificate $cert -Filepath .Test.ps1

Посде подписи в конец скрипта добавляется цифровая подпись, и при запуске он выполняется, но спрашивает, выполнять ли скрипт от недоверенного издателя, в т.ч. есть вариант ответа «всегда доверять».

Переменные

get-help *variable*
 
$MyVar="Hello"
$MyVar= get-service bits
$MyVar.status
$MyVar.stop()
$MyVar.refresh() # если не обновить, то сервис будет показываться как запущенный
$MyVar.status
 
#Задать переменную интерактивно
$var=read-host "Введите имя компьютера"
get-service bits -computername $var
 
write-host $var -foregroundcolor red -backgroundcolor green
write-host $var | get-member # не сработает

Write-host ничего не передаёт и вообще его использование не рекомендуется, нужно использовать write-output:

write-output $var | get-member # а вот это сработает

Цвет текста в консоли

# предупреждение
write-warning "Стоять близко к краю платформы опасно"
write-error "Стоять близко к краю платформы опасно"

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

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

${привет, как дела?} = 555

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

1..5 > C:temptest.txt
${C:temptest.txt)
1
2
3
4
5

Но если задать переменной значение, то будет возвращаться именно оно, причём, оно также будет отображаться и в другом экземпляре консоли

${C:temptest.txt) = "Переменная №1"

Automation in scale: remoting

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

Это не сработает, так как между сессиями переменная не передаётся:

icm -comp dc {$var=2}
icm -comp dc {write-output $var}

Правильный вариант — обращаться в ту же сессию, что и ранее

$sessions=new-pssession -computername dc
icm -session $sessions {$var=2}
icm -session $sessions {$var}
 
# можно померить время, за которое выполняется команда
measure-command {icm -computername dc {get-process}}
# это должно быть быстрее
measure-command {icm -session $sessions {get-process}}
# Взять два сервера
$servers= 's1', 's2'
# убедиться, что на них нет веб-страниц
$servers | foreach {start iexplore http://$_}
# сделать переменную для сессий
$sessions=new-pssession -computername $servers
# поставить IIS
icm -session $sessions {install-windowsfeature web-server}
# теперь проверка будет положительной
$servers | foreach {start iexplore http://$_}
# можно создать "страничку" в notepad и разложить её по серверам как главную
notepad c:default.htm # написать там что-то
$servers | foreach {copy-item c:default.htm -destination \$_c$inetpubwwwroot}

Удалённые сессии полезны ещё и потому, что не нужно ставить доп. компонентов типа Exchange management shell локально, потому что можно подключиться непосредственно к серверу, где эти командлеты имеются изначально.

$s=new-pssession -computername dc
import-pssession -session $s -module activedirectory -prefix remote

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

get-remoteadcomputer -filter *

Но по факту всё это выполняется удалённо, под теми учётными данными, под которыми была создана удалённая сессия.

Просмотр параметров командлетов

$c = get-command get-process
$c.parameters
$c.parameters["Name"]

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

(get-command get-remoteadcomputer).definition

Присвоение префикса командлету

$s = nsn
import-session $s -commandname get-process -prefix wow
get-wowprocess

Introducing scripting and toolmaking

Если нажать в Powershell ISE сочетание Ctrl+Space, то это может показать классы WMI.

Get-CimInstance Wind32_Logical#Ctrl+Space

После пайпа можно нажать Enter, и в интерактивном режиме команду можно продолжать набирать.

Get-WmiObject win32_logicaldisk -filter "DeviceID='c:'" | 
>> Select @{n='freegb';e={$_.freespace / 1gb -as [int]}}

Задать параметр:

param(
  $Computername='localhost',
  $bogus
  )
Get-WmiObject -computername $Computername win32_logicaldisk -filter "DeviceID='c:'" | Select @{n='freegb';e={$_.freespace / 1gb -as [int]}}

Эти параметры можно выбирать после запуска сохранённого скрипта клавишей Tab и задавать их на лету.

После сохранения скрипта с параметрами и вызова этого скрипта через get-help, вывод выглядит как спавка к командлету, где командлетом является сам скрипт. В данном случае $Computername — это объект, но если написать в скрипте

  [string]$Computername

, то параметр будет иметь значение «строка». Для полноценного строкового параметра не хватает скобочек, их надо добавить:

  [string[]]$Computername='localhost'

Если в начале скрипта добавить

  [CmdletBinding()]

, то будут доступны все прочие параметры [<Commonparameters>]

Если в список параметров добавить

param(
  [Parameter(Mandatory=$True)]

, то следующий за ним параметр (один), будет обязательным.

Learn Windows Powershell in a month of lunches (3rd edition), краткий конспект

Справка

help Get-Service # Получить справку по Get-Service
Update-Help # Обновить справку
Save-Help # Сохранить справку локально
Update-Help -Source path # Загрузить справку из локального источника
help *log* # найти командлеты, в которых упоминается log
help Get-Service -ShowWindow # показать справку в отдельном окне
help Get-Service -Online # показать справку в интернете
Help Get-EventLog -example # показать примеры использования
Help about_* # список справочной информации по областям применения

Интерпретация синтаксиса справки

Get-EventLog [-LogName] <String> [[-InstanceId] <Int64[]>] [-After <DateTime>] [-AsBaseObject]
[-Before <DateTime>] [-ComputerName <String[]>] [-EntryType <String[]>] [-Index <Int32[]>]
[-Message <String>] [-Newest <Int32>] [-Source <String[]>] [-UserName <String[]>] [<CommonParameters>]
 
Get-EventLog [-AsString] [-ComputerName <String[]>] [-List] [<CommonParameters>]

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

[<CommonParameters>] — стандартные параметры для всех командлетов.

[ ] — необязательный (optional) параметр.

Positional parameter — обязательный параметр, который может использоваться без указания имени параметра, в данном случае [-LogName] <String>, где обязательно указание только <String>. Например, можно написать

Get-EventLog System -Newest 20

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

Значения параметров

Параметр «переключатель» (switches) — не нуждаются во вводных данных, например, в данном случае — [-AsString]. Такие параметры никогда не являются Positional parameter, поэтому всегда нужно печатать имя параметра, а также, они всегда необязательны.

Типы вводных данных:

Строка (String) — ряд букв и цифр. Если с пробелами (типа C:Program Files), то нужно заключать в одинарные кавычки (‘ ‘).

Целые числа (Int, Int32, Int64) — без десятичных значений.

Дата и время (DataTime) — строка, интерпретируемая как указатель времени в соответствии с региональными параметрами системы.

Квадратные скобки, которые указаны рядом ([-ComputerName <string[]>]) означают, что значений может быть несколько (array, collection, list), разделённых запятыми. Например:

Get-EventLog Security -computer Server-R2,DC4,Files02

Множественное значение может быть прочитано из файла, например

Get-EventLog Application -computer (Get-Content names.txt)

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

Запуск команд

Не интерпретировать параметры, передаваемые стороннему приложению: —%

C:windowssystem32sc.exe --% qc bits

Провайдеры (providers)

Провайдеры — это хранилища информации, выглядящие как диски — это заданные псевдонимы команд, реестр, файловая система и т. д.

Get-PSProvider # вывести список доступных провайдеров

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

Get-Command -noun *item*

Суть в том, что можно запрашивать любые объекты провайдера одними и теми же командлетами.

Set-Location -Path C:Windows # файловая система
Set-Location -Path hkcu: # реестр
Set-Location -Path Env: # системные переменные
# если не указать тип, то PS спросит об этом, т. к. непонятен тип объекта
New-Item TestFolder -Type Directory

По умолчанию, путь к объекту обязательный и может содержать маску (* и ?), но можно задать необязательный параметр -LiteralPath, который не будет интерпретировать следующее за ним значение.

Можно выгружать информацию в CSV и XML с помощью командлетов Export-CliXML и Export-Csv. в XML выгружается больше подробностей. Подобную выгрузку можно использовать для сравнения, например, если выгрузить с одного компьютера список процессов, перенести полученный файл на другой компьютер и там запустить сравнение списка в файле со списком работающих процессов там (в данном случае — по имени):

Diff -reference (Import-CliXML reference.xml) -difference (Get-Process) -property Name

Если выпустить -Property, то сравнение будет идти по всем полям. Diff в Powershell не очень хорошо работает для сравнения текстовых файлов.

# Тупо выгрузить в файл
Dir > DirectoryList.txt
# А вот здесь можно задать параметры выгрузки - кодировка, доп. инфо и т. д.
Dir | Out-File DirectoryList.txt
 
help out* # посмотреть, куда можно выводить результат
get-service | out-printer # напечатать список служб
Get-Service | ConvertTo-HTML > services.html # создать HTML-страничку со списком служб

У командлетов есть определённый уровень воздействия (impact level) на систему, который задаётся параметром $confirmpreference (значение по умолчанию — High). Если уровень воздействия командлета равен или превышает этот уровень, то выдаётся запрос подтверждения.

# Можно форсировать запросы подтверждения
Get-Service | Stop-Service -confirm
# Эмуляция выполнения
Get-Service | Stop-Service -whatif

Отличие Import-CSV от Get-Content: Get-Content импортирует сырые неструктурированные данные из CSV, тогда как Import-CSV разбирает CSV и представляет его в удобном виде. Та же параллель с XML.

# Без комментария о типе файла, не перезаписывать сущ. файл,
# использовать в качестве разделителя региональные параметры, подтверждать действие
Get-Service | Export-CSV services.csv -NoTypeInformation -NoClobber -UseCulture -Confirm

Расширения

Два типа расширений: оснастка (snap-in) и модуль (module). От использования оснасток уходят в пользу модулей.

# вывести список установленных, но не загруженных оснасток
get-pssnapin –registered
# загрузить оснастку (указать имя)
add-pssnapin sqlservercmdletsnapin100
# Вывести список команд, принадлежащих к загруженной оснастке
Get-Command -pssnapin sqlservercmdletsnapin100

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

Чтобы загружать нужные оснастки прямо при запуске PS, нужно загрузить эти оснастки, а затем сохранить их:

Export-Console c:myshell.psc
# Загрузить PS уже с нужными оснастками
%windir%system32WindowsPowerShellv1.0powershell.exe -noexit -psconsolefile c:myshell.psc

Модули в этом способе не участвуют.

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

get-content env:psmodulepath
get-module # список модулей
import-module # загрузить модуль

С 3-й версии PS нужно прописывать путь в переменной, если где-то лежит модуль и его нужно использовать. Это нужно для автоматической загрузки нужного модуля при вызове его командлета. Как и оснастка, модуль может добавить нового провайдера.

Для автозагрузки модулей при старте PS есть механизм сценария профиля (profile script):

  1. Сделать подпапку WindowsPowerShell в «Документах», создать в ней файл profile.ps1

  2. В этом файле прописать все нужные команды Add-PSSnapin и Import-Module для загрузки нужных расширений.

  3. В PS от админа выполнить команду

    Set-ExecutionPolicy RemoteSigned
  4. Переоткрыть PS, после этого profile.ps1 будет загружен автоматически.

Галерея модулей: http://powershellgallery.com. Есть модуль PowerShellGet для удобной установки модулей из галереи.

Объекты

Если вывести Get-Process, то будет таблица с видом по умолчанию, большинство свойств будут скрыты — это обусловлено тем, что выводить все свойства на экран нецелесообразно из-за ограниченного пространства на экране. Один из способов показать все свойства без фильтрации — это направить вывод в HTML:

Get-Process | ConvertTo-HTML | Out-File processes.html

Собственно, объектом (object) называется строка в «таблице», представляющая собой одну сущность — процесс, службу и т. д.

Свойством (property) называется колонка таблицы — один тип информации о процессах, сервисах и т. п.

Метод (method) — также обозначается как действие (action). Взаимодействует с объектом — например, останавливает процесс, запускает службу и т. д.

Набор (collection) — все объекты, которые перечислены в этой «таблице».

Get-Process | Get-Member # (или gm) показать свойства и методы командлета

К примеру, чтобы убить процесс, есть три пути: вызвать метод kill,

# передать через пайп
Get-Process -Name Notepad | Stop-Process
# или обойтись одним командлетом
Stop-Process -name Notepad

Сортировка

Get-Process | Sort-Object -property VM
Get-Process | Sort VM -desc # сокращённо и в обратном порядке
# Если несколько процессов занимают одинаковое кол-во памяти, сортировать по ID
Get-Process | Sort VM,ID -desc

Выбор свойств

Select-Object можно написать как просто select.

Get-Process | Select-Object -property Name,ID,VM,PM | Convert-ToHTML | Out-File test2.html
Get-Process | Select -First 10 # 10 первых, -Last - 10 последних

Нужно не путать Select-Object (выбор свойств для отображения) с Where-Object (фильтрует объекты после пайпа на основании заданных критериев).

Ещё про пайп

Положим, есть список имён компьютеров в текстовике, и PS позволяет сделать так:

Get-Content .computers.txt | Get-Service

Это нзывается привязкой параметров (parameter binding). PS смотрит на тип полученных данных и далее применяет его к параметру второй команды, способному принять такой тип данных. В данном случае Get-Content производит данные типа System.String (или, коротко, String). Get-Service принимает тип данных String параметром -Name. Тип выдаваемых данных можно посмотреть командой Get-Member (или gm), а тип принимаемых данных — в справке по командлету в строке «Accept pipeline input?» того или иного параметра.

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

get-process -name note* | Stop-Process

Если привязка по значению (ByValue) не удаётся, PS пробует другой подход — по имени параметра (ByPropertyName). Благодаря этому возможно такое (обратите внимание, что параметр -name указан явно):

get-service -name s* | stop-process

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

Более успешный пример — создать файл .csv cо следующим содержанием:

aliases.csv
Name,Value
d,Get-ChildItem
sel,Select-Object
go,Invoke-Command

Если выполнить Get-Member, то можно узнать, что Import-CSV выдаёт на выходе

import-csv .aliases.csv | gm

Далее, если выполнить

import-csv .aliases.csv | new-alias

то окажется, что создались три новых алиаса для командлетов, так как строки при импорте преобразовались в объекты, а параметры Name и Value совпали с одноимёнными параметрами в командлете New-Alias.

Замена параметров при передаче

Например, есть файл CSV, который был прислан извне, и на базе него нужно создать пользователей в AD.

newusers.csv
login,dept,city,title
DonJ,IT,Las Vegas,CTO
GregS,Custodial,Denver,Janitor
JeffH,IT,Syracuse,Network Engineer

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

import-csv .newusers.csv | select-object -property *,
>> @{name='samAccountName';expression={$_.login}},
>> @{label='Name';expression={$_.login}},
>> @{n='Department';e={$_.Dept}} | New-ADUser

-property * — вывести все доступные свойства.

@{key=value} — создание хэш-таблиц соответствия. Ключ может указываться как Name, N, Label или L. Значение — как Expression или E.

$_ — обращение к исходному объекту, передаваемому через пайп.

Скобки

Некоторые командлеты не принимают данные через пайп, например, Get-WmiObject -ComputerName. Выход — использовать скобки, которые действуют как в алгебре, т. е., в скобках действие выполняется в первую очередь.

# Так работать не будет:
get-content .computers.txt | get-wmiobject -class win32_bios
# А так - будет:
Get-WmiObject -class Win32_BIOS -ComputerName (Get-Content .computers.txt)

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

# Так работать не будет, в скобках тип будет ADComputer,
# а нужно String:
Get-Service -computerName (Get-ADComputer -filter * -searchBase "ou=domain controllers,dc=company,dc=pri")
# А так - будет (передать только имена):
Get-Service -computerName (Get-ADComputer -filter * -searchbase "ou=domain controllers,dc=company,dc=pri" | select -expand name)
# -expand - вывести значения без названия столбца

Форматирование

В папке $pshome есть файл otnettypes.format.ps1xml, отвечающий за форматирование вывода команд. Например, если выполнить

Get-Process | gm

скопировать тип (System.Diagnostics.Process) и поискать его в файле otnettypes.format.ps1xml, то под строкой <Name>process</Name> будут находиться стандартные параметры форматирования вывода команды.

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

Get-WmiObject Win32_OperatingSystem | Gm

Такого типа данных нет в otnettypes.format.ps1xml, в этом случае используется «второе правило форматирования» — вывод по умолчанию, описанный в Types.ps1xml (DefaultDisplayPropertySet).

«Третье правило» форматирует вывод согласно его типу, например, если отображается до 4 параметров, используется таблица, 5 и более — список.

Команды форматирования

Format-Table (ft) — таблица.

-AutoSize — подгоняет ширину столбцов под длину строк.

-Property — выбор столбцов для отображения, перечисляются через запятую. Звёздочка — вывести все столбцы.

Примеры:

Get-Process | Format-Table -property *
Get-Process | Format-Table -property ID,Name,Responding -autoSize
Get-Process | Format-Table * -autoSize

-groupby — сортировка по какому-то из столбцов.

-Wrap — перенос строк в столбце.

Format-List (fl) — список. Используются те же параметры, что и для таблицы.

В какой-то степени fl можно использовать как gm, с той разницей, что fl покажет и значения параметров.

Get-Service | Fl *

Format-Wide (fw) — широкий список. Выводит только одно свойство (-Property), но в несколько колонок.

Get-Process | Format-Wide name -col 4

Более комплексные примеры:

Get-Service | Format-Table @{name='ServiceName';expression={$_.Name}},Status,DisplayName
Get-Process | Format-Table Name,@{name='VM(MB)';expression={$_.VM / 1MB -as [int]}} -autosize
Get-Process | Format-Table Name,@{name='VM(MB)';expression={$_.VM};formatstring='F2';align='right'} -autosize

formatstring — код стандартного форматирования чисел и дат (https://msdn.microsoft.com/en-us/library/fbxft59x(v=vs.95).aspx).

-Width — задаваемая ширина столбца.

align — выравнивание.

Вывод

Если используется команда, начинающаяся с Format-, то правила форматирования для этих команд заданы так, что вывод делается в Out-Default, который передаёт данные в Out-Host (на экран). То есть, эти две строки дадут одинаковый результат:

Get-Service | Format-Wide | Out-Host
Get-Service | Format-Wide

Можно вывести данные в файл и на принтер, т. е., использовать Out-File и Out-Printer. У каждой из этих команд свои правила форматирования по умолчанию.

Также, есть команда Out-GridView, которая создаёт стандартное окно Windows с выводимой информацией, в консоль ничего не выводится (в других системах может не работать). Out-GridView не принимает правил форматирования и обрабатывает только стандартные объекты.

Команды форматирования (Format-*) должны идти последними в строке, единственное исключение — команды вывода (Out-*). Пример неправильного использования (в файле services.html будет ересь, т. к. в него передаются инструкции форматирования вместо объектов):

Get-Service | Select Name,DisplayName,Status | Format-Table | ConvertTo-HTML | Out-File services.html

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

Фильтр результатов и сравнение

Два подхода: запрос сразу нужной информации (the filter left technique) и последующая фильтрация результатов другой командой. Желательно по-максимуму использовать первый как потребляющий меньше ресурсов.

Для последующей фильтрации используется команда Where-Object (where).

Операторы сравнения

-eq — Equality

-ne — Not equal to

-ge — Greater than or equal to

-le — Less than or equal to

-gt — Greater than

-lt — Less than

Для сравнения нескольких строк одновременно используются -and и -or. Например, (5 -gt 10) -and (10 -gt 100) — это False, т. к. одно утверждение неверно, а (5 -gt 10) -or (10 -lt 100) — True, так как одно утверждение верно.

Оператор -not меняет True или False на противоположное значение. Например,

$_.Responding -eq $False
# можно написать как
-not $_.Responding
 
# Ещё пример фильтра
Get-ADComputer -Filter 'Name -notlike "*0000*" -and Enabled -eq "True"' | select Name | sort Name

Иногда -not пишется как !.

-like — понимает маски, например «Hello» -like «*ll*» — true. Противоположный оператор — -notlike.

-match — сравнение текстовой строки и регулярного выражения. Противоположный оператор — -notmatch.

Если нужно использовать чувствительные к регистру операторы, в начале добавляется «c»: -ceq, -cne, -cgt, -clt, -cge, -cle, -clike, -cnotlike, -cmatch, -cnotmatch. Полезно для операций со строками.

# Справка
help about_comparison_operators

Примеры использования фильтрации уже полученных результатов:

Get-Service | Where Status -eq 'Running'
get-service | where-object {$_.status -eq 'running' -AND $_.StartType -eq 'Manual'}

Удалённый доступ

# Включить на целевой машине
Enable-PSRemoting
# Справка:
about_remote_troubleshooting

Иногда советуют запускать Set-WSManQuickConfig, но это не нужно, т.к. Enable-PSRemoting сам запускает Set-WSManQuickConfig и выполняет дополнительные действия, такие, как создание правила на файрволле. WinRM v2 использует порты TCP 5985 (HTTP) и 5986 (HTTPS), Enable-PSRemoting стандартно конфигурирует доступ через 5985 (HTTP). В домене можно включить удалённый доступ через GPO: Computer Configuration → Administrative Templates → Windows Components → Remote Shell + Windows Remote Management. Через GPO также можно настроить длительность неактивных сессий, кол-во одновременных подключений, права и т. д.

Менять номер порта не рекомендуется, но возможно:

Winrm set winrm/config/listener?Address=*+Transport=HTTP
@{Port="1234"}

Два способа подключения: one-to-one (1:1) и one-to-many (1:N)

1:1 как RDP, только консоль.

Enter-PSSession -computerName Server-R2
[server-r2] PS C:>
# Выйти:
Exit-PSSession

Ограничения:

  1. PS-профили, которые есть на удалённой машине, загружены не будут.

  2. Удалённая сессия будет ограничена политикой выполнения (execution policy) удалённой машины, а не локальной.

Без крайней необходимости лучше не запускать удалённые сессии из-под удалённых сессий (remoting chain), т. к. это трудно отслеживать. Иногда это бывает нужно, например, если третья машина находится за шлюзом и напрямую сессию запустить нельзя.

One-to-many (1:N) — каждый комп запускает команду у себя и возвращает результат.

Invoke-Command -computerName Server-R2,Server-DC4,Server12
-command { Get-EventLog Security -newest 200 |
Where { $_.EventID -eq 1212 }}
# Вместо -command можно использовать -scriptblock, указывая путь к скрипту.

По умолчанию PS запускает 32 удалённых запроса одновременно, остальные ставит в очередь, это можно изменить с помощью параметра -throttleLimit.

# Запуск команды на серверах в списке
Invoke-Command -command { dir }
-computerName (Get-Content webservers.txt)
# Взять список из AD (нужен RSAT на клиенте)
Invoke-Command -command { dir } -computerName (
Get-ADComputer -filter * -searchBase "ou=Sales,dc=company,dc=pri" |
Select-Object -expand Name )

Разница между Invoke-Command и -computerName

Get-EventLog Security -newest 200
-computerName Server-R2,Server-DC4,Server12
| Where { $_.EventID -eq 1212 }
  1. Команда запускается последовательно на каждой машине. не параллельно.

  2. В выводе нет свойства PSComputerName, т. е. трудно сказать, с какой машины какой результат.

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

  4. Фильтр по событию 1212 применяется уже после запроса, следовательно, по сети будут передаваться ненужные события.

  5. События являются объектами, т. е., полностью функциональны.

Invoke-Command -computerName Server-R2,Server-DC4,Server12
-command { Get-EventLog Security -newest 200 |
Where { $_.EventID -eq 1212 }}
  1. Команда запускается одновременно на всех машинах, выполнится быстрее.

  2. В выводе есть свойство PSComputerName, легко определить что откуда.

  3. Используется WinRM, проще сделать правила на файрволлах между клиентом и серверами.

  4. Фильтрация происходит на серверах, и по сети передаётся уже готовый вывод.

  5. Перед передачей на клиента, серверы формируют (serialize) результат в виде XML, клиент при получении обрабатывает (deserialize) информацию и выводит её на экран. Это выглядит как объекты, но ими не является.

Локальная и удалённая обработка

# Фильтрация на удалённых серверах
Invoke-Command -computerName Server-R2,Server-DC4,Server12
-command { Get-EventLog Security -newest 200 |
Where { $_.EventID -eq 1212 }}
# Фильтрация на клиенте (плохая идея)
Invoke-Command -computerName Server-R2,Server-DC4,Server12
-command { Get-EventLog Security -newest 200 } |
Where { $_.EventID -eq 1212 }
# Работать не будет, т.к. результат выдачи с сервера - не объект
Invoke-Command -computerName Server-R2
-command { Get-Process -name Notepad } |
Stop-Process
# Сработает
Invoke-Command -computerName Server-R2
-command { Get-Process -name Notepad |
Stop-Process }
# На локальной машине доступны методы
get-service | get-member
# Здесь методов не будет, потому что вывод - не объекты
Invoke-Command -ScriptBlock { Get-Service } -ComputerName
server2 | Get-Member

Настройки удалённой сессии

Параметр -SessionOption при запуске Invoke-Command или Enter-PSSession.

  1. Задаёт таймауты сессий

  2. Выключает сжатие и шифрование данных

  3. Пропуск проверки SSL-сертификатов, имени и других проверок безопасности

Enter-PSSession -ComputerName server2
-SessionOption (New-PSSessionOption -SkipCNCheck)

Примечания

  • Удалённые сессии работают с реальными именами компьютеров — IP и алиасы использовать нельзя.

  • Конфигурация по умолчанию рассчитана на домен, если что — надо читать help about_remote_troubleshooting, например, если надо настроить работу удалённых сессий между доменами.

  • Invoke-Command — это значит, что команда выполняется на удалённой машине, и PS там закрывается, соответственно, данные больше недоступны. При множестве последовательных взаимозависимых команд нужно запускать их в рамках одной сессии.

  • Для успешной работы нужно убедиться, что она идёт под админом, либо нужно использовать параметр -credential, где указывать админскую учётку.

  • Enable-PSRemoting создаёт правило только для Windows firewall, другие файрволлы надо настраивать отдельно.

  • GPO перекрывает локальные настройки, если что-то не работает, полезно проверить настройки GPO.

Рекомендуется книга Secrets of PowerShell Remoting.

WMI и CIM

WMI содержит пространства имён (namespaces), например, rootCIMv2 содержит данные о Windows и железе, rootMicrosoftDNS — о роли DNS (если она установлена), rootSecurityCenter (rootSecurityCenter2) — файрволл, антивирус, антишпионское ПО.

Также, WMI содержит классы — управляемые компоненты, к которым WMI умеет обращаться. Например, Antivirus-
Product в rootSecurityCenter, Win32_LogicalDisk в rootCIMv2. Наличие какого-то класса не означает, что в системе есть такой компонент — например, класс Win32_TapeDrive есть во всех версиях Windows независимо от того, есть стример в реальности или нет.

Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiSpywareProduct
 
displayName              : Kaspersky Endpoint Security для Windows
instanceGuid             : {B1D2E896-6D96-7460-F17A-838B9D00DD65}
pathToSignedProductExe   : C:Program Files (x86)Kaspersky LabKaspersky Endpoint Security for Windowswmias.exe
pathToSignedReportingExe : C:Program Files (x86)Kaspersky LabKaspersky Endpoint Security for Windowsx64wmi64.exe
productState             : 266240
timestamp                : Thu, 18 Apr 2019 12:14:05 GMT
PSComputerName           :
 
displayName              : Windows Defender
instanceGuid             : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46}
pathToSignedProductExe   : %ProgramFiles%Windows DefenderMSASCui.exe
pathToSignedReportingExe : %ProgramFiles%Windows DefenderMsMpeng.exe
productState             : 393472
timestamp                : Tue, 23 May 2017 06:40:25 GMT
PSComputerName           :

Просматривать репозиторий WMI удобно с помощью WMI explorer. Можно искать и так:

Get-WmiObject -Namespace root/CIMV2 -list |where name -match 'disk' |sort name

WIM-команды, типа Get-WmiObject и Invoke-WmiMethod — устаревшие, не развиваются, работают через RPC, пробросить их через файрволл трудно. Их можно использовать на старых системах, в ОС Windows Server 2012 R2 и новее они отключены по умолчанию. CIM-команды, типа Get-CimInstance и Invoke-CimMethod — современная замена, работают через WS-MAN (WinRM).

# Вывести все классы в пространстве имён cimv2
Get-WmiObject -namespace rootcimv2 -list
# Содержимое класса win32_desktop
Get-WmiObject -namespace rootcimv2 -class win32_desktop
Get-WmiObject win32_desktop # или так
# использование алиаса
gwmi antispywareproduct -namespace rootsecuritycenter2
# методы и свойства класса
gwmi win32_operatingsystem | gm
# фильтр
gwmi win32_desktop -filter "name='COMPANY\Administrator'"
  • Операторы сравнения не как в PS (-like, -eq), а =, <, >= и т. д. Можно использовать LIKE, и как указатель wildcard нужно писать не *, а %, например, «NAME LIKE ‘%administrator%’».

  • Строки сравнения — в одиночных кавычках, весь фильтр — в двойных.

  • Обратная косая черта () — экранирующий знак, если нужно поставить в строке , то придётся удваивать — \.

  • Вывод gwmi всегда содержит ряд системных свойств, которые начинаются с двойного подчёркивания, по умолчанию PS часто подавляет их вывод, но это можно переопределить. Пара полезных свойств: __SERVER — имя компьютера, с которого была запрошена информация (это же имя есть в PSComputerName), __PATH — абсолютный путь к запущенному экземпляру.

# выполняется последовательно, если комп недоступен - выдаёт ошибку и идёт дальше
Gwmi Win32_BIOS -comp server-r2,server3,dc4
# вариант с форматированием и названием колонок
gwmi win32_bios -computer server-r2,localhost |
ft @{label='ComputerName';expression={$_.__SERVER}},
@{label='BIOSSerial';expression={$_.SerialNumber}},
@{label='OSBuild';expression= {gwmi -class win32_operatingsystem
-computer $_.__SERVER | select -expand BuildNumber}} –autosize

Отличия Get-CimInstance от Get-WmiObject:

  1. Используется -ClassName, а не -Class

  2. Нет параметра -List, вместо этого нужно использовать Get-CimClass с параметром -Namespace

  3. Нет параметра -Credential, если нужны другие учётные данные для запуска, надо использовать Invoke-Command

Особенность работы с WMI в Powershell — справка малоэффективна, нужно гуглить или пользоваться всякими костылями типа WMI Explorer.

Несколько задач одновременно, фоновый режим

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

  • В синхронном режиме можно отвечать на возникающие запросы, в асинхронном — возникший запрос остановит задачу.

  • В синхронном режиме сразу появляются сообщения об ошибках, если что-то идёт не так, в асинхронном сразу увидеть ошибки нельзя, но можно их захватывать определённым способом.

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

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

В фоне нужно запускать только хорошо отлаженные сценарии, с наибольшим шансом успешного выполнения. Фоновые команды в PS называются задачи (jobs). Эти задачи можно создавать несколькими способами, также есть несколько способов управления ими.

# Запустить задачу
Start-Job -ScriptBlock {dir} -Name Job1 -Credential DOMAINUsername
# Задача из файла, на другой машине
Start-Job -FilePath C:tempscript.ps1 -Name Job2 -Credential DOMAINUsername -Computer server2

Все эти задачи называются локальными, т. к. запуск идёт с локальной машины. После запуска задачам присваивается ID, причём, номера ID идут непоследовательно, так как у каждой задачи есть дочерние процессы (child jobs). Несмотря на то, что задачи локальные, они требуют работающего механизма PowerShell’s remoting system, иначе работать не будет.

У Get-WmiObject есть параметр -AsJob, который запускает командлет в фоне, но там нельзя выбрать произвольное имя задачи.

get-wmiobject win32_operatingsystem -computername (get-content allservers.txt) –asjob
 
WARNING: column "Command" does not fit into the display and was removed.
Id Name State HasMoreData Location
-- ---- ----- ----------- --------
5 Job5 Running False server-r2,localhost
 
# Посмотреть другие команды, у которых есть параметр -AsJob
Help * -parameter asjob

У Get-CimInstance нет параметра -AsJob, его нужно использовать в сочетании с Start-Job или Invoke-Command.

Создание удалённой фоновой задачи:

invoke-command -command { get-process }
-computername (get-content .allservers.txt )
-asjob -jobname MyRemoteJob
 
WARNING: column "Command" does not fit into the display and was removed.
Id Name State HasMoreData Location
-- ---- ----- ----------- --------
8 MyRemoteJob Running True server-r2,localhost

Просмотр результатов

get-job # список задач
get-job -id 1 | fl * # подробности первой задачи
receive-job -id 1 # вывод результатов. Нужно указать ID или имя задачи
# сортировка результата удалённой задачи
receive-job -name myremotejob | sort-object PSComputerName |
Format-Table -groupby PSComputerName
  • Если вывести результаты материнской задачи, они будут включать результаты дочерних. Как вариант, можно выводить результаты одной или нескольких дочерних задач.

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

  • Результаты могут не быть объектами (deserialized objects), и методы к ним не могут применяться, но можно форматировать вывод (sort, fl и т. д.)

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

C:> start-job -scriptblock { dir }
# выведет список по пути
$env:userprofileDocuments

Поэтому, в командах нужно указывать пути.

Работа с задачами

  • Remove-Job — удалить вместе с результатом выполнения в кэше

  • Stop-Job — прервать выполнение, результаты останутся на момент прерывания

  • Wait-Job — полезно в скрипте, указание ждать выполнения задачи

# Показать дочерние задания
get-job -id 1 | select -expand childjobs
# грохнуть все задачи, где уже нет результатов
get-job | where { -not $_.HasMoreData } | remove-job

Если фоновая задача выполнилась с ошибкой (State failed), то текст ошибки хранится как результат в дочерней задаче.

Запланированные задачи (scheduled jobs)

Это несколько отличается как от фоновых задач PS, так и от заданий в планировщике Windows (scheduled tasks). Чтобы создать задачу, нужно задать триггер (New-JobTrigger), определяющий, когда задача запускается, параметры задачи (New-ScheduledTaskOption), затем задача регистрируется в Планировщике — на диске создаётся файл XML и иерархия каталогов для хранения результатов выполнения.

Register-ScheduledJob -Name DailyProcList -ScriptBlock {
Get-Process } -Trigger (New-JobTrigger -Daily -At 2am)
-ScheduledJobOption (New-ScheduledJobOption -WakeToRun -RunElevated)

Если запросить список задач (Get-Job), то видно, что каждый раз при выполнении запланированной задачи создаётся задача в списке, причём, если запрашивать результат выполнения, то они не удалятся, так как хранятся на диске, а не в памяти. Но если удалить задачу, то результаты будут также удалены с диска. Количество создаваемых и хранимых задач регулируется параметром -MaxResultCount в команде Register-ScheduledJob.

Как делать не надо:

# после запуска соединение прерывается, и результаты задачи уже не будут доступны
invoke-command -command { Start-Job -scriptblock { dir } } -computername Server-R2
# здесь нужно использовать -AsJob у Invoke-Command
start-job -scriptblock { invoke-command -command { dir } -computername SERVER-R2 }

Вообще, не надо мешать в кучу рассмотренные три способа запуска задач.

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

# Последние 25 ошибок из системного лога выгружать в XML
# с пн по пт в 6:00
Register-ScheduledJob -ScriptBlock {Get-EventLog -LogName System -Newest 25 -EntryType Error |
Export-Clixml -Path C:Tempjob.xml} -Name EventLogErrors -Trigger (
New-JobTrigger -Weekly -DaysOfWeek 1,2,3,4,5 -At 6AM)

Работа со многими объектами одновременно

В отличие от подхода, когда запрашивается какое-то количество объектов и потом они обрабатываются, перебираясь по одному (foreach), есть более эффективные способы обработки.

Предпочтительный путь — использование «пакетных» команд. Это команды, способные принимать данные через пайп.

Get-Service | Stop-Service
Get-Service -name BITS,Spooler,W32Time | Set-Service -startuptype Automatic
 
# Недостаток - не видно вывода от предыдущих команд
Get-Service -name BITS,Spooler,W32Time -computer Server1,Server2,Server3 | Set-Service -startuptype Automatic
# Теперь видно, с использованием -PassThru
Get-Service -name BITS -computer Server1,Server2,Server3 | Start-Service -passthru | Out-File NewServiceStatus.txt

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

# Запрос интеловских адаптеров
gwmi win32_networkadapterconfiguration -filter "description like '%intel%'"
# Вывод доступных объектов внутри, там есть метод EnableDHCP().
gwmi win32_networkadapterconfiguration -filter "description like '%intel%'" | gm
# Вот так работать не будет:
gwmi win32_networkadapterconfiguration -filter "description like '%intel%'" | EnableDHCP()
# Нужно использовать специальную команду для вызова методов WMI
# Код возврата выполненного метода (ReturnValue) можно погуглить
gwmi win32_networkadapterconfiguration -filter "description like '%intel%'" | Invoke-WmiMethod -name EnableDHCP
# То же самое с CIM
gcim -classname win32_networkadapterconfiguration -filter "description like '%intel%'" |Invoke-CimMethod -methodname EnableDHCP

Также, можно в случае с WMI/CIM поискать другой, родной для PS командлет, выполняющий нужную функцию — в данном случае Set-NetIPAddress.

Тем не менее, иногда приходится использовать перебор. Например, нужно задать пароль для запуска служб, и ни Get-Service, ни Set-Service с паролями работать не умеют, придётся использовать WMI. В методе change много параметров, для пропуска ненужных используется переменная $null.

# Так работать не будет:
gwmi win32_service -filter "name = 'BITS'" | invoke-wmimethod -name
change -arg $null,$null,$null,$null,$null,$null,$null,"P@ssw0rd"
# Invoke-WmiMethod : Input string was not in a correct format.
 
# Можно долго выяснять, в чём дело, но быстрее и проще использовать перебор (% = foreach):
gwmi win32_service -filter "name = 'BITS'" |
% {$_.change($null,$null,$null,$null,$null,$null,$null,"P@ssw0rd") }

Иллюстрация разных подходов

Get-Service -name *B* | Stop-Service # пакетная команда
Get-Service -name *B* | % { $_.Stop()} # перебор
Get-WmiObject Win32_Service -filter "name LIKE '%B%'" |
Invoke-WmiMethod -name StopService # WMI
Get-WmiObject Win32_Service -filter "name LIKE '%B%'" |
% { $_.StopService()} # WMI с перебором
Stop-Service -name *B* # специализированная команда

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

Get-Something | ForEach-Object { $_.Delete() }

Безопасность

Политика выполнения скриптов — в клиентских системах вообще запрещено (Restricted), на серверах можно выполнять те, что созданы локально или подписанные (RemoteSigned).

Можно управлять политикой выполнения через GPO (Computer Configuration → Policies → Administrative Templates → Windows Components → Windows PowerShell).
AllSigned — все скрипты должны быть подписаны доверенным УЦ.

Unrestricted — можно всё.

Bypass — для использования в приложениях, работающих с PS.

Plenty of experts, including Microsoft’s own “Scripting Guy,” suggest
using the Unrestricted setting for ExecutionPolicy. Their feeling is that the
feature doesn’t provide a layer of security, and you shouldn’t give yourself
false confidence that it’s protecting you from anything.

Дополнительные меры:

  1. Скрипты .ps1 не выполняются по двойному клику мышкой, а открываются как текстовые файлы.

  2. Запустить скрипт из консоли невозможно, просто набирая его имя, т. к. консоль не ищет скрипты в локальной папке.

Сделать самоподписанный сертификат для подписи кода

help about_signing
New-SelfSignedCertificate

Переменные — место для хранения

Переменные могут содержать пробелы, тогда нужно их заключать в фигурные скобки: ${variable 1}. Переменные не сохраняются между сессиями PS. PS воспринимает заключённое в одинарные кавычки буквально, поэтому

$var = 'What does $var contain?'
$var
What does $var contain?
 
$computername = 'SERVER-R2'
$phrase = "The computer name is $computername"
$phrase
The computer name is SERVER-R2

Символ ` (escape character, под ~) — отменяет действие последующего символа, т. е.,

$computername = 'SERVER-R2'
$phrase = "`$computername contains $computername"
$phrase
$computername contains SERVER-R2
 
$phrase = "`$computername`ncontains`n$computername"
$phrase
$computername
contains
SERVER-R2
 
# справка
help about_escape
# Несколько объектов в переменной
$computers = 'SERVER-R2','SERVER1','localhost'
$computers
SERVER-R2
SERVER1
Localhost
 
# Извлечение отдельных элементов из массива
# Первый объект - 0, второй - 1, последний - -1, предпоследний - -2
$computers[0]
SERVER-R2
$computers[1]
SERVER1
$computers[-1]
localhost
$computers[-2]
SERVER1
 
# Подсчёт кол-ва объектов
$computers.count
3
 
# Вызов свойств и методов
$computername.length
9
$computername.toupper()
SERVER-R2
$computername.tolower()
server-r2
$computername.replace('R2','2008')
SERVER-2008
$computername
SERVER-R2
 
# Применительно к отдельному объекту массива
$computers[0].tolower()
server-r2
$computers[1].replace('SERVER','CLIENT')
CLIENT1
 
# Заменить значение в массиве
$computers[1] = $computers[1].replace('SERVER','CLIENT')
$computers
SERVER-R2
CLIENT1
Localhost
 
# Обработка всех значений в массиве
$computers = $computers | ForEach-Object { $_.ToLower()}
$computers
server-r2
client1
localhost

В PS v1 и v2 у переменных, содержащих множественные значения, нельзя было использовать методы и свойства, с v3 сделали авторазвёртывание (automatic unrolling), т. е.

# PS v3 понимает, что у $services нет св-ва Name, но у дочерних объектов есть
$services = Get-Service
$services.Name
# Для предыдущих версий нужно было бы делать так
Get-Service | ForEach-Object { Write-Output $_.Name }
# или так
Get-Service | Select-Object –ExpandProperty Name
 
# то же работает и для методов
$objects = Get-WmiObject –class Win32_Service –filter "name='BITS'"
$objects.ChangeStartMode('Disabled')
# Так работать не будет - двойные кавычки не воспринимают
# конструкцию [0].name как функциональную часть
$services = get-service
$firstname = "$services[0].name"
$firstname
AeLookupSvc ALG AllUserInstallAgent AppIDSvc ... wudfsvc WwanSvc[0].name
# без кавычек это будет работать
 
# если кавычки всё же нужны, то используется субпеременная $()
$services = get-service
$firstname = "The first name is $($services[0].name)"
$firstname
The first name is AeLookupSvc

Иногда принудительное указание типа переменной необходимо.

$number = Read-Host "Enter a number"
Enter a number: 100
$number = $number * 10
$number
100100100100100100100100100100
# в данном случае 100 воспринимается как строка,
# и повторяется 10 раз вместо умножения.
# Посмотреть тип переменной:
$number |gm
 
# надо указать переменную так:
[int]$number = Read-Host "Enter a number"

Популярные типы переменных:

  • [int] — целое число

  • [single] и [double] — число с одним или двумя знаками после разделителя

  • [string] — строка

  • [char] — один символ

  • [xml] — документ с разметкой XML

  • [adsi] — запрос Active Directory Service Interfaces

Ввод и вывод

Запрос информации от пользователя

$computername = read-host "Enter a computer name"
Enter a computer name: SERVER-R2

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

# the void data type is a special type that means “throw the result away.”
# Another way to do the same thing would be to pipe the result to Out-Null.
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
# 1 - текст запроса, 2 - заголовок окна, 3 - предлагаемое значение
$computername = [Microsoft.VisualBasic.Interaction]::InputBox('Enter a computer name','Computer Name','localhost')

Вывод

write-host "COLORFUL!" -fore yellow -back magenta

Write-Host используется только для показа информации, не для форматирования, но тем не менее, он не используется для сообщений типа “now connecting to SERVER2,” “testing for folder,” и т. д. Для этого лучше использовать Write-Verbose. С 5-й версии PS, Write-Host по сути стал алиасом к более новой команде Write-Information.

В отличие от Write-Host, Write-Output умеет передавать информацию через пайп и технически не предназначена для отображения.

# Если написать
write-output "Hello"
# то информация пройдёт путь write-output "Hello" -> Out-Default -> Out-Host -> Hello.
 
# ничего не выведется
write-output "Hello" | where-object { $_.length -gt 10 }
# Hello будет выведено, т. к. пайп в данном случае не работает
write-host "Hello" | where-object { $_.length -gt 10 }

Другие команды вывода, работают подобно Write-Host. Чтобы их использовать, нужно задать их конфигурацию как Continue, изменив стандартное SilentlyContinue.

Cmdlet Purpose Configuration variable
Write-Warning Displays warning text, in yellow by default, and preceded by the label WARNING: $WarningPreference (Continue by default)
Write-Verbose Displays additional informative text, in yellow by default, and preceded by the label VERBOSE: $VerbosePreference (SilentlyContinue by default)
Write-Debug Displays debugging text, in yellow by default, and preceded by the label DEBUG: $DebugPreference (SilentlyContinue by default)
Write-Error Produces an error message (работает немного по-другому, т. к. пишет ошибку в поток вывода ошибок PS) $ErrorActionPreference (Continue by default)

Есть ещё Write-Progress, отображающий прогресс-бар, но он работает совсем по-другому.

Сессии: облегчение удалённого управления

В отличие от рассматривавшихся ранее Invoke-Command и Enter-PSSession, где нужно каждый раз задавать параметры подключения, механизм аутентификации, порты и т. д., существуют сессии — постоянное подключение локального PS к удалённому.

Используя New-PSSession, параметры задаются один раз, затем объект сессии хранится в памяти PS:

new-pssession -computername server-r2,server17,dc5
# вызвать сессии
get-pssession
# удобно помещать в переменную
$iis_servers = new-pssession -comp web1,web2,web3 -credential WebAdmin
# закрыть
$iis_servers | remove-pssession
# закрыть все (при закрытии консоли сессии закрываются автоматически)
get-pssession | remove-pssession
# зайти на первый сервер
enter-pssession -session $iis_servers [0]
# или так, если порядок неизвестен
enter-pssession -session ($iis_servers |where { $_.computername -eq 'web1' })
# или так (PS хранит сессии в общем списке, даже если они записаны в переменную)
enter-pssession -session (get-pssession -computer web1)
Get-PSSession -ComputerName web1 | Enter-PSSession # как вариант
# выйти
exit-pssession

Записывать сессии в переменную имеет смысл только тогда, когда компьютеров несколько.

$serv = New-PSSession -ComputerName serv1,serv2,serv3,serv4
Invoke-Command -Command {gwmi win32_process |select processname,csname |ft} -Session $serv

У Get-WmiObject есть свой параметр -computername (у Get-CimInstance нет, он заточен под использование удалённых сессий), но лучше его не использовать, так как

  • Удалённый доступ PS использует определённый порт, WMI нет.

  • Удалённый доступ экономит ресурсы, т.к. не одна машина запрашивает данные, а каждый выполняет свою работу и высылает результаты

  • Удалённые запросы выполняются параллельно, WMI работает последовательно

  • Ранее заданные сессии не могут быть использованы с Get-WmiObject

# Параметры -session можно дать результат команды в скобках.
Invoke-Command -Command {gwmi win32_process |select processname,csname |ft} -Session (Get-PSSession -ComputerName serv2,serv3)
# В данном случае, Invoke-Command не умеет получить объекты через пайп как Enter-PSSession.

Неявный доступ (implicit remoting) — импорт модулей и оснасток с удалённой машины. Удобно в случаях, когда нельзя поставить их на локальную тачку, например RSAT для 2008 R2 на Windows XP и т.п.

# установка соединения
$session = new-pssession -comp server-r2
# Загрузка нужного модуля
invoke-command -command { import-module activedirectory } -session $session
# Импорт команд модуля с добавлением префикса rem, чтобы не было путаницы (New-remADUser)
import-pssession -session $session -module activedirectory -prefix rem
# создаётся временный локальный модуль

Команды выполняются на удалённой машине и будут доступны до закрытия сессии или окна терминала. Минус — результат выполнения команд не будет объектами (deserialized).

С PSv3 можно возобновлять закрытые сессии

# Id Name ComputerName State
# 4 Session4 COMPUTER2 Disconnected
Get-PSSession -computerName COMPUTER2 | Connect-PSSession

Управлять параметрами сессий можно через GPO или WSMan drive (WSMan:localhostShell, WSMan:localhostService).

Скриптинг

С параметрами и документацией

Get-DiskInventory.ps1
<#
.SYNOPSIS
Get-DiskInventory retrieves logical disk information from one or
more computers.
.DESCRIPTION
Get-DiskInventory uses WMI to retrieve the Win32_LogicalDisk
instances from one or more computers. It displays each disk's
drive letter, free space, total size, and percentage of free
space.
.PARAMETER computername
The computer name, or names, to query. Default: Localhost.
.PARAMETER drivetype
The drive type to query. See Win32_LogicalDisk documentation
for values. 3 is a fixed disk, and is the default.
.EXAMPLE
Get-DiskInventory -computername SERVER-R2 -drivetype 3
#>
param (
$computername = 'localhost',
$drivetype = 3
)
gwmi Win32_LogicalDisk -comp $computername -filter "drivetype=3" |
Sort DeviceID |
ft DeviceID,@{n='FreeSpace(MB)';e={$_.FreeSpace / 1MB -as [int]}},
@{n='Size(GB)';e={$_.Size / 1GB -as [int]}},
@{n='%Free';e={$_.FreeSpace / $_.Size * 100 -as [int]}}

Значения параметров — значения по умолчанию.

# Справка
help .Get-DiskInventory -full
# почитать про справку
help about_comment_based_help

Скрипт выполняется в одном потоке, тогда как последовательные команды — каждый в своём.

Область (scope) — форма контейнера для хранения элементов PS. Сама консоль — global scope, верхний уровень. При запуске скрипта образуется script scope, являющийся дочерним (child) к global scope (parent). У функций есть свои private scopes, дочерние к скрипту. Все области существуют, пока запущен породивший их процесс. Если данные (например, переменная), не найдены в пределах области, PS смотрит на уровень выше, нет ли данных там.

Совершенствование задания параметров в скриптах

Сделать параметр Computername обязательным, с подсказкой при запросе и алиасом. Алиас позволяет при запуске указать тот же параметр другим именем. Также, проверяется параметр типа диска — принимается только 2 или 3.

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

[CmdletBinding()]
param (
[Parameter(Mandatory=$True,HelpMessage="Enter a computer name to query")]
[Alias('hostname')]
[string]$computername,
[ValidateSet(2,3)]
[int]$drivetype = 3
)
Write-Verbose "Подключение к $computername"
Write-Verbose "Поиск дисков типа $drivetype"
gwmi Win32_LogicalDisk -comp $computername -filter "drivetype=3" |
Sort DeviceID |
ft DeviceID,@{n='FreeSpace(MB)';e={$_.FreeSpace / 1MB -as [int]}},
@{n='Size(GB)';e={$_.Size / 1GB -as [int]}},
@{n='%Free';e={$_.FreeSpace / $_.Size * 100 -as [int]}}
Write-Verbose "Операция успешно завершена"
  • Все параметры заключены в блок param()

  • Один параметр может иметь несколько декораторов (decorators), которые могут быть написаны одной строкой или разделены на несколько для удобства восприятия

  • Имена параметров разделяются запятыми, кроме последнего, после которого запятой не нужно

  • Между параметрами лучше оставлять пустую строку, чтобы легче было читать

  • Параметры задаются как переменные, но используются при запуске скрипта как параметры запуска

# Прочесть про опции параметров:
help about_functions_advanced_parameters

Ещё пример

[CmdletBinding()]
param(
[Parameter(Mandatory=$True)]
[Alias('hostname')]
$computername
)
Write-Verbose "Подключение к $computername"
gwmi win32_networkadapter -computername $computername |
where { $_.PhysicalAdapter } |
select MACAddress,AdapterType,DeviceID,Name,Speed
Write-Verbose "Завершено"

Углублённая настройка удалённого управления

Иногда нужно указывать битность при использовании, например, удалённой 32-битной оснастки с 64-битной системы. Это одна из конфигураций сессии (endpoints, session configurations).

# Список доступных конфигураций
Get-PSSessionConfiguration
# Подключение с указанием конфигурации
Enter-PSSession -ComputerName DONJONES1D96 -ConfigurationName 'Microsoft.PowerShell32'

Создание конфигурации: New-PSSessionConfigurationFile создаёт файл конфигурации (.pssc), где перечислены всё характеристики. Register-PSSessionConfiguration считывает файл и создаёт endpoint, также можно задать разные параметры, например, права доступа, изменить эти параметры можно позже с помощью Set-PSSession-Configuration.

Это можно делать, к примеру, для делегирования кому-то выполнения некоторых команд

New-PSSessionConfigurationFile -Path C:HelpDeskEndpoint.pssc -ModulesToImport NetAdapter `
-SessionType RestrictedRemoteServer -CompanyName "Our Company" -Author "Don Jones" `
 -Description "Net adapter commands for use by help desk" -PowerShellVersion '3.0'
# -SessionType RestrictedRemoteServer - удаляет все базовые команды PS для этой сессии, за исключением необходимых
 
# Запуск конфигурации, будет запрос пароля для HelpDeskProxyAdmin
# -ShowSecurityDescriptorUI выводит окно с запросом, каким пользователям давать права
Register-PSSessionConfiguration -Path .HelpDeskEndpoint.pssc `
-RunAsCredential COMPANYHelpDeskProxyAdmin -ShowSecurityDescriptorUI `
-Name HelpDesk
 
# Использование созданной конфигурации
Enter-PSSession -ComputerName DONJONES1D96 -ConfigurationName HelpDesk
# Список доступных команд
Get-Command

Многоступенчатый удалённый доступ (multihop remoting). Если попробовать создать сессию на 3-й компьютер с удалённого, то ничего не выйдет, т. к. удалённый компьютер не имеет права делегирования прав локальной машины далее. Начиная с Windows Vista, это можно переопределить.

# На локальной машине (x - удалённый комп)
Enable-WSManCredSSP -Role Client -DelegateComputer x
# На удалённой машине
Enable-WSManCredSSP -Role Server

При удалённом доступе PS проверяет подлинность в том числе удалённой машины для защиты от спуфинга. Если указывается IP-адрес или алиас, то стандартный метод проверки не работает — надо задействовать SSL или TrustedHosts. См. бесплатную книгу Secrets of PowerShell Remoting для более подробной информации.

Регулярные выражения (regex) для разбора текстовых файлов

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

В PS слово уже является regex, т. к. запросы нечувствительны к регистру, например, запросив Don, можно получить DON, don, Don, DoN и т. д.

  • w — буква, цифра или подчёркивание, но не знак препинания и не пробел (won = Don, Ron, ton…)

  • W — наоборот

  • d — цифра

  • D — не цифра

  • s — любой «белый» разделитель — TAB, пробел или Enter

  • S — не s

  • . — один символ

  • [abcde] — набор символов для сравнения, используется один (d[aeiou]n = don или dan, но не doun или deen)

  • [a-z] — диапазон символов для сравнения, можно указывать несколько: [a-f,m-z], используется больше одного символа

  • [^abcde] — набор символов НЕ для сравнения, используются несколько (d[^aeiou] = dns, но не don)

  • ? — обозначает один экземпляр предыдущего символа или его отсутствие. do?n = don, donn или dn, но не doon.

  • * — любое кол-во символов

  • + — любое кол-во предыдущего символа или группы символов: (dn)+o — dndndndno

  • — экранирующий символ, чтобы вывести , надо написать

  • {2} — кол-во предыдущих символов. d{1} — одна цифра, {2,} — два символа и более, {1,3} — от одного до трёх.

  • ^ — начало строки. ^d.n = donrrr, но не равно rrrdon

  • $ — конец строки.

# справка
help about_regular_expressions
 
# примеры
"don" -match "d[aeiou]n"
True
"dooon" -match "d[aeiou]n"
False
"dooon" -match "d[aeiou]+n"
True
"djinn" -match "d[aeiou]+n"
False
"dean" -match "d[aeiou]n"
False
"(Windows+NT+6.2;+WOW64;+rv:11.0)+Gecko" -match "6.2;[wW]++Gecko"
True
# 6.2; — This is 6.2; and notice that we escaped the period to make it a literal character
# rather than the single-character wildcard that a period normally indicates.
# [wW]+ — This is one or more word or nonword characters—in other words, anything.
# +Gecko — This is a literal +, then Gecko.
 
C:logfiles> get-childitem -filter *.log -recurse |
select-string -pattern "s40[0-9]s" |
ft Filename,LineNumber,Line -wrap
 
# имена с двумя цифрами
dir $env:windir |? Name -match "d{2}"
 
# выбрать из кэша записи с IP-адресами
Get-DNSClientCache |? Data -match "d{1,}.d{1,}"

Разные прочие техники и трюки

Можно задать профиль для PS — настройки при каждом запуске, например

Import-Module ActiveDirectory
Add-PSSnapin SqlServerCmdletSnapin100
cd c:
 
# справка по профилям
help about_profiles

Профиль относится к приложению PS (hosting application — консоль, ISE), не движку. Размещение файла профиля в порядке чтения при запуске:

  1. $pshomeprofile.ps1 — для всех пользователей и всех приложений

  2. $pshomeMicrosoft.PowerShell_profile.ps1 — для консоли, $pshome/Microsoft.PowerShellISE_profile.ps1 — для ISE.

  3. $homeDocumentsWindowsPowerShellprofile.ps1 — для данного пользователя и всех приложений

  4. $homeDocumentsWindowsPowerShellMicrosoft.PowerShell_profile.ps1 — консоль, $homeDocumentsWindowsPowerShellMicrosoft.PowerShellISE_profile.ps1 — ISE.

«Все приложения» — консоль и ISE, но не сторонние приложения. Также на 64-битных системах может иметь значение задание профилей для 32- и 64-битных консолей и ISE, т. к. не все модули и оснастки есть для обоих вариантов. Профили — это те же скрипты, т. е., например, если execution policy Restricted, то профиль просто не запустится.

Операторы

# -as - создание объекта с другим типом
1000 / 3 -as [int]
# -is - проверяет объект и возвращает True или False
123.45 -is [int] # false
"SERVER-R2" -is [string] # true
$True -is [bool] # true
(Get-Date) -is [datetime] # true
# -replace
"192.168.34.12" -replace "34","15"
192.168.15.12
# -join
$array = "one","two","three","four","five"
PS C:> $array
one
two
three
four
five
$array -join "|"
one|two|three|four|five
# -split
(gc computers.tdf) -split "`t" |set-variable array # Server1 Windows East Managed (`t - TAB)
Server1
Windows
East
Managed
$array[0]
Server1
# -contains
'this' -contains '*his*'
False
'this' -like '*his*'
True
 
$collection = 'abc','def','ghi','jkl'
$collection -contains 'abc'
True
$collection -contains 'xyz'
False
 
# -in - возвращает true or false
$collection = 'abc','def','ghi','jkl'
'abc' -in $collection
True
'xyz' -in $collection
False

Манипуляции со строками

"Hello" | gm
 
# метод IndexOf()
"SERVER-R2".IndexOf("-")
6
 
# Split(), Join(), and Replace() operate similarly to the -split, -join, and -replace operators
# ToLower() and ToUpper()
"HeLLo".tolower()
hello
# trim ()
"      HeLLo".trim()
HeLLo

Манипуляции с датой

get-date | gm
(get-date).month
(get-date).adddays(-90)
(get-date).ToShortDateString()
28.05.2019

Даты WMI

# У WMI нечеловеческий формат дат
get-wmiobject win32_operatingsystem | select lastbootuptime
lastbootuptime
--------------
20190528095517.490356+180
 
get-wmiobject win32_operatingsystem |gm
# есть методы converttodatetime и convertfromdatetime
$i = get-wmiobject win32_operatingsystem
$i.converttodatetime($i.lastbootuptime)
28 мая 2019 г. 9:55:17
 
get-wmiobject win32_operatingsystem | select BuildNumber,__SERVER,
@{l='LastBootTime';e={$_.ConvertToDateTime($_.LastBootupTime)}}
 
# Команды CIM сразу выдают нормальный формат
gcim win32_operatingsystem | select lastbootuptime
lastbootuptime
--------------
28.05.2019 9:55:17

Задание стандартных значений параметров

Например, у dir стандартный параметр -Path — текущая папка.

Умолчания хранятся в спец. переменной $PSDefaultParameterValues, которая пуста при запуске консоли.

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

$credential = Get-Credential -UserName Administrator -Message "Enter Admin credential"
$PSDefaultParameterValues.Add('*:Credential',$credential)
# сделать это только для Invoke-Command
$PSDefaultParameterValues.Add('Invoke-Command:Credential',
{Get-Credential -Message 'Enter administrator credential' -UserName Administrator})
# используется метод add()? 1-й аргумент - команда, 2-й - параметр. * - применить ко всем.
# посмотреть список стандартных параметров
$PSDefaultParameterValues
# справка
help about_parameters_default_values

$PSDefaultParameterValues, как и другие переменные, действует в рамках области (scope), т. е., в контексте сущности, где переменная появилась. (help about_scope)

Scriptblocks

Скриптблок — то, что заключено в {}, кроме хэш-таблиц @{}

  • where -filterscript даёт скриптблок

  • foreach -process даёт скриптблок

  • Хэш-таблицы, которые используются при выборе свойств в select или format-table, принимают скриптблоки в качестве значения e= (expression).

  • Некоторые команды принимают скриптблоки в качестве параметра: Invoke-Command -ScriptBlock {} или Start-Job -ScriptBlock {}.

Чтобы вызвать скриптблок, нужно вначале ставить & (call).

$block = {get-process | sort -Property vm -Descending | select -first 10}
&$block
# справка
help about_script_blocks

Памятка

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

  • Распознать переменные, что они содержат, это поможет понять, что делает команда

  • Читать справку к новым командам

  • Использовать тестовую среду, например, VM.

Пунктуация

` (обратная кавычка) — экранирует последующий символ. Например, можно написать:

cd c:Program` Files

~ — папка профиля

( ) — как в арифметике, приоритет выполнения.

Get-Service -computerName (Get-Content c:computernames.txt)

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

[ ] — индекс объекта в массиве, отсчёт с нуля. $services[2] — третий объект. Также, тип объекта — [string], [int] и т. д.

{ } — скриптблок или фильтр

Get-Service | Where-Object { $_.Status -eq 'Running' }
# ключ=значение в хэш-таблицах
$hashtable = @{l='Label';e={expression}}
# как вариант написания переменной с пробелами и другими нестандартными символами
${My Variable}

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

» » — переменные, escape characters читаются.

$two = "Hello $one `n"

$ — знак переменной

% — foreach. It’s also the modulus operator, returning the remainder from a division operation.

? — where

> — направление вывода (Out-File)

+, -, /, % — математические операторы. «+» ещё используется как соединитель строк.

— — указывает на параметр или оператор (-computerName, -eq)

@ — указатель на:

  1. хэш-таблицу @{}

  2. массив $array = @(1,2,3,4). можно обойтись просто 1,2,3,4, т.к. PS и так воспринимает список с разделителями-запятыми как массив.

  3. here-string — @» «@ — блок с буквально читаемой строкой, также могут быть описаны как ‘ ‘. help about_quoting_rules

& — вызов (invocation operator), типа call в CMD

; — разделитель двух команд, которые пишутся в строку.

# — комментарий, <# #> — закомментировать много строк.

= — оператор присвоения. В сравнениях не используется, есть оператор -eq. Также используется с мат. операторами: $var +=5 прибавляет 5 к $var.

/ или — прямой — это деление, обратный — экранирующий символ в фильтре WMI и regex. Оба используются в путях.

. — вызов метода или свойства ($_.Status), путь к текущему каталогу, две точки — вышестоящий каталог.

, — вне кавычек — разделитель членов массива или значений для свойства команды (Get-Process -computername Server1,Server2,Server3).

: — (технически, ::) — доступ к статическим членам класса, например, .NET.

! — то же, что -not

В справке

[ ] — необязательный параметр (([-Name <string>]), или parameter is positional ([-Name] <string>), или и то и другое ([[-Name] <string>]). Также, указатель на то, что параметр может принимать множественные значения (<string[]>).

< > — типы данных (<string>, <int>, <process> и т. д.)

Операторы

  • -eq — равенство (-ceq — чувств. к регистру)

  • -ne — неравенство (-cne — чувств. к регистру)

  • -ge — больше или равно

  • -le — меньше или равно

  • -gt — больше, чем

  • -lt — меньше, чем

  • -contains — содержит объект ($collection -contains $object), возврат true or false, -notcontains — наоборот

  • -in — объект содержится в ($object -in $collection), возврат true or false, -notin — наоборот

Логические:

  • -not (или !) — true or false

  • -and — и

  • -or — или

Функциональные:

  • -join — объединяет строки в массив

  • -split — разъединяет массив в строки

  • -replace — замена одной строки на другую

  • -is — true, если объект такого типа ($one -is [int])

  • -as — назначение типа объекта ($one -as [int])

  • .. — диапазон (1..10)

  • -f — format operator, замена значений в массиве «{0}, {1}» -f «Hello»,»World»

Передача параметров через пайп делается двумя способами: сначала используется ByValue, когда PS смотрит на тип передаваемых данных и кто с другой стороны с этими данными способен работать, а второй — ByPropertyName, когда PS ищет одноимённые параметры, чтобы отдать данные туда.

$_ используется в скриптблоках после пайпа

Get-Service |? {$_.Status -eq 'Running'}
gwmi -class Win32_Service -filter "name='mssqlserver'" |
foreach -process { $_.ChangeStartMode('Automatic') }

В любом случае, $_ окружён { }.

Доп. материалы

PowerShell in Depth

Custom Object

Вариант 1:

$os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost
$cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost
$bios = Get-WmiObject –Class Win32_BIOS –comp localhost
$proc = Get-WmiObject –Class Win32_Processor –comp localhost |
Select –First 1
$props = @{OSVersion=$os.version
           Model=$cs.model
           Manufacturer=$cs.manufacturer
           BIOSSerial=$bios.serialnumber
           ComputerName=$os.CSName
           OSArchitecture=$os.osarchitecture
           ProcArchitecture=$proc.addresswidth}
$obj = New-Object –TypeName PSObject –Property $props
Write-Output $obj

В PS v3 и новее можно задать порядок свойств:

$props = [ordered]@{ OSVersion=$os.version
           Model=$cs.model
           Manufacturer=$cs.manufacturer
           BIOSSerial=$bios.serialnumber
           ComputerName=$os.CSName
           OSArchitecture=$os.osarchitecture
           ProcArchitecture=$proc.addresswidth}

Вариант 2 (не рекомендуется, т. к. тип объекта будет неправильным):

$obj = "" | Select-Object ComputerName,OSVersion,OSArchitecture,
           ProcArchitecture,Model,Manufacturer,BIOSSerial
$obj.ComputerName = $os.CSName
$obj.OSVersion = $os.version
$obj.OSArchitecture = $os.osarchitecture
$obj.ProcArchitecture = $proc.addresswidth
$obj.BIOSSerial = $bios.serialnumber
$obj.Model = $cs.model
$obj.Manufacturer = $cs.manufacturer

Вариант 3:

$obj = New-Object –TypeName PSObject
$obj | Add-Member NoteProperty ComputerName $os.CSName
$obj | Add-Member NoteProperty OSVersion $os.version
$obj | Add-Member NoteProperty OSArchitecture $os.osarchitecture
$obj | Add-Member NoteProperty ProcArchitecture $proc.addresswidth
$obj | Add-Member NoteProperty BIOSSerial $bios.serialnumber
$obj | Add-Member NoteProperty Model $cs.model
$obj | Add-Member NoteProperty Manufacturer $cs.manufacturer

или так:

$obj | Add-Member NoteProperty ComputerName $os.CSName –pass |
 Add-Member NoteProperty OSVersion $os.version –pass |
 Add-Member NoteProperty OSArchitecture $os.osarchitecture –Pass |
 Add-Member NoteProperty ProcArchitecture $proc.addresswidth –pass |
 Add-Member NoteProperty BIOSSerial $bios.serialnumber –pass |
 Add-Member NoteProperty Model $cs.model –pass |
 Add-Member NoteProperty Manufacturer $cs.manufacturer

Вариант 4 (для PS v3 или новее):

$obj = [pscustomobject]@{OSVersion=$os.version
           Model=$cs.model
           Manufacturer=$cs.manufacturer
           BIOSSerial=$bios.serialnumber
           ComputerName=$os.CSName
           OSArchitecture=$os.osarchitecture
           ProcArchitecture=$proc.addresswidth
          }

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

Вариант 5 — создать новый класс:

$source=@"
public class MyObject
{
  public string ComputerName {get; set;}
  public string Model {get; set;}
  public string Manufacturer {get; set;}
  public string BIOSSerial {get; set;}
  public string OSArchitecture {get; set;}
  public string OSVersion {get; set;}
  public string ProcArchitecture {get; set;}
}
"@
Add-Type -TypeDefinition $source -Language CSharpversion3
$os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost
$cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost
$bios = Get-WmiObject –Class Win32_BIOS –comp localhost
$proc = Get-WmiObject –Class Win32_Processor –comp localhost |
Select –First 1
$props = @{OSVersion=$os.version
           Model=$cs.model
           Manufacturer=$cs.manufacturer
           BIOSSerial=$bios.serialnumber
           ComputerName=$os.CSName
           OSArchitecture=$os.osarchitecture
           ProcArchitecture=$proc.addresswidth}
$obj = New-Object –TypeName MyObject –Property $props
Write-Output $obj

По быстродействию лучше всего варианты 4 и 1.

WMI (Windows Management Instrumentation) — это технология, с помощью которой можно получить и изменить достаточно широкий перечень параметров Windows.

Для примера мы хотим узнать информацию о процессоре. Мы можем использовать команду CMD sysinfo или Powershell Get-ComputerInfo, но увидеть только часть информации. С помощью WMI мы можем получить почти всю информацию.

Для получения всех классов WMI в Powershell мы можем использовать:

Get-WmiObject -List

Мы получим все классы для пространства имен rootcimv2 т.к. оно стоит по умолчанию. Если мы хотим использовать другое, то его нужно указать с ключом -Namespace.

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

Get-WmiObject -List -ComputerName CL1

Где:
-ComputerName — имя компьютера

WMI работает на 135 порту, а так же привилегированная учетная запись с правами на WMI и DCOM.

Либо у нас должен работать PSRemoting (тогда мы будем использовать Ivoke-Command). Весь процесс описан тут. 

Получение свойств класса через Powershell WMI

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

Get-WmiObject -List | where {$_.name -like "*BIOS*"}

 Если мы выведем свойства класса операционной системы, то не увидим названия:

Get-WmiObject -Class Win32_OperatingSystem

Получение класса WMI Powershell

Часть свойств можно получить и так:

[wmiclass]"Win32_OperatingSystem" | Get-Member

Для того что бы отобразить все свойства нужно выполнить:

Get-WmiObject -Class Win32_OperatingSystem | Select-Object -Property *

Получение всех свойств через WMI Powershell

Либо можно объявить результат в переменную:

$result = Get-WmiObject -Class Win32_OperatingSystem

Получить все значения переменной:

$result | Get-Member

Все значения WMI Powershell

И затем вызывать через переменную. Так я получу название:

$result.Caption

Поиск свойств в Powershell WMI

У нас два способа поиска нужных свойств. Первый через ключ -Filter:

Get-WmiObject -List | where {$_.Name -Like "*share*"}
Get-WmiObject -Class Win32_Share -Filter "Status = 'OK'"

Фильтрация свойств WMI Powershell

Но если мы напишем что-то не так, то увидим язык WQL (WMI Query Language):

Get-WmiObject : Invalid query «select * from Win32_Share where Status1 = ‘OK'»

Т.е. мы можем писать и запрос WQL:

Get-WmiObject -Query "SELECT * FROM Win32_share WHERE Status='OK'"

Вызов методов WMI через Powershell

Этот метод запустит Notepad.exe на удаленном компьютере AD. В $cred будут храниться учетные данные, если мы будем запускать процесс под другим пользователем.

$cred = Get-Credential
$process = Get-WmiObject -Query "SELECT * FROM Meta_Class WHERE __Class = 'Win32_Process'" `
-Namespace "rootcimv2" -Computername 'AD' -Credential $cred
$process.Create( "notepad.exe" )

Есть другой подход, с другой командой:

Invoke-WmiMethod -Path win32_process -Name create -ArgumentList notepad.exe

Отмечу, что вызвать процесс в графической оболочке нельзя, он будет запущен в бэкграунде. Связано это с тем, что Microsoft против что бы вторгались в интерактивный сеанс пользователя кому-либо (не моя цитата). Один из вариантов решения этого помещать задачи в планировщике.

Для того что бы увидеть остальные команды по работе с WMI в Powershell можно запустить:

Get-Command -Noun *WMI*

Что бы увидеть примеры использования или получить справку:

Get-help Invoke-WmiMethod -Examples

Теги:

#powershell

#wmi

Понравилась статья? Поделить с друзьями:
  • Запуск windows media player в полноэкранном режиме автоматически
  • Запуск windows installer в безопасном режиме windows 10
  • Запуск windows defender через командную строку
  • Запуск автоматического восстановления windows 10 при загрузке
  • Запуск windows 7 с флешки без установки торрент