Глава 4. Выполнение команд

Когда вы начинаете искать в Интернете примеры PowerShell, это запросто представит вам впечатление, что PowerShell как некую разновидность основанного на .NET составления сценариев или языка программирования. Наши последователи, получившие признание Microsoft MVP (most valuable professional, наиболее ценный профессионал) и сотни прочих пользователей PowerShell это достаточно серьёзные гики, которым нравится копаться в своей оболочке чтобы выяснить что с ней можно сделать. Но почти все мы начинали именно с того, с чего начинается данная глава: с запуска команд. Именно этим вы и будете заниматься в данной главе: не писать сценарии, не программировать, а запускать команды и утилиты командной строки.

Давайте общаться безопасно

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

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

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

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

Политика выполнения

Самая первая включаемая PowerShell мера безопасности это политика исполнения (execution policy). Эта настройка для всей машины управляет теми сценариями, которые будет исполнять PowerShell. По умолчанию в Windows 10 установлено Restricted (Ограничено). В Windows Server установкой по умолчанию выступает RemotedSigned, а политика исполнения в устройствах, отличных от Windows не применяется. Настройка Restricted в устройствах Windows запрещает вовсе исполнение сценариев. И это верно: по умолчанию вы можете применять PowerShell для интерактивного запуска команд, но вы не можете применять его для исполнения сценариев. Давайте представим себе, что вы выгрузили некий сценарий из Интернета. Когда вы попробуете его исполнить, вы получите следующее сообщение об ошибке:


File C:\Scripts\Get-DiskInventory.ps1 cannot be loaded because the execution 
➥ of scripts is disabled on this system. Please see "get-help about_signing"
➥ for more details.
		

Просмотрим текущую политику выполнения запустив Get-ExecutionPolicy. Вы можете изменить имеющуюся политику исполнения одним из трёх способов:

  • Исполняя команду Set-ExecutionPolicy - Она изменяет имеющиеся настройки в части HKEY_LOCAL_MACHINE Реестра Windows и обычно должна запускаться Администратором, поскольку обычные пользователи не обладают правами на запись в эту часть Реестра.

  • Применяя Group Policy Object (GPO) - Начиная с Windows Server 2008 R2, включена поддержка относящихся к PowerShell настроек. Показанные на Рисунке 4.1 настройки PowerShell расположены в Computer Configuration > Policies > Administrative Templates > Windows Components > Windows PowerShell. Рисунок 4.2 отображает включёнными эту настройку. При установке через GPO настраиваемые в Групповой политике настройки перекрывают имеющиеся локальные настройки. По существу, вы пытаетесь исполнить Set-ExecutionPolicy, это сработает, однако предупредительное сообщение скажет вам, что ваша новая настройка не вступила в действие по причине перекрытия Групповой политикой.

     

    Рисунок 4-1


    Поиск настроек PowerShell Windows в Объекте Групповой политики

     

    Рисунок 4-2


    Изменение политики исполнения PowerShell Windows в Объекте Групповой политики

  • Вручную, исполняя PowerShell.exe и применяя переключатель командной строки -ExecutionPolicy - При исполнении подобным образом предписанная политика исполнения перекрывает любые локальные настойки , а также определённые Групповой политикой установки. Что можно наблюдать на Рисунке 4.1.

Вы можете установить значение политики исполнения в одну из пяти настроек (обращаем внимание на то, что Объект Групповой политики предоставляет доступ лишь к средним трём из следующего списка):

  • Restricted - Это значение по умолчанию и сценарии не выполняются. Исключениями выступают лишь несколько поддерживаемых Microsoft сценариев, которые настраивают настройки конфигурации PowerShell по умолчанию. Эти сценарии подписаны цифровой подписью Microsoft и при изменении не будут выполняться.

  • AllSigned - PowerShell будет выполнять любой обладающий цифровой подписью сценарий, применяя сертификат подписи кода, выпущенный любым доверенным Центром авторизации (CA, certification authority).

  • RemoteSigned - PowerShell будет исполнять все локальные сценарии и выполнит удалённые сценарии когда они подписаны цифровым образом с применением сертификата цифровой подписи, выпущенного доверенным CA. Удалённые сценарии это расположенные в неком удалённом компьютере, доступ к которому обычно выполняется через путь UNC (Universal Naming Convention, имя, соответствующее соглашению об универсальном назначении имён). Помеченные как поступившие через Интернет сценарии также рассматриваются удалёнными. Все браузеры, Edge, Chrome, Firefox и Outlook помечают выгружаемое как поступающее через Интернет.

  • Unrestricted - Будут исполняться все сценарии.

  • Bypass - Это особая настройка служит для применения разработчиками, которые встроили PowerShell внутри своего приложения. Данная установка обходит настроенную политику выполнения и должна применяться только в случае когда размещённое приложение предоставляет свой собственный уровень безопасности приложения. Фактически, вы говорите PowerShell: "Не беспокойся, я под защитой безопасности".

[Предостережение]Постойте, что?

Вы обратили внимание на то, что можно установить политику исполнения в неком Объекте Групповой политики, а также переопределить её при помощи параметра PowerShell.exe? Что хорошего в контролируемой GPO настройке, которую запросто могут переопределять люди? Это подчёркивает тот факт, что политика исполнения предназначена для защиты лишь от неосведомлённых пользователей для непреднамеренного запуска анонимных сценариев.

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

На практике, обладающий познаниями разработчик вредоносного программного обеспечения запросто способен получать прямой доступ к функциям .NET Framework, причём не применяя PowerShell в качестве посредника. Или, иначе говоря, когда пользователь без авторизации обладает правами администратора в вашем компьютере и способен запускать произвольный код, у вас уже имеются проблемы.

Если вы желаете запускать сценарии и вы хотите применять их только в тех компьютерах, в которых должны исполняться сценарии, Microsoft рекомендует вам пользоваться RemoteSigned. В соответствии с Microsoft, все прочие компьютеры должны оставаться с Restricted. Они говорят, что RemoteSigned предоставляет достойный баланс между безопасностью и удобством. AllSigned более строго, но требует от всех ваших сценариев необходимости наличия цифровой подписи. Сообщество PowerShell в целом разделено и обладает разными соображениями о том что такое надлежащая политика исполнения. На данный момент мы будем применять рекомендацию Microsoft и предложим вам самостоятельно изучить данный вопрос.

[Замечание]Замечание

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

Не создания сценария, а исполнение команд

Как подразумевает его название, PowerShell это оболочка. Прочие оболочки, которые вы вероятно применяли или, по крайней мере, слышали про них, это cmd.exe, Bash, Zsh, fish и ksh. PowerShell это не только оболочка, но и язык программирования сценариев - однако не тем способом, который являют собой JavaScript или Python.

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

В конечном счёте, когда вы пробуете набирать одни и те же команды (с их параметрами) снова и снова, вы скопируете их и поместите в текстовый файл. Присвойте этому файлу расширение файлового имени .ps1, и вы несомненно получаете сценарий PowerShell. Теперь, вместо набора команд снова и снова вы запускаете такой сценарий, а он исполняет все имеющиеся внутри команды. Обычно это гораздо проще чем писать некую программу на полностью функциональном языке программирования. По существу, это тот шаблон, который годами применяется администраторами UNIX. Распространённые оболочки UNIX/Linux, например Bash, обладают аналогичным подходом: исполняют команды пока вы не убедитесь в их правильности, а затем вставляют их в текстовый файл и именуют его сценарием.

Не поймите нас неверно: при помощи PowerShell вы можете сделать всё настолько сложным, насколько это вам требуется. Он пользуется теми же шаблонами применения, что и Python и прочие языки программирования или сценариев. PowerShell предоставляет вам доступ ко всей базовой мощности .NET Core и мы наблюдали "сценарии" PowerShell, которые практически неотличимы от написанной в Visual Studio программы на C#. PowerShell поддерживает такие разнообразные шаблоны применения, поскольку он предназначен для широкого круга пользователей. Основной момент состоит в том, что вам нет нужды применять его на таком уровне лишь по той причине, что он поддерживает данный уровень сложности, и это вовсе не означает, что при меньшей сложности вы не способны быть чрезвычайно действенным.

Вот некая аналогия. Наверное, вы водите машину. Если вы похожи на нас, замена масла - это самая сложная задача механика, которую вы когда либо выполняли в своём автомобиле. Мы вовсе не авто гики и не способны перебрать двигатель. Также мы не можем выполнять крутые J - развороты, которые вы наблюдаете в кино. Вы никогда не увидите в автомобильной рекламе нас за рулём автомобиля на закрытой трассе. Однако тот факт что мы не экстремальные каскадёры, не мешает нам быть чрезвычайно эффективными водителями на менее сложном уровне. Возможно, когда- нибудь мы решим заняться в качестве хобби трюковым вождением (наши страховые компании будут в восторге), и на этот момент нам придётся узнать немного больше о том, как работают наши автомобили, освоить некие новые навыки и тому подобное. У нас всегда имеется возможность роста. Однако на данный момент мы счастливы тем, что мы способны выполнять роль обычного водителя.

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

Анатомия команд

Рисунок 4.3 показывает основную анатомию сложной команды PowerShell. Мы называем её полной формой синтаксиса команды. Мы отображаем здесь некую сложную команду, а потому вы можете наблюдать все те моменты, которые могут появляться.

 

Рисунок 4-3


Анатомия команды PowerShell

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

  • Названием командлета выступает Get-Command. Командлеты PowerShell всегда имеют такой формат именования глагол - существительное. В своём следующем разделе мы подробнее поясним командлеты.

  • Самым первым именем параметра является -Verb и ему придаётся значение -Verb. Поскольку это значение не содержит никаких пробелов и символов пунктуации, его нет нужды заключать в кавычки.

  • Вторым именем параметра выступает -Module и он снабжается двумя значениями: PSReadLine и PowerShellGet. Это разделяемый запятыми список, а поскольку никакое из значений не содержит пробелов и символов пунктуации, ни одно из значений не требует заключения в кавычки.

  • Наш заключительный параметр, -Syntax это параметр переключателя. Это означает, что он не получает значения; достаточно описание самого параметра.

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

  • Названия параметров всегда начинаются с тире (-).

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

  • Между предшествующим названию параметра тире (-) и самим названием параметра нет никаких пробелов.

  • Здесь ничто не чувствительно к регистру.

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

Соглашение об именовании командлетов

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

  • Командлет это естественная утилита командной строки PowerShell. Она присутствует исключительно внутри PowerShell и написана на языке .NET Core, например, на C#. Мир cmdlet уникален для PowerShell, поэтому когда вы добавляете его к своим ключевым словам для поиска в предпочитаемой вами поисковой системе, получаемые вами результаты, в целом, будут относиться к PowerShell. Это слово произносится как command-let.

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

  • Некое приложение является внешним исполняемым файлом, состоящее из утилит командной строки, таких как ping и ipconfig.

  • Команда это обобщающий термин, который мы применяем как ссылку на все предыдущие термины.

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

Основное правило таково: Имена начинаются с некого стандартного глагола, такого как Get, или Set, или New, или Pause. Вы можете исполнить Get-Verb чтобы увидеть список допустимых глаголов (вы обнаружите около сотни, хотя только примерно дюжина является распространёнными). После глагола следует тире, за которым идёт отдельное существительное, такое как Job, либо Process, либо Item. Разработчики могут создавать свои собственные, поэтому для отображения их всех нет никакого командлета Get-Noun.

Что такого особенного в данном правиле. Ну, допустим, мы сказали вам, что имеются командлеты Start-Job, Get-Job, Get-Process, Stop-Process и так далее. Способны ли вы догадаться какая из команд запустит новый процесс в вашем компьютере? Можете ли вы угадать какая команда внесёт изменения в Виртуальную Машину Azure (VM)? Если вы угадали об Stop-Process, вы верно поняли первый случай. Если вы догадались до Set-VM, вы оказались близки: это Set-AzVM и вы найдёте команду для Виртуальных Машин Azure в модуле Az.Compute (модули мы обсудим с Главе 7). Все команды Azure пользуются префиксом Az, за которым следует то существительное, с которым путается эта команда. Дело в том, что обладая таким последовательным соглашением о названиях с ограниченным набором глаголов, вы способны догадываться об их именах, а затем можете применять Help или Get-Command совместно с символами подстановки чтобы убедиться в своей догадке. Вам становится проще разбираться с названиями необходимых вам команд без необходимости всякий раз запускать Google или Bing.

[Замечание]Замечание

Не все из так называемых глаголов в действительности являются глаголами. Хотя официально Microsoft и применяет термин соглашение об именовании глагол- существительное, вы встречаетесь с такими "глаголами" как New, Where и тому подобными. Вам придётся смириться с этим.

Псевдонимы: клички для команд

Хотя имена команд PowerShell могут быть хорошими и согласованными, они также могут оказываться длинными. Такое название команды как Remove-AzStorageTableStoredAccessPolicy слишком велики для набора, даже для завершения табуляцией. Хотя это название команды ясное - взглянув на него вы, скорее всего, догадаетесь что она делает - его ужасно набирать.

Именно здесь на помощи приходят псевдонимы PowerShell. Некий псевдоним это ничто иное как кличка для команды. Пытаетесь набрать Get-Process? Попробуйте это:


PS /Users/james> Get-Alias -Definition "Get-Process"
Capability      Name
----------      ----
Cmdlet          gps -> Get-Process
		

Теперь вы знаете что gps это псевдоним для Get-Process.

При применении некого псевдонима, его команда работает точно так же. Параметры те же самые; всё в точности такое же - только короче само название команды.

Когда вы смотрите на некий псевдоним (парни из Интернета, как правило, пользуются ими, как будто мы все запомнили сотни встроенных псевдонимов) и не способны понять что он собой представляет, обратитесь за подсказкой:


PS /Users/james> help gps
NAME
    Get-Process
SYNOPSIS
    Gets the processes that are running on the local computer.
SYNTAX
    Get-Process [[-Name] <String[]>] [-FileVersionInfo] [-Module]
    [<CommonParameters>]
    Get-Process [-FileVersionInfo] -Id <Int32[]> [-Module] 
    [<CommonParameters>]
    Get-Process [-FileVersionInfo] -InputObject <Process[]> [-Module] 
    [<CommonParameters>]
    Get-Process -Id <Int32[]> -IncludeUserName [<CommonParameters>]
    Get-Process [[-Name] <String[]>] -IncludeUserName [<CommonParameters>]
    Get-Process -IncludeUserName -InputObject <Process[]>
  ➥ [<CommonParameters>]
		

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

[Замечание]Дополнительно

Вы можете создавать свои собственные псевдонимы при помощи New-Alias, экспортировать список псевдонимов применяя Export-Alias, или даже импортировать ранее созданные псевдонимы воспользовавшись Import-Alias. При создании псевдонима он продолжает существование пока имеется ваш текущий сеанс оболочки. Как только вы закрываете её окно, он пропадает. Именно поэтому вы можете пожелать их экспорт с тем, чтобы применять их в прочих сеансах PowerShell.

Мы стараемся избегать создания и применения персональных псевдонимов, потому как они не доступны для всех, а лишь для тех, кто их сделал. Когда кто- то начнёт искать что делает xtd, мы создадим путаницу и несогласованность.

И xtd не делает ничего. Это поддельный псевдоним, созданный нами.

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

Применение ярлыков

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

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

Усечение имён параметров

PowerShell не принуждает вас набирать имена параметров целиком. Как вы можете вспомнить из Главы 3, вместо набора -ComputerName, к примеру, вы можете обойтись -comp. Основное правило состоит в том, что вам придётся набрать достаточно для необходимого названия чтобы PowerShell был способен отличить его. Когда имеются параметр -ComputerName, параметр -Common и параметр -Composite, вам придётся набирать, по крайней мере, -compu, -comm и -compo, потому как именно это минимальное число букв, необходимое для уникальной идентификации каждого.

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

Применение псевдонимов имён параметров

Параметры также способны обладать своими собственными псевдонимами, хотя их и будет чрезвычайно сложно обнаружить, поскольку они не отображаются в файлах подсказок или ещё в чём- то подходящем. Например, команда Get-Process обладает параметром -ErrorAction. Для обнаружения его псевдонима вы исполняете такую команду:


PS /Users/james> (get-command get-process | select -Expand 
➥ parameters).erroraction.aliases
		

Мы выделили жирно имена команды и параметра; заменяйте их теми командой и параметром, которыми интересуетесь. В данном случае наш вывод раскроет что псевдонимом для -ErrorAction выступает -ea, а потому вы можете выполнить следующее:


PS /Users/james> Get-Process -ea Stop
		

Заполнение Tab отобразит вам значение псевдонима -ea; когда вы наберёте Get-Process -e и начнёте нажимать Tab, он отобразится. Однако в подсказке по этой команде -ea не отображается вовсе, а заполнение табуляцией не отражает того, что -ea и -ErrorAction это одно и то же.

[Замечание]Замечание

Именно это носит название общих параметров. Чтобы ознакомиться с ними дополнительно, вы можете запустить Get-Help about_CommonParamaters .

Применение позиционных параметров

При просмотре синтаксиса команды в файле подсказки вы запросто можете выделять позиционные параметры:


SYNTAX
    Get-ChildItem [[-Path] <string[]>] [[-Filter] <string>] [-Include 
  ➥ <string[]>] [-Exclude <string[]>] [-Recurse] [-De
    pth <uint>] [-Force] [-Name] [-Attributes {ReadOnly | Hidden | System | 
  ➥ Directory | Archive | Device | Normal | Tem
    porary | SparseFile | ReparsePoint | Compressed | Offline | 
  ➥ NotContentIndexed | Encrypted | IntegrityStream | NoScr
    ubData}] [-FollowSymlink] [-Directory] [-File] [-Hidden] [-ReadOnly] 
[-System] [<CommonParameters>]
 	   

Здесь оба, и -Path, и -Filter позиционные, и вы знаете об этом, поскольку соответствующее название параметра и принимаемый им ввод содержатся внутри квадратных скобок. Более ясное пояснение доступно в полной подсказке (в данном случае, help Get-ChildItem -Full), что выглядит следующим образом:


-Path <String[]>
    Specifies a path to one or more locations. Wildcards are
    permitted. The default location is the current directory (.).
    Required?                    false
    Position?                    0
    Default value                Current directory
    Accept pipeline input?       true (ByValue, ByPropertyName)
    Accept wildcard characters?  True
 	   

Это ясно указывает что наш параметр -Path находится в положении 0, что означает что он является самым первым параметром после своего командлета. Для позиционных параметров вам не требуется набирать значение имени параметра; вы можете предоставлять его значение в верном месте. Например:


PS /Users/james> Get-ChildItem /Users
    Directory: /Users
Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         3/27/2016  11:20 AM            james
d-r--         2/18/2016   2:06 AM            Shared
		

Это в точности то же что и:


PS /Users/james> Get-ChildItem -Path /Users
    Directory: /Users
Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d-----         3/27/2019  11:20 AM            james
d-----         2/18/2019   2:06 AM            Shared
		

Основная проблема с позиционными параметрами состоит в том, что именно на вас лежит ответственность в запоминании того что за чем следует. Вначале вам надлежит набирать все позиционные параметры, причём в верном порядке, прежде чем вы получаете возможность добавлять параметры с названиями (не позиционные). Если вы смешаете порядок параметров ваша команда завершится неудачей. Для простых команд, таких как Dir, которой вы, скорее всего, пользуетесь годами, ввод -Path представляется странным, и почти никто так не поступает. Но для более сложных команд, которые могут обладать тремя или четырьмя позиционными параметрами подряд, может оказаться сложным запоминать что за чем следует.

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


PS /Users/james> move file.txt /Users/james/
		

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


PS /Users/james> move-item -Path /tmp/file.txt -Destination /Users/james/
		

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


PS /Users/james> move -Destination /Users/james/ -Path /tmp/file.txt
		

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

Поддержка внешних команд

До сих пор все те команды, которые вы запускали в своей оболочке (по крайней мере те, которые мы предлагали вам исполнять), были встроенными командлетами. В вашей машине Windows поставляются встроенными в PowerShell около 2900 командлетов и около 200 в ваших машинах Linux или macOS. Вы можете добавлять ещё - такие продукты как Azure PowerShell, AWS PowerShell и SQL Server все они поступают с добавлениями, которые содержат сотни дополнительных командлетов.

Однако вы не ограничены командлетами PowerShell. Вы также можете применять те же самые утилиты командной строки, которые вы, вероятно, применяли годами, в том числе ping, nslookup, ifconfig или ipconfig и тому подобные. Поскольку они не являются естественными командлетами PowerShell, вы пользуетесь ими в точности также как и всегда. Пройдите далее и воспользуйтесь прямо сейчас несколькими любимцами.

Та же самая история и с операционными системами не- Windows. Вы можете применять grep, bash, sed, awk, ping, и все прочие имеющиеся инструменты командной строки, которые только есть у вас. Они будут работать как обычно и PowerShell будет отображать их результаты точно также как это делала ваша старая оболочка (например, Bash).

[Совет]Попробуйте прямо сейчас

Попробуйте исполнить какие- нибудь внешние утилиты командной строки, которыми вы пользовались ранее. Они работают также? Не падают ли какие- нибудь из них?

Данный раздел иллюстрирует важный урок: при помощи PowerShell Microsoft (возможно, впервые) не говорит: "Вам придётся изучать всё с самого начала". Вместо этого Microsoft произносит: "Если вы уже знаете как что- то выполнять, продолжайте делать это так же. Мы попробуем снабдить вас лучшими и более совершенными инструментами чтобы двигаться далее, однако всё что вы уже знаете, будет продолжать работать".

В некоторых экземплярах Microsoft предоставил лучшие инструменты чем уже имевшиеся, боле старые. Например, внутренний командлет Test-Connection предоставляет дополнительные возможности и более гибкий вывод нежели старая внешняя команда ping. Однако если вы знаете как пользоваться ping и она решает всё что вам требуется, переходите непосредственно к её применению. Она будет прекрасно работать внутри PowerShell.

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

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


$exe = "func"
$action = "new"
$language = "powershell"
$template = "HttpTrigger"
$name = "myFunc"
& $exe $action -l $language -t $template -n $name
 	   

Здесь предполагается, что у вас имеется некая внешняя команда с названием func. (Это утилита командной строки из реальной практики, которая применяется для взаимодействия с функциями Azure.) Если вы никогда не пользовались ею или у вас нет её, отлично; большинство утилит командной строки старой школы работают точно так же, поэтому это хороший пример для изучения. Она принимает ряд параметров:

  • "new" здесь это вариант того действия, которое вы хотите предпринять, а -new, init, start и logs это возможные варианты.

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

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

  • -n это название самой функции.

Всё что мы выполнили, это поместили все свои различные элементы - значение пути и названия исполняемого файла, а также все значения параметров - в заполнители, которые начинаются с символа $. Это заставляет PowerShell рассматривать данные значения как отдельные элементы и не пытаться выполнять их анализ чтобы определить содержат ли они команды или специальные символы. Затем мы применили оператор вызова (&), передав ему название исполняемого файла, все параметры и значения параметров. Данный шаблон будет работать практически для любой утилиты командной строки, которая испытывает неудобства при запуске из PowerShell.

Звучит сложно? Ладно, имеются и хорошие новости: в PowerShell v3 и далее вам нет нужды так возиться. Просто добавьте два тире и символ процента перед чем бы то ни было, и PowerShell даже не будет пытаться выполнять синтаксический анализ этого; он просто передаст это непосредственно в применяемую вами утилиту командной строки. Чтобы окончательно прояснить, это означает, что вы не будете иметь возможности передавать в качестве значений параметров переменные.

Вот простой пример того что завершается отказом:


PS /Users/james> $name = "MyFunctionApp"
PS /Users/james> func azure functionapp list-functions --% $name
 
Can't find app with name "$name"
		

Мы пытаемся запустить утилиту func командной строки для перечисления всех наших функций Azure со значением названия "MyFunctionApp", однако если мы в явном виде постулируем что мы хотим, PowerShell передаст все эти параметры в лежащую в основе команду без попытки проделать что бы то ни было с ней:


PS /Users/james> func new -t HttpTrigger -n --% "MyFunc"
Select a template: HttpTrigger
Function name: [HttpTrigger] Writing /Users/tyler/MyFuncApp/MyFunc/run.ps1
Writing /Users/tyler/MyFuncApp/MyFunc/function.json
The function "MyFunc" was created successfully from the "HttpTrigger" 
➥ template.
PS /Users/james>
		

К счастью, это не то, к чему вам приходится прибегать часто.

Работа с ошибками

Когда вы приступите к работе с PowerShell, вы неизбежно встретитесь с уродливым красным текстом, а возможно и время от времени даже после того как вы станете опытным пользователем оболочки. Это случается со всеми нами. Но не позволяйте этому красному тексту давить на вас. (Лично нас это возвращает к школьным урокам английского и плохо написанным сочинениям, так что давление - это мягко сказано.)

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

 

Рисунок 4-4


Интерпретация сообщения об ошибке PowerShell

С большинством ошибок просто разобраться. На Рисунке 4.4, прямо в самом начале говорится, "Вы набрали get и я понятия не имею что это означает". Это обусловлено тем что мы неверно набрали название необходимой команды: предполагалось, что это будет Get-Command, а не Get Command. Упс. А что насчёт Рисунка 4.5?

 

Рисунок 4-5


Что за "фрагмент второго пути"?

Получаемое сообщение на Рисунке 4.5, "Фрагмент второго пути не должен быть именем устройства или UNC", сбивает с толку. Что за второй путь? мы не набирали второй путь. Мы набирали один путь, C:\Users\James, а также параметр командной строки, \s, не так ли?

Ну, нет. Один из простейших способов решения такой проблемы - прочесть подсказку и набрать команду полостью. Если бы мы набрали Get-ChildItem -Path C:\Users\James, мы бы осознали, что \s это неверный синтаксис. Мы подразумевали -Recurse. Порой сообщение об ошибке может казаться бесполезным и, если кажется, что вы и PowerShell разговариваете на различных языках, то это так и есть. PowerShell, очевидно, не собирается изменять свой язык, поэтому, скорее всего, ошибаетесь вы, и обращение к подсказке с указанием целиком команды, параметров и всего прочего зачастую является самым быстрым способом решения проблемы.

Общие моменты путаницы

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

Набор имён командлетов

Прежде всего необходимо вводить названия командлетов. Это всегда глагол- существительное, как Get-Content. Все эти варианты, как мы обнаружим, пробуют новички, но они не работают:

  • Get Content

  • GetContent

  • Get=Content

  • Get_Content

Часть проблем обусловлена опечатками (например, = вместо -), а часть от лени произношения. Все мы произносим команду как Get Content, устно пропуская тире. Однако вам необходимо набирать тире.

Набор параметров

Параметры также пишутся сообразно. Такие параметры как -Recurse, получают тире перед своим названием. Когда некий параметр обладает значением, между самим параметром и его значением поставляется пробел. Вам необходимо обладать разделительными пробелами для названия командлета от его параметров, а также каждого параметра друг от друга. Всё приводимое ниже верно:

  • 123

  • Dir -rec (сокращённое название параметра годится)

  • New-PSDrive -name DEMO -psprovider FileSystem -root \\Server\Share

Однако вот эти примеры все не верны:

  • Dir-rec (отсутствует пробел между псевдонимом и параметром)

  • New-PSDrive -nameDEMO (нет пробела между названием параметра и его значением)

  • New-PSDrive -name DEMO-psprovider FileSystem (отсутствует пробел между значением первого параметра и названием второго параметра)

PowerShell обычно не придирчив к верхнему и нижнему регистру, а это означает, что dir и DIR это одно и тоже, как и в отношении -RECURSE -recurse и -Recurse. Однако эта оболочка очень требовательна к таким пробелам и тире.

Лабораторные занятия

[Замечание]Замечание

Для данных лабораторных занятий вам потребуется PowerShell 7 или последующей версии, запущенный под Windows, macOS или Linux.

Применяя изученное в данной главе и в нашей предыдущей главе по использованию системы подсказок, выполните в PowerShell следующие задачи:

  1. Отобразите список исполняемых процессов.

  2. Проверьте подключение к google.com или bing.com не применяя внешней команды, подобной ping.

  3. Отобразите список всех команд которые относятся к типу командлетов. (Это хитроумно, мы показывали вам Get-Command, однако вам придётся прочесть его подсказку чтобы отыскать как сузить весь перечень до запрошенного нами.)

  4. Отобразите список всех псевдонимов.

  5. Создайте новый псевдоним с тем, чтобы вы были способны запускать ntst для исполнения netstat из приглашения на ввод PowerShell.

  6. Отобразите перечень процессов, начинающихся с p. И снова, прочтите подсказку для необходимой команды - и не забывайте, что звёздочка (*) почти универсальный замещающий символ в PowerShell.

  7. Создайте новую папку (также именуемую как каталог) с названием MyFolder1 при помощи командлета New-Item. А затем сделайте это снова и назовите её MyFolder2. Если вы не знакомы с New-Item, воспользуйтесь Help

  8. Удалите папки, созданные в упражнении 7 одной командой. Воспользуйтесь Get-Command для поиска аналогичного применявшемуся в 7 упражнению командлета - и не забывайте, что звёздочка (*) - практически универсальный символ подстановки для PowerShell.

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

Ответы лабораторных занятий

  1. Get-Process

  2. Test-Connection google.com

  3. Get-Command -Type cmdlet

  4. Get-Alias

  5. New-Alias -Name ntst -Value netstat

  6. Get-Process -Name p*

  7. New-Item -Name MyFolder1 -Path c:\scripts -Type Directory;

    New-Item -Name MyFolder2 -Path c:\scripts -Type Directory

  8. Remove-item C:\Scripts\MyFolder*