Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Когда я начал изучать PowerShell, я изначально опирался на графический пользовательский интерфейс (GUI) для задач, которые казалось слишком сложными для простых команд PowerShell. По мере того как я продолжал учиться, я улучшал свои навыки и перешел от простых однострочных программ к созданию скриптов, функций и модулей. Важно помнить, что чувство перегруженности сложными примерами в интернете является нормальным. Никто не становится экспертом по PowerShell; мы все начинаем как новички.
Для тех, кто в основном использует графический интерфейс для административных задач, установите средства управления на административной рабочей станции для удаленного управления серверами. Независимо от того, используется ли на сервере GUI или установка Server Core OS, этот подход является полезным. Это практический способ ознакомиться с удаленным управлением серверами при подготовке к выполнению административных задач с помощью PowerShell.
Как и в предыдущих разделах, попробуйте использовать эти понятия в лабораторной среде.
Однострочник PowerShell представляет собой непрерывный конвейер. Это распространенное неправильное представление о том, что команда в одной физической строке является однострочной строкой PowerShell, но это не всегда верно.
Например, рассмотрим следующий пример: команда растягивается на несколько физических строк, но это однострочная команда PowerShell, так как она образует непрерывный конвейер. Для повышения удобочитаемости и ясности рекомендуется разбить длинную однострочную команду на символе pipe, который является естественным местом для разрыва в PowerShell. Это стратегическое использование разрывов линий улучшает удобочитаемость без нарушения потока конвейера.
Get-Service |
Where-Object CanPauseAndContinue -EQ $true |
Select-Object -Property *
Name : LanmanWorkstation
RequiredServices : {NSI, MRxSmb20, Bowser}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Workstation
DependentServices : {SessionEnv, Netlogon}
MachineName : .
ServiceName : LanmanWorkstation
ServicesDependedOn : {NSI, MRxSmb20, Bowser}
ServiceHandle :
Status : Running
ServiceType : Win32OwnProcess, Win32ShareProcess
StartType : Automatic
Site :
Container :
Name : Netlogon
RequiredServices : {LanmanWorkstation}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Netlogon
DependentServices : {}
MachineName : .
ServiceName : Netlogon
ServicesDependedOn : {LanmanWorkstation}
ServiceHandle :
Status : Running
ServiceType : Win32ShareProcess
StartType : Automatic
Site :
Container :
Name : vmicheartbeat
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Hyper-V Heartbeat Service
DependentServices : {}
MachineName : .
ServiceName : vmicheartbeat
ServicesDependedOn : {}
ServiceHandle :
Status : Running
ServiceType : Win32OwnProcess, Win32ShareProcess
StartType : Manual
Site :
Container :
Name : vmickvpexchange
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Hyper-V Data Exchange Service
DependentServices : {}
MachineName : .
ServiceName : vmickvpexchange
ServicesDependedOn : {}
ServiceHandle :
Status : Running
ServiceType : Win32OwnProcess, Win32ShareProcess
StartType : Manual
Site :
Container :
Name : vmicrdv
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Hyper-V Remote Desktop Virtualization Service
DependentServices : {}
MachineName : .
ServiceName : vmicrdv
ServicesDependedOn : {}
ServiceHandle :
Status : Running
ServiceType : Win32OwnProcess, Win32ShareProcess
StartType : Manual
Site :
Container :
Name : vmicshutdown
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Hyper-V Guest Shutdown Service
DependentServices : {}
MachineName : .
ServiceName : vmicshutdown
ServicesDependedOn : {}
ServiceHandle :
Status : Running
ServiceType : Win32OwnProcess, Win32ShareProcess
StartType : Manual
Site :
Container :
Name : vmicvss
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Hyper-V Volume Shadow Copy Requestor
DependentServices : {}
MachineName : .
ServiceName : vmicvss
ServicesDependedOn : {}
ServiceHandle :
Status : Running
ServiceType : Win32OwnProcess, Win32ShareProcess
StartType : Manual
Site :
Container :
Name : webthreatdefsvc
RequiredServices : {RpcSs, wtd}
CanPauseAndContinue : True
CanShutdown : True
CanStop : True
DisplayName : Web Threat Defense Service
DependentServices : {}
MachineName : .
ServiceName : webthreatdefsvc
ServicesDependedOn : {RpcSs, wtd}
ServiceHandle :
Status : Running
ServiceType : Win32OwnProcess, Win32ShareProcess
StartType : Manual
Site :
Container :
Name : webthreatdefusersvc_644de
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : True
CanStop : True
DisplayName : Web Threat Defense User Service_644de
DependentServices : {}
MachineName : .
ServiceName : webthreatdefusersvc_644de
ServicesDependedOn : {}
ServiceHandle :
Status : Running
ServiceType : 240
StartType : Automatic
Site :
Container :
Name : Winmgmt
RequiredServices : {RPCSS}
CanPauseAndContinue : True
CanShutdown : True
CanStop : True
DisplayName : Windows Management Instrumentation
DependentServices : {}
MachineName : .
ServiceName : Winmgmt
ServicesDependedOn : {RPCSS}
ServiceHandle :
Status : Running
ServiceType : Win32OwnProcess, Win32ShareProcess
StartType : Automatic
Site :
Container :
Естественные разрывы строк могут возникать при часто используемых символах, включая запятую (,
) и открывающиеся скобки ([
), скобки ({
), а также скобки ((
). Другие, которые не так распространены, включают точку с запятой (;
), знак равенства (=
), а также открытие одиночных и двойных кавычки ('
,"
).
Использование обратного апострофа (`
) или символа гравис для продолжения строки является спорным. Лучше всего избежать этого, если это возможно. Использование обратной кавычки после естественного символа разрыва строки является распространенной ошибкой. Эта избыточность не требуется и может загромождать код.
Команды в следующем примере выполняются правильно из консоли PowerShell. Однако попытка запустить их в области консоли интегрированной среды сценариев PowerShell (ISE) приводит к ошибке. В отличие от консоли PowerShell, панель консоли Интегрированной среды скриптов не предполагает автоматически продолжение команды на следующую строку. Чтобы предотвратить эту проблему, нажмите клавиши Shift +Enter в области консоли ISE вместо Enter, когда вам нужно разбить команду на несколько строк. Эта комбинация ключей сигнализирует isE о том, что команда продолжается в следующей строке, предотвращая выполнение, которое приводит к ошибкам.
Get-Service -Name w32time |
Select-Object -Property *
Name : w32time
RequiredServices : {}
CanPauseAndContinue : False
CanShutdown : True
CanStop : True
DisplayName : Windows Time
DependentServices : {}
MachineName : .
ServiceName : w32time
ServicesDependedOn : {}
ServiceHandle :
Status : Running
ServiceType : Win32OwnProcess, Win32ShareProcess
StartType : Manual
Site :
Container :
В следующем примере не является однострочным скриптом PowerShell, так как это не один непрерывный конвейер. Вместо этого это две отдельные команды, размещенные в одной строке, разделенные точкой с запятой. Эта точка с запятой указывает конец одной команды и начало другой.
$Service = 'w32time'; Get-Service -Name $Service
Status Name DisplayName
------ ---- -----------
Running w32time Windows Time
Для многих языков программирования и скриптов требуется точка с запятой в конце каждой строки. Однако в PowerShell точки с запятой в конце строк не нужны и не рекомендуются. Их следует избегать для более чистого и более читаемого кода.
В этой главе показано, как фильтровать результаты различных команд.
Рекомендуемой практикой в PowerShell является фильтрация результатов как можно раньше в конвейере. Это предполагает применение фильтров с помощью параметров в начальной команде, обычно в начале конвейера. Обычно этот процесс называется фильтрацией по левому.
Чтобы проиллюстрировать эту концепцию, рассмотрим следующий пример: используйте параметр Name из Get-Service
для фильтрации результатов на начальном этапе конвейера, возвращая только сведения о "службе времени Windows". Этот метод демонстрирует эффективное получение данных, обеспечивая возврат только необходимых и соответствующих сведений.
Get-Service -Name w32time
Status Name DisplayName
------ ---- -----------
Running w32time Windows Time
Обычно вы увидите в Интернете примеры передачи команды PowerShell в командлет Where-Object
для фильтрации результатов. Этот метод неэффективн, если более ранняя команда в конвейере имеет параметр для выполнения фильтрации.
Get-Service | Where-Object Name -EQ w32time
Status Name DisplayName
------ ---- -----------
Running W32Time Windows Time
Первый пример демонстрирует фильтрацию непосредственно в источнике, возвращая результаты специально для службы времени Windows. В отличие от этого, второй пример извлекает все службы, а затем использует другую команду для фильтрации результатов. Это может показаться незначительным в небольших сценариях, но рассмотрим ситуацию, связанную с большим набором данных, например Active Directory. Неэффективно получить сведения для тысяч учетных записей пользователей, чтобы сузить их до небольшого подмножества. Практика фильтрации на ранних этапах — применять фильтры как можно раньше в последовательности команд, даже в, казалось бы, тривиальных случаях. Эта привычка обеспечивает эффективность в более сложных сценариях, где она становится более важной.
Существует заблуждение, что порядок команд в PowerShell не имеет значения, но это ошибочное мнение. Последовательность, в которой вы упорядочиваете команды, особенно при фильтрации, важна. Например, предположим, что вы используете Select-Object
для выбора определенных свойств и Where-Object
для фильтрации. В этом случае необходимо сначала применить фильтрацию. В случае сбоя необходимые свойства могут быть недоступны в цепочке обработки для фильтрации, что приводит к неэффективным или ошибочным результатам.
В следующем примере не удается получить результаты, так как свойство CanPauseAndContinue отсутствует, когда Select-Object
передан в Where-Object
. Это связано с тем, что свойство CanPauseAndContinue не было включено в выбор, сделанный Select-Object
. Фактически это исключается или отфильтровывается.
Get-Service |
Select-Object -Property DisplayName, Running, Status |
Where-Object CanPauseAndContinue
Изменение порядка Select-Object
и Where-Object
приводит к желаемым результатам.
Get-Service |
Where-Object CanPauseAndContinue |
Select-Object -Property DisplayName, Status
DisplayName Status
----------- ------
Workstation Running
Netlogon Running
Hyper-V Heartbeat Service Running
Hyper-V Data Exchange Service Running
Hyper-V Remote Desktop Virtualization Service Running
Hyper-V Guest Shutdown Service Running
Hyper-V Volume Shadow Copy Requestor Running
Web Threat Defense Service Running
Web Threat Defense User Service_644de Running
Windows Management Instrumentation Running
Как показано во многих примерах в этой книге, вы часто можете использовать выходные данные одной команды в качестве входных данных для другой команды. В главе 3 Get-Member
использовалось для определения типа объекта, создаваемого командой.
Глава 3 также показала использование параметра ParameterTypeGet-Command
для определения того, какие команды приняли этот тип входных данных. В зависимости от того, насколько подробна помощь по команде, она может включать разделы INPUTS и OUTPUTS.
В разделе INPUTS указано, что можно передать ServiceController или объект String командлету Stop-Service
.
help Stop-Service -Full
Следующий результат сокращен, чтобы отобразить релевантную часть инструкции.
...
INPUTS
System.ServiceProcess.ServiceController
You can pipe a service object to this cmdlet.
System.String
You can pipe a string that contains the name of a service to this
cmdlet.
OUTPUTS
None
By default, this cmdlet returns no output.
System.ServiceProcess.ServiceController
When you use the PassThru parameter, this cmdlet returns a
ServiceController object representing the service.
...
Однако он не указывает, какие параметры принимают этот тип входных данных. Эту информацию можно узнать, проверив различные параметры в полной версии справки о командлете Stop-Service
.
help Stop-Service -Full
Снова в результатах ниже отображается только соответствующая справка. Обратите внимание, что параметр DisplayName не принимает входные данные конвейера. Параметр InputObject принимает данные из конвейера по значению для объектов ServiceController. Параметр Name принимает входные данные конвейера по значению для объектов String и входных данных конвейера по имени свойства.
...
-DisplayName <System.String[]>
Specifies the display names of the services to stop. Wildcard
characters are permitted.
Required? true
Position? named
Default value None
Accept pipeline input? False
Accept wildcard characters? true
-InputObject <System.ServiceProcess.ServiceController[]>
Specifies ServiceController objects that represent the services to
stop. Enter a variable that contains the objects, or type a command
or expression that gets the objects.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByValue)
Accept wildcard characters? false
-Name <System.String[]>
Specifies the service names of the services to stop. Wildcard
characters are permitted.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? true
...
При обработке входных данных конвейера, если параметр принимает данные как по имени свойства, так и по значению, сначала отдается предпочтение привязке по значению. Если этот метод терпит неудачу, он пытается обработать входные данные конвейера , используя имя свойства. Однако термин в значении может вводить в заблуждение. Более точное описание по типу— это
Например, если вы отправляете выходные данные команды, создающей объект ServiceController в Stop-Service
, эти выходные данные привязаны к параметру InputObject. Если команда, работающая через пайп, создает объект String, она связывает выходные данные с параметром Name. Если вы отправляете выходные данные из команды, которая не создает ServiceController или объект String, но включает свойство с именем Name, Stop-Service
привязывает значение свойства Name к его параметру Name.
Определите, какой тип выходных данных создаёт команда Get-Service
.
Get-Service -Name w32time | Get-Member
Get-Service
создает тип объекта ServiceController.
TypeName: System.ServiceProcess.ServiceController
Как показано в справке для командлета Stop-Service
, параметр InputObject принимает объекты ServiceController через конвейер по значению. Это означает, что при передаче выходных данных командлета Get-Service
в Stop-Service
, объекты ServiceController, созданные Get-Service
, привязываются к параметру InputObject командлета Stop-Service
.
Get-Service -Name w32time | Stop-Service
Теперь попробуйте использовать строковые входные данные. Соедините w32time
с Get-Member
, чтобы убедиться, что это строка.
'w32time' | Get-Member
TypeName: System.String
В документации по PowerShell показано, что при передаче строки через конвейер в Stop-Service
, эта строка привязывается к параметру Nameпо значению. Проведите практический тест, чтобы увидеть это в действии: перенаправьте символьную строку w32time
на Stop-Service
. В этом примере показано, как Stop-Service
обрабатывает строку w32time
в качестве имени службы для остановки. Выполните следующую команду, чтобы наблюдать за этой привязкой и выполнением команд в действии.
Обратите внимание, что w32time
заключён в одинарные кавычки. В PowerShell рекомендуется использовать одинарные кавычки для статических строк, резервируя двойные кавычки для ситуаций, когда строка содержит переменные, требующие расширения. Одинарные кавычки задают PowerShell обрабатывать содержимое буквально, без разбора переменных. Этот подход не только гарантирует точность в том, как скрипт интерпретирует строку, но и повышает производительность, так как PowerShell тратит меньше усилий по обработке строк в отдельных кавычках.
'w32time' | Stop-Service
Создайте пользовательский объект для тестирования входных данных конвейера по имени свойства для параметра NameStop-Service
.
$customObject = [pscustomobject]@{
Name = 'w32time'
}
Содержимое переменной CustomObject является объектом типа PSCustomObject и содержит свойство с именем Name.
$customObject | Get-Member
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Name NoteProperty string Name=w32time
При работе с переменными в PowerShell, например $customObject
в этом примере, важно использовать двойные кавычки, если необходимо заключить переменную в кавычки. Двойные кавычки позволяют расширить переменную. PowerShell оценивает переменную и использует его значение. Например, если заключить $customObject
в двойные кавычки и перенаправить его в Get-Member
, PowerShell обработает значение $customObject
. Напротив, использование одинарных кавычек приведет к передаче строкового литерала $customObject
и Get-Member
, а не значения переменной. Это различие важно для сценариев, в которых необходимо оценить значение переменных.
При отправке содержимого переменной $customObject
в командлет Stop-Service
привязка к параметру Name выполняется по имени свойства , а не по значению . Это связано с тем, что $customObject
— это объект, содержащий свойство с именем Имя. В этом сценарии PowerShell определяет свойство Name в $customObject
и использует его значение для параметра Name для Stop-Service
.
Создайте другой пользовательский объект с помощью другого имени свойства, например Service.
$customObject = [pscustomobject]@{
Service = 'w32time'
}
Ошибка возникает при попытке остановить службу w32time
, перенаправляя $customObject
в Stop-Service
. Привязка конвейера вызывает ошибку, так как $customObject
не создает объект ServiceController или String и не содержит свойство Name.
$customObject | Stop-Service
Stop-Service : Cannot find any service with service name
'@{Service=w32time}'.
At line:1 char:17
+ $customObject | Stop-Service
+ ~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (@{Service=w32time}:String) [
Stop-Service], ServiceCommandException
+ FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShe
ll.Commands.StopServiceCommand
Если имена выходных свойств одной команды не соответствуют требованиям к входным данным конвейера другой команды, можно использовать Select-Object
для переименования имен свойств, чтобы они правильно выстроились.
В следующем примере используйте Select-Object
для переименования свойства Service в свойство с именем Name.
На первый взгляд синтаксис этого примера может показаться сложным. Однако важно понимать, что для изучения синтаксиса требуется больше, чем копирование и вставка кода. Вместо этого потребуется время, чтобы ввести код вручную. Эта практическая практика помогает запоминать синтаксис, и он становится более интуитивно понятным при повторяющихся усилиях. Использование нескольких мониторов или разбиения экрана также может помочь в процессе обучения. Отображение примера кода на одном экране при активном вводе и эксперименте с ним на другом. Эта настройка облегчает следование за материалом и улучшает ваше понимание и запоминание синтаксиса.
$customObject |
Select-Object -Property @{Name='Name';Expression={$_.Service}} |
Stop-Service
Существуют случаи, в которых может потребоваться использовать параметр, который не принимает входные данные конвейера. В таких случаях вы по-прежнему можете использовать выходные данные одной команды в качестве входных данных для другого. Во-первых, захват и сохранение отображаемых имен нескольких определенных служб Windows в текстовый файл. Этот шаг позволяет использовать сохраненные данные в качестве входных данных для другой команды.
'Background Intelligent Transfer Service', 'Windows Time' |
Out-File -FilePath $env:TEMP\services.txt
Скобки можно использовать для передачи выходных данных одной команды в качестве входных данных для параметра другой команде.
Stop-Service -DisplayName (Get-Content -Path $env:TEMP\services.txt)
Эта концепция похожа на порядок операций в Алгебре. Так же, как математические операции в скобках вычисляются сначала, команда, заключенная в скобки, выполняется перед внешней командой.
PowerShellGet, модуль, включенный в PowerShell версии 5.0 и выше, предоставляет команды для обнаружения, установки, обновления и публикации модулей PowerShell и других элементов в репозитории NuGet. Для тех, кто использует PowerShell версии 3.0 и выше, PowerShellGet также доступен как отдельная загрузка.
Галерея PowerShell — это веб-репозиторий, размещённый в корпорации Майкрософт, разработанный как централизованная платформа для обмена модулями PowerShell, скриптами и другими ресурсами. Хотя корпорация Майкрософт размещает коллекцию PowerShell, сообщество PowerShell вносит большую часть доступных модулей и сценариев. Учитывая источник этих модулей и скриптов, обратите внимание, прежде чем интегрировать любой код из коллекции PowerShell в среду. Просмотрите и проверьте скачиваемые файлы из коллекции PowerShell в изолированной тестовой среде. Этот процесс гарантирует, что код является безопасным и надежным, работает должным образом и защищает вашу среду от потенциальных проблем или уязвимостей, возникающих из невидимого кода.
Многие организации предпочитают устанавливать собственный внутренний частный репозиторий NuGet. Этот репозиторий служит двойной целью. Во-первых, он выступает в качестве безопасного расположения для хранения модулей, разработанных в собственной среде, предназначенных исключительно для внутреннего использования. Во-вторых, он предоставляет проверенную коллекцию модулей, поступающих из внешних источников, включая общедоступные репозитории. Компании обычно проводят тщательную проверку перед добавлением этих внешних модулей в внутренний репозиторий. Этот процесс важен для обеспечения того, чтобы модули были свободны от вредоносного содержимого и соответствуют стандартам безопасности и эксплуатации компании.
Используйте командлет Find-Module
, который является частью модуля PowerShellGet, чтобы найти модуль в галерее PowerShell, написанный мной и называющийся MrToolkit.
Find-Module -Name MrToolkit
NuGet provider is required to continue
PowerShellGet requires NuGet provider version '2.8.5.201' or newer to
interact with NuGet-based repositories. The NuGet provider must be available
in 'C:\Program Files\PackageManagement\ProviderAssemblies' or
'C:\Users\mikefrobbins\AppData\Local\PackageManagement\ProviderAssemblies'.
You can also install the NuGet provider by running 'Install-PackageProvider
-Name NuGet -MinimumVersion 2.8.5.201 -Force'. Do you want PowerShellGet to
install and import the NuGet provider now?
[Y] Yes [N] No [S] Suspend [?] Help (default is "Y"):
Version Name Repository Description
------- ---- ---------- -----------
1.3 MrToolkit PSGallery Misc PowerShell Tools
При первом использовании одной из команд из модуля PowerShellGet появится запрос на установку поставщика NuGet.
Чтобы установить модуль MrToolkit, передайте предыдущую команду в Install-Module
.
Find-Module -Name MrToolkit | Install-Module -Scope CurrentUser
Untrusted repository
You are installing the modules from an untrusted repository. If you trust
this repository, change its InstallationPolicy value by running the
Set-PSRepository cmdlet. Are you sure you want to install the modules from
'https://www.powershellgallery.com/api/v2'?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "N"):y
Так как коллекция PowerShell является ненадежным репозиторием, вам будет предложено утвердить установку модуля.
Модуль MrToolkit включает функцию с именем Get-MrPipelineInput
. Этот командлет предназначен для предоставления пользователям удобного метода для идентификации параметров команд, способных принимать входные данные из конвейера. В частности, он показывает три ключевых аспекта:
- Какие параметры команды могут принимать входные данные из конвейера
- Тип объекта, который принимает каждый параметр
- Принимают ли они входные данные конвейера по значению или по имени свойства
Эта возможность значительно упрощает процесс понимания и использования возможностей конвейера команд PowerShell.
Сведения, полученные ранее путем анализа справочной документации, могут быть определены этой функцией.
Get-MrPipelineInput -Name Stop-Service | Format-List
ParameterName : InputObject
ParameterType : System.ServiceProcess.ServiceController[]
ValueFromPipeline : True
ValueFromPipelineByPropertyName : False
ParameterName : Name
ParameterType : System.String[]
ValueFromPipeline : True
ValueFromPipelineByPropertyName : True
В этой главе вы узнали о тонкостях однострочных команд PowerShell. Вы также узнали, что количество физических строк команды не имеет значения для ее классификации как однострочной команды PowerShell. Кроме того, вы узнали о ключевых понятиях, таких как фильтрация слева, конвейер и PowerShellGet.
- Что такое однострочник PowerShell?
- Каковы некоторые символы, в которых могут возникать естественные разрывы строк в PowerShell?
- Почему следует фильтровать влево?
- Каковы два способа, которым команда PowerShell может принимать входные данные конвейера?
- Почему вы не должны доверять командам, найденным в галерее PowerShell?
- about_Pipelines
- о_Синтаксисе_Команд
- о_Параметрах
- PowerShellGet: большой простой способ обнаружения, установки и обновления модулей PowerShell
В следующей главе вы узнаете о форматировании, псевдонимах, поставщиках и операторах сравнения.
Отзыв о PowerShell
PowerShell — это проект с открытым исходным кодом. Выберите ссылку, чтобы оставить отзыв: