Powershell: Пришло ли время для «PowerShell vZeroTechnicalDebt» и / или для механизма включения новых / исправленных функций, нарушающих обратную совместимость?

Созданный на 26 апр. 2018  ·  69Комментарии  ·  Источник: PowerShell/PowerShell

Обратите внимание, что термин _технический долг_ используется здесь в широком смысле для обозначения «накопившегося неисправного поведения, которое не может быть исправлено без нарушения обратной совместимости»;


_Update_: @rjmholt официально начал обсуждение того, как реализовать


Примечание. Эта проблема, возникшая из-за https://github.com/PowerShell/PowerShell/issues/5551#issuecomment -380522712, предназначена только для того, чтобы

Стремление PowerShell к обратной совместимости на протяжении многих лет очень хорошо служило сообществу.

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

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

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

  • Интеграция функций / исправлений, нарушающих обратную совместимость, в существующую кодовую базу, доступная только на основе _opt-in_.

Какие подходы, если таковые имеются, мы готовы рассмотреть?
Когда мы проясним это, мы сможем конкретизировать процессы.

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

  • Сложность и непоследовательность текущей обработки ошибок и проблемная [отсутствие] интеграции с «родными» (внешними) программами - # 3996

  • Непоследовательное, трудно предсказуемое наследование переменных предпочтений / общих параметров - # 4568

  • Проблемы с производительностью из-за того, что [object[]] является основным типом коллекции - https://github.com/PowerShell/PowerShell/issues/5643#issuecomment -378467986

    • Понятно, что PowerShell никогда не сможет сравниться со скоростью утилит Unix, но тем более важно сделать взаимодействие с ними предсказуемым и безболезненным, насколько это возможно - просмотрите оставшиеся проблемы, повторно цитируя и анализируя.
  • Проблемные динамические функции, которые должны работать лексически: https://github.com/PowerShell/PowerShell/issues/3879#issuecomment -304940545 re break и continue , https://github.com/ PowerShell / PowerShell-RFC / blob / master / 1-Draft / RFC0003-Lexical-Strict-Mode.md re Set-StrictMode (хотя последнее может быть исправлено без нарушения совместимости)

  • Проблемы, связанные с [psobject] (хотя, возможно, их можно исправить без нарушения совместимости): # 5551, # 5579, # 4343, # 5763

  • Злополучное разделение -LiteralPath / -Path - краткое обоснование на https://github.com/PowerShell/PowerShell/issues/6714#issuecomment -383992749 и уход от бед на https://github.com / PowerShell / PowerShell / issues / 6714 # issuecomment -384353966 (не уверен, что есть хорошее решение)

  • Неработающее цитирование для внешних программ - # 3734, # 5576 (и другие) и связанные с ними вялые RFC

  • -Command и -File Анализ аргументов CLI - https://github.com/PowerShell/PowerShell/issues/4024#issuecomment -311541803, # 3223 - и общее несовпадение с CLI POSIX-подобного оболочки - # 3743 - включая профили пользователей, загружаемые по умолчанию даже при неинтерактивных (скриптовых) вызовах - # 992

  • Непоследовательный и неожиданный разбор составных аргументов командной строки - # 6467 - и токенов без параметров, которые _подобны_ параметрам - # 6291, # 6292 и # 6360

  • Нарушение обработки параметров ValueFromRemainingArguments , как утверждается в https://github.com/PowerShell/PowerShell/issues/2035#issuecomment -323816221, с нарушенным поведением, показанным в # 5955 и # 5122 - возвращение к https: //github.com/PowerShell/PowerShell/pull/2038

Данные окружающей среды

Написано от:

PowerShell Core v6.0.2
Issue-Meta

Самый полезный комментарий

Исправлять проблемы дорого, что я считаю техническим долгом того, что PowerShell не принимает новые концепции .NET по мере их появления.

  • Синтаксис языка для параметров типа для универсальных методов # 5146

  • Поддержка движком Extension Methods для автоматического отображения в системе типов (как в _compiled_ .Net языках). # 2226

  • Поддержка языков для асинхронных API # 6716 (и RFC )

Есть несколько достойных сожаления особенностей:

  • Можем ли мы сделать что-то на основе подсказок типа (например, @KirkMunro 's FormatPx ) вместо командлетов,

  • Не могли бы вы нормализовать поставщика реестра, чтобы он был основан на содержании, а не чувствовал бы себя демонстрацией того, как поставщик свойств может работать? # 5444

  • Не могли бы вы провести глубокий рефакторинг PSProvider, чтобы упростить их написание? Жалко, что требуется два уровня абстракции, чтобы прийти к "SHiPS" и, наконец, дать людям возможность писать поставщиков, которые они готовы использовать.

Как насчет более важного вопроса:

Хотели бы мы пересмотреть подход «много способов лучше» и работать над подходом «ямы успеха»? Я имею в виду, готовы ли мы удалить функции, которые считаются «легким способом», но которые в корне хуже, в пользу наличия только «правильного способа» для работы? Например:

  • Сделайте CmdletBinding всегда включенным
  • Обозначение @ () означает List[PSObject]
  • Сделать @ {} означать Dictionary[PSObject, PSObject] (или Dictionary[string, PSObject] 😲)
  • Сделайте _Process_ блоком по умолчанию
  • Возможно, даже сделать _ValueFromPipelineByPropertyName_ значением по умолчанию ;-)

Все 69 Комментарий

Интересно. Мне всегда было интересно, почему 1 в .ps1 будет использоваться для добавления своего рода семантического управления версиями в сценарии PowerShell, позволяя сценарию указывать, был ли он адаптирован к возможным критическим изменениям.

Исправлять проблемы дорого, что я считаю техническим долгом того, что PowerShell не принимает новые концепции .NET по мере их появления.

  • Синтаксис языка для параметров типа для универсальных методов # 5146

  • Поддержка движком Extension Methods для автоматического отображения в системе типов (как в _compiled_ .Net языках). # 2226

  • Поддержка языков для асинхронных API # 6716 (и RFC )

Есть несколько достойных сожаления особенностей:

  • Можем ли мы сделать что-то на основе подсказок типа (например, @KirkMunro 's FormatPx ) вместо командлетов,

  • Не могли бы вы нормализовать поставщика реестра, чтобы он был основан на содержании, а не чувствовал бы себя демонстрацией того, как поставщик свойств может работать? # 5444

  • Не могли бы вы провести глубокий рефакторинг PSProvider, чтобы упростить их написание? Жалко, что требуется два уровня абстракции, чтобы прийти к "SHiPS" и, наконец, дать людям возможность писать поставщиков, которые они готовы использовать.

Как насчет более важного вопроса:

Хотели бы мы пересмотреть подход «много способов лучше» и работать над подходом «ямы успеха»? Я имею в виду, готовы ли мы удалить функции, которые считаются «легким способом», но которые в корне хуже, в пользу наличия только «правильного способа» для работы? Например:

  • Сделайте CmdletBinding всегда включенным
  • Обозначение @ () означает List[PSObject]
  • Сделать @ {} означать Dictionary[PSObject, PSObject] (или Dictionary[string, PSObject] 😲)
  • Сделайте _Process_ блоком по умолчанию
  • Возможно, даже сделать _ValueFromPipelineByPropertyName_ значением по умолчанию ;-)

Все отличные предложения, @Jaykul.

Повторное создание нотации @() означает List[PSObject] : я думаю, мы можем пойти дальше и использовать эффективно расширяемый тип коллекции в качестве основного типа коллекции PowerShell, чтобы он использовался везде, где [object[]] в настоящее время есть (и используется для внутренних целей, а также при возврате коллекций без потери производительности при преобразовании типов); существуют проблемы, связанные с использованием + , но @PetSerAl предложил реализацию настраиваемого списка для решения этой .

Повторно сделав Process {} блоком по умолчанию в функциях, в качестве отступления: это то, что в настоящее время делает Filter , но оно ограничено - подразумеваемым - блоком Process и этим вариантом функции по-видимому, никогда не прижился; объединение двух в контексте Function имеет для меня смысл.

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

Жаль, что у PowerShell еще не было возможности создать новый исполняемый файл, который работал бы бок о бок с Windows PowerShell, но это могло оторваться от некоторой устаревшей грязи, которая его затягивает.

Только представьте, что бы произошло, если бы мы пошли на это:
Реально говоря, потребуется не менее 6 месяцев целенаправленных усилий, чтобы придумать версию «без сожалений», и еще 6 месяцев, чтобы повторить ее. Затем сторонние модули также должны адаптироваться к нему, чтобы эта версия была полезной, что займет еще как минимум 6 месяцев, чтобы получить разумное покрытие (и имейте в виду, что некоторые модули никогда не будут) ... Затем учтите задержки и непредвиденные проблемы и т. д. Итак, нет, я думаю, что это всего лишь принятие желаемого за действительное, что можно избавиться от всего технического долга в одной версии за один раз (и при этом продолжать разработку, а не просто поддерживать старую версию).

Как бы мне ни хотелось, чтобы такая версия существовала, я думаю, что к ней можно будет добраться только медленно, по одному критическому изменению за раз. С v6 уже было принято много критических изменений, но я думаю, что если в одну версию будет включено слишком много критических изменений, будет слишком сложно обновлять существующие скрипты / модули. Хорошо обсудить наиболее важные критические изменения, но пока не будет LTS-версии pwsh, я не думаю, что пора думать о второй серии pwsh с более существенными изменениями параллельно с существующей основной версией.

@bergmeister Согласен. Однако даже относительно небольшие изменения в основном пути могут серьезно помешать внедрению. Посмотрите на Python 3. Потребовалось 10 лет, чтобы по-настоящему завоевать популярность. С гораздо большими изменениями, кто знает, сколько времени потребуется, чтобы Perl 6 стал доминирующим (а им потребовалось 15 лет, чтобы придумать правильные вещи, поэтому 1,5 года для PowerShell ++ кажутся оптимистичными :-)) С другой стороны, PHP кажется регулярно ломать вещи, возможно, из-за способа и того, для чего он используется.

Python 3 - определенно шоу ужасов, действительно ли оно прижилось? Я все еще использую 2.7 и не планирую в ближайшее время обновляться. Но в последнее время я тоже мало что слышал о Perl 6 ...

Я думаю, что уроки, которые следует извлечь из Python, заключаются в том, чтобы отделить критические изменения языка от изменения версии движка. Гипотетически движок PS 7 мог по-прежнему запускать файлы более ранних сценариев (.PS1) в режиме непрерывных изменений, в то время как если бы сценарий был помечен как осведомленный 7 (скажем, с расширением .PS7), они могли бы объявить, что они были обновлены _и_ что для работы требуется как минимум PS 7. Надеюсь, это имеет смысл.

Возможно, лучшая история успеха - это JavaScript / TypeScript / Babel. Транспилер (с поддержкой исходной карты) кажется лучшим способом эволюции языка.

Javascript - особый случай. Вы в значительной степени застряли в этом, поэтому транспилирование - действительно единственный вариант. Typescript - это «просто» Javascript с расширениями, поэтому его легко принять. Любая программа javascript - это программа машинописного текста, поэтому вы начинаете с того, что у вас есть, и просто добавляете оттуда аннотации. С другой стороны, Dart - это собственный язык, но транслируемый либо в javascript, либо в собственную среду выполнения в Chrome (по крайней мере, это был план в какой-то момент). Dart, похоже, не получил широкого распространения за пределами Google, вероятно, потому, что это его собственный язык.

@BurtHarris

Python 3 - определенно шоу ужасов, действительно ли оно прижилось?

На прошлой неделе я читал статью, в которой автор утверждал, что для Python 3 достигнута критическая масса. Что все основные модули доступны, и теперь люди мигрируют массово. Мы увидим..

Интересно. Мне всегда было интересно, почему 1 в .ps1 может использоваться для добавления семантического управления версиями к сценариям PowerShell, позволяя сценарию указывать, адаптирован ли он к возможным критическим изменениям.

WRT .ps1 , мы оставляем за собой право изменить расширение в случае, если мы полностью ошиблись языком, что приведет к катастрофическим изменениям в среде выполнения, так что сценарии для предыдущей версии просто не будут работать. Но изменение расширения также приводит к огромному количеству работы, потому что очень много вещей в экосистеме привязано к расширению. Так что это не то, что нужно делать легкомысленно. И, конечно же, будучи частью Windows, если бы мы разделили расширение, нам все равно пришлось бы поддерживать обе версии (вроде Python 2/3).

@bergmeister :

Действительные опасения, но в духе:

Хорошо обсудить самые важные критические изменения

пожалуйста, поделитесь тем, что вы имеете в виду.

медленно, одно ломающее изменение за раз

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

  • Поэтапное введение может привести к тому, что никто не сможет вспомнить, какая версия требуется для какой функции; На ум приходит Perl (v5-).

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

Я уже говорил об этом раньше: для меня - и это всего лишь догадка - v6 GA была неудачным компромиссом между недовольством старожилов внесением изменений и переносом достаточного количества багажа, препятствующего внедрению в [подобном] Unix мире.

Тем не менее, учитывая относительную молодость PowerShell в [-подобном] мире Unix, возможно, есть (все же) большая готовность решать проблемы путем несовместимых изменений. Как заявляет @BrucePay , Windows PowerShell необходимо будет поддерживать в любом случае, и она может оставаться безопасным убежищем для обратной совместимости.

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

OP включает следующее заявление:

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

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

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

  • условная отложенная привязка [scriptblock] arguments (# 6419)
  • когда именно происходит неявное перечисление (# 5832)
  • преобразование [AutomationNull]::Value в $null во время привязки параметров (связано с # 6357)
  • влияние break и continue на поток управления в конвейере (# 5811)
  • что происходит, когда вы шлепаете $null ( ТАК )
  • как использование скриптовых блоков в разных состояниях сеанса влияет на $_ ( SO 1 , SO 2 )

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

  1. они представляют поведение, которое, вероятно, не может быть улучшено в PowerShell, и
  2. У меня нет надежды надежно обнаружить все их последствия при чтении или написании PowerShell.

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

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

(Кстати, спасибо @ mklement0 за прямой думал об этом. Приятно видеть возможность для всех высказать свое мнение.)

Спасибо, @ alx9r.

Я думаю, что важно различать внутреннюю сложность и внешнюю сложность:

  • _ Внутренняя_ сложность проистекает из внутренней сложности реализуемых концепций, которая в случае PowerShell имеет два основных источника: _ внутренняя_ сложность от введения новой парадигмы (объектно-ориентированный конвейер) и объединение двух разных миров (синтаксис оболочки и синтаксис языка программирования. ), и _внешнюю_ сложность из-за взаимодействия с множеством разрозненных внешних миров.

  • _Extrinsic_ сложность проистекает из дырявых абстракций и несоответствий.

    • Такая сложность должна быть устранена.
    • Если это не вариант из-за проблем с обратной совместимостью, такая сложность должна быть _документирована как известные проблемы_.

    • Поведение области видимости переменной модуля сценария (на которое вы ссылаетесь в контексте $_ ) - это больше, чем просто причуда: это основная причина серьезной проблемы, ранее упомянутой # 4568.

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

      • Более разумно использовать разделение с помощью $null для передачи _no_ аргументов, а не позиционного аргумента $null .
      • Почему [System.Management.Automation.Internal.AutomationNull]::Value преобразуется в $null во время _привязки параметра_, даже если тип сохраняется в _direct переменной assignment_? См. Https://github.com/PowerShell/PowerShell/issues/9150#issuecomment -473743805
      • Какая польза от _dynamic_ scoping break и continue в стеке вызовов с _quiet termination_, если не обнаружено никакого включающего цикла?

Хотя изобилие функций и объединение разрозненных миров затрудняет запоминание всей необходимой _ внутренней_ сложности, минимизация _ внешней_ сложности по-прежнему важна.

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

Все сводится к твердым концепциям (которые не противоречат интуитивным ожиданиям), описательному именованию и хорошей документации:

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

Так что даже если мы решим, что _устранение_ внешней сложности не вариант, мы можем хотя бы _ систематически задокументировать_ - и обсуждение здесь может послужить отправной точкой для составления «галереи ловушек» (которая также может включать случаи неизбежной _ внутренней_ сложности, которые может быть удивительно).

мы можем, по крайней мере, систематически задокументировать это - и обсуждение здесь может служить отправной точкой для составления «галереи подводных камней»

Роман Кузьмин давно собирает такую ​​галерею, здесь: https://github.com/nightroman/PowerShellTraps

Спасибо, @HumanEquivalentUnit - похоже, отличная коллекция.

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

  • обоснование дизайна, объясняющее, почему такое поведение, хотя и может быть неожиданным, в конце концов оправдано (правильно оформленное объяснение может избавить от элемента неожиданности)

  • признание проблемы, заявив, что:

    • либо: это не будет исправлено в интересах обратной совместимости.
    • или: рассматривается будущее изменение
    • или: проблема уже устранена в PS _Core_

Странно, что его спрашивают, _пришло ли время для "PowerShell vZeroTechnicalDebt" _

Как раз для этого есть необходимая версия команды.

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

Но мы (наконец-то) получаем платформу, которая действительно становится лучше с каждой итерацией ядра. И намного проще в обслуживании.

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

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

https://stackoverflow.com/questions/8505294/how-do-i-deal-with-paths-when-writing-a-powershell-cmdlet

Ссылка: # 8495

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

PS> 1, 2, 2 + 1, 4, 4 + 1
1
2
2
1
4
4
1

На большинстве языков можно было бы ожидать, что это будет результат:

1
2
3
4
5

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

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

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

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

@ vexx32 просто для ясности, я не предлагал флаг experimental который в конечном итоге станет не экспериментальным. Я думал о другом (возможно, больше о Enable-PSFeature поскольку он будет официально поддерживаться (и, таким образом, защищен от критических изменений в отличие от экспериментальных функций)). Я также думал, что это будет единый флаг, в котором вы выберете эти новые критические изменения как набор, а не индивидуально.

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

Добавление @ jszabo98 к списку проблем, составленному здесь, на основе # 8512:

-and и -or неожиданно имеют _same_ приоритет, тогда как в большинстве языков (включая C #) -and имеет более высокий приоритет, чем -or .

Пример выражения, противоречащего ожиданиям:

PS> $true -or $true -and $false
False

Из-за левоассоциативности и того же приоритета -and и -or выше оценивается как ($true -or $true) -and $false а не как ожидаемое $true -or ($true -and $false)

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

Фактически, у нас уже есть модель, которая работает во всем мире - LTS. MSFT использует это для разработки Windows 10. Модель используется для разработки дистрибутивов Unix.
Для нас это означает, что мы можем выпускать версии LTS PowerShell Core каждые два года и включать их в версии Windows 10 LTS и Unix LTS. (Одна из проблем - синхронизировать даты выпуска Windows и Unix для версий LTS. Думаю, MSFT может договориться с основными компаниями Unix.)
В течение этих двух лет мы собираем незначительные критические изменения, переводя более существенные критические изменения на следующий цикл.
Для каждой новой версии LTS ScriptAnalyzer должен получать набор новых правил для облегчения миграции сценария.
В этой модели критически важным продуктам и скриптам нужно будет только перейти с предыдущей версии на следующую после тщательного тестирования и миграции.

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

Обновление: оно должно быть синхронизировано с версиями .Net Core LTS. Я ожидаю, что .Net Core 3.1 будет следующим LTS, а PowerShell Core 6.x должен был быть в этой версии.

Честно? Похоже, это действительно отличная идея для PowerShell Core. Это позволит нам вносить критические изменения, которые действительно могут помочь ему двигаться вперед, не перегружая его проблемами совместимости, а также _не_ не перегружая его слишком большим количеством критических изменений в промежутке между выпусками LTS.

Ссылка: https://github.com/PowerShell/PowerShell/pull/8407#issuecomment -453221566

Get-Variable -ValueOnly -Name myVar | Should -Be $var утверждение не выполняется, если $var является массивом.

Это связано с тем, что Get-Variable -ValueOnly не использует перегрузку перечисления для WriteObject() .

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

Мы должны настроить почти все процессы, которые используют powershell для вызова ядра pwsh.exe перед запуском реальных сценариев, потому что запланированные задачи Windows, jenkins и многие среды не поддерживают ядро ​​PowerShell. Мы делаем это, потому что используем функции, которые доступны только в определенной версии PS.

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

Это философия UNIX. Заставьте инструмент делать одно и делать это хорошо. Затем объедините инструменты, чтобы создать целое, которое больше суммы его частей. Это мир сценариев, в котором мы все время выполняем вызовы подоболочки к другим утилитам и обрабатываем результаты. Исторически таков сценарий. Powershell стремится к странному соглашению, пытаясь сохранить весь код в родном коде, но это всего лишь соглашение, а не требование. PS работает с доступом к ОС и всем доступным утилитам, как и сценарии оболочки unix.

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

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

@ jtmoree-kahalamgmt-com Спасибо за ваш отзыв! Не стесняйтесь открывать новые вопросы, чтобы поделиться своим опытом и отзывами, а также задать новые полезные функции.

Это было бы намного проще, если бы расширение файла для ядра было обновлено до .ps6, чтобы движок PowerShell мог выполнять эту работу за нас.

См. Https://github.com/PowerShell/PowerShell/issues/2013#issuecomment -247987977

И я создал https://github.com/PowerShell/PowerShell/issues/9138 на основе ваших отзывов.

Python 3 - определенно шоу ужасов, действительно ли оно прижилось? Я все еще использую 2.7 и не планирую в ближайшее время обновляться. Но в последнее время я тоже мало что слышал о Perl 6 ...

Я думаю, что уроки, которые следует извлечь из Python, заключаются в том, чтобы отделить критические изменения языка от изменения версии движка. Гипотетически движок PS 7 мог по-прежнему запускать файлы более ранних сценариев (.PS1) в режиме непрерывных изменений, в то время как если бы сценарий был помечен как осведомленный 7 (скажем, с расширением .PS7), они могли бы объявить, что они были обновлены _и_ что для работы требуется как минимум PS 7. Надеюсь, это имеет смысл.

Я считаю, что называть Python 3 шоу ужасов слишком драматично. Если я посмотрю на самые загруженные пакеты PyPi и возьму метаданные отдельных пакетов о загрузках v2 и v3, я вижу, что v3 теперь прервал 33% проникновения практически для всех лучших пакетов, а для более новых библиотек, таких как библиотека запросов Кена Рейца, это Распределение почти 50/50: вчера было 685 тыс. загрузок версии 3 по сравнению с 875 тыс. загрузок версии 2.

Главное, что сдерживало Python 3 долгое время, - это поддержка научным сообществом pandas и pysci. Но, судя по последним статистическим данным, научное сообщество теперь предпочитает Python 3 Python 2: https://pypistats.org/packages/pandas 231k загрузок v3 против 175k загрузок v2.

Как сказал бы знаменитый доктор У. Эдвардс Деминг: «Мы верим в Бога; все остальные приносят данные!» Может быть, вы можете написать сценарий PowerShell для анализа набора данных PyPi и рассказать мне, насколько ужасно Python 3 использует данные: https://packaging.python.org/guides/analyzing-pypi-package-downloads/

Я был бы доволен (именно в таком порядке):

  1. Более простая в использовании модульная система, обеспечивающая хорошие трассировки стека.

    • Например, файл psm1 позволяет описывать произвольные правила загрузки функций, но это вызывает загадочные трассировки стека, в которых все функции логически объединены в файл psm1. Это означает, что номера строк на трассировке стека примерно так же полезны, как шоколадный чайник.
  2. Заменить форматирование строки объекта Error по умолчанию PowerShell, которое поглощает 99% полезности программирования в архитектуре фон Неймана на основе стека.

    • C # более или менее правильно это понимает. PowerShell наполовину умен.
  3. Исправьте нулевое перенаправление, чтобы три разных способа перенаправления выходных потоков на нулевое устройство были эквивалентны по производительности.

  4. Исправить динамическую область видимости :

function a($f) {& $f}
function main() {
    $f = {write-host 'success'}
    a {& $f} # stack-overflow
    a {& $f}.getnewclosure() # okay
}
[void] (main)
  1. Исправить захват переменных :
set-strictmode -version 'latest'
$erroractionpreference = 'stop'

function main() {
    $a = 'foo'
    $f = {
        $g = {$a}.getnewclosure()
        & $g # "variable '$a' cannot be retrieved because it has not been set."
    }.getnewclosure()
    & $f
}

main
  1. Выход накапливается; return не делает то же самое, что и другие языки; почини это.

  2. PowerShell не имеет синтаксического сахара для удаления внешних ресурсов объектов

  3. Перепишите PowerShellGet. Это ужасно. Функции с сотнями строк кода, проглоченными исключениями, без тестового покрытия.

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

    • Кеш не является потокобезопасным. Какого черта?
    • Вся концепция кеширования модуля для целей анализа - это путаница / взлом. Я понимаю, что в Microsoft существует огромная поддержка этой функции, потому что PowerShell чертовски медленный, но посмотрите мое следующее предложение для настоящего исправления.
    • ЕДИНСТВЕННЫЙ способ очистить ваш AnalysisCache - это перезапустить PowerShell.exe.
    • Кэширование модулей для целей анализа тесно связывает анализ с состоянием выполнения модулей.
  5. Предоставьте «скомпилированные модули», аналогичные тому, как файлы Py компилируются в файлы pyc для повышения производительности.

  6. Добавить $none literal

    • Рассмотрите возможность замены $null на $none во многих местах
    • Пересмотрите, как работает ParameterSetName, и разрешите передавать параметрам специальное значение $none , чтобы мне не нужно было писать сумасшедшие операторы переключения для вызова кода 5 разными способами. COM и C # dynamic делают это правильно - PowerShell делает это катастрофой. Примером может служить то, как я должен динамически отображать конфигурацию развертывания для отчетов SSRS в модуле ReportingServicesTools на основе типа возникновения подписки. Я бы предпочел просто передать набор свойств и позволить методу внутренне справляться со сложностью, а не навязывать внешнюю сложность конечным пользователям. ParameterSetName полезен только как концепция в качестве шаблона, а не для программирования. Он путает специальный полиморфизм с intellisense.

@jzabroski Что касается форматирования ErrorRecord, для обсуждения этого используется отдельная проблема: https://github.com/PowerShell/PowerShell/issues/3647 , поскольку форматирование не считается критическим изменением, мы можем внести улучшения.

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

@jzabroski Что касается форматирования ErrorRecord, здесь обсуждается отдельная проблема: # 3647, поскольку форматирование не считается критическим изменением, мы можем внести улучшения.

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

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

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

Я обновил свои предложения, чтобы прояснить, почему они ломают (и удивительны) предложения по изменениям.

Выход накапливается; return не делает то же самое, что и другие языки; почини это.

return ведет себя так, как вы ожидаете, в рамках метода class . Способ "накопления вывода" в обычной / расширенной функции PS довольно типичен для сред сценариев оболочки, например оболочки Korn и Bash. То есть скопируйте несколько команд из консоли и поместите их в функцию. Когда вы вызываете эту функцию, она выводит каждую команду так же, как при выполнении этих команд с консоли.

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

return $foo

действительно выполняется как:

$foo
return

Это дает людям ощущение, что они могут контролировать вывод с помощью return, а они не могут.

return ведет себя так, как вы ожидаете, в рамках метода class . Способ "накопления вывода" в обычной / расширенной функции PS довольно типичен для сред сценариев оболочки, например оболочки Korn и Bash.

Я слышал, как это говорят люди, в том числе @BrucePay (см. Мой курсив ниже, цитируя его), но суть в следующем:

Только в PowerShell у нас есть этот нелогичный бессмысленный "возврат не возвращает", а вывод накапливается. Это прославленная утечка памяти, и вы должны думать об этом как о таковой.

Если честно, везде в PowerShell In Action я ищу фразу «проблемы», могу что-то добавить в список vZeroTechnicalDebt. Вот что Брюс пишет об операторе возврата:

7.3 ВОЗВРАЩЕНИЕ ЗНАЧЕНИЙ ИЗ ФУНКЦИЙ
Теперь пора поговорить о возвращении значений из функций. Мы делали это все время, но есть кое-что, что нам нужно выделить. Поскольку PowerShell - это оболочка, она не возвращает результаты - она ​​записывает выходные данные или генерирует объекты. Как вы видели, результатом любого выражения или конвейера является передача вызывающему объекту объекта результата. Если в командной строке ввести три выражения, разделенных точкой с запятой, будут выведены результаты всех трех операторов:
[...]
В традиционном подходе вы должны инициализировать результирующую переменную $result , чтобы удерживать создаваемый массив, добавить каждый элемент в массив, а затем выдать массив:

PS (16) > function tradnum
> {
> $result = @()
> $i=1
> while ($i -le 10)
> {
> $result += $i
> $i++
> }
> $result
> }

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

Я думаю, что мотивация, лежащая в основе этой функции, хороша, но есть гораздо более понятные и легкие для чтения способы достижения той же цели: неявное продвижение от одного объекта к коллекции объектов. Более того, в PowerShell уже есть простой способ вернуть вывод для перенаправления: Write-Output .

В Bash return выходит из функции, точка.

А? Bash точно так же накапливает вывод:

hillr@Keith-Dell8500:~$ function foo() {
> echo "Hello"
> ls ~
> date
> return
> echo "World"
> }
hillr@Keith-Dell8500:~$ foo
Hello
bar.ps1  date.txt   test.ps1
baz.ps1  dotnet    powershell-preview_6.2.0-rc.1-1.ubuntu.16.04_amd64.deb
Tue Mar 26 16:06:18 DST 2019

Как и PowerShell, Bash по-прежнему выводит все, начиная с каждой команды до оператора return .

А, я думаю, вы имеете в виду то, что возвращается в $? . Да, это разница. Я думаю, что это должны быть возвращаемые значения int в Bash, чтобы указать успех / неудачу. В PS $? указывает успех / неудачу как логическое значение на основе ошибок, сгенерированных функцией. На практике я не думаю, что $? используется так часто. Вместо этого я использую обработку исключений через try/catch/finally .

Да. return в этих языках имеет только одно предназначение. В PowerShell он смешан с выводом. Смешивать возвращаемые значения и выходные потоки - плохая идея. Это также может привести к проблемам с производительностью, похожим на утечку памяти. Что вам действительно нужно, так это совместные подпрограммы или "доходность возврата", или генераторы, конструкторы генераторов и сканеры (как в Icon). Причина в том, что входное потребление является ленивым, а сбой приостанавливает вычисления, позволяя избавиться от части вычислений, сгенерированных на данный момент.

Вы можете думать о «перенаправлении вывода» как о двух объектах: Processor и ProcessorContext.

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

Вместо этого я использую обработку исключений через try/catch/finally .

Это много набора текста и не во всех случаях ясно выражает намерение.

Что ж, PowerShell основан на .NET, который собирает мусор, поэтому он не должен подвергаться «утечкам» памяти. Это не значит, что у вас не может быть запаса памяти. Поэтому вам нужно быть немного осторожным при обработке больших выходных данных / коллекций, которые назначаются переменной или помещаются в какую-либо хеш-таблицу.

Я думаю, что у оператора return PowerShell должна быть только одна цель, а именно - возврат раньше срока - ничего больше. Когда кто-то делает return 42 это не имеет никакого отношения к $? . Это просто еще один элемент, выводимый в поток вывода.

Как я упоминал ранее, $? управляется PowerShell и не имеет ничего общего с тем, что функция выводит / возвращает. $? устанавливается на основе сгенерированных ошибок (или их отсутствия). Это означает, что когда вы выполняете $res = foo - $ res будет содержать каждый объект, выводимый функцией foo. Если вы хотите узнать, не завершилась ли функция "сбой", вы можете проверить $? на каждой выполняемой вами команде ИЛИ вы можете заключить группу команд в блок try/catch . Я считаю, что первые гораздо реже печатают (в скриптах).

слышу, как люди говорят это, в том числе @BrucePay (см. мой акцент ниже, цитируя его), но суть в следующем:
В Korn Shell return завершает функцию, точка.
В Bash return выходит из функции, точка.

В PowerShell return также выходит из функции:

PS C:\> function test { "hello"; return "!"; "world"}
PS C:\> test
hello
!

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

Смешивания нет, потому что нет разницы между потоком вывода и возвращаемым значением в PowerShell. Вы говорите так, как будто функция записывает строки в stdout и отдельно возвращает восклицательный знак вызывающему, но это не так. Указание на write-output похоже на ту же ошибку; все они: write-output 'x' , 'x' , return 'x' отправляют что-то по тому же пути вывода в конвейер. Отдельного возвращаемого значения нет.

Что вам действительно нужно, так это совместные подпрограммы или "доходность возврата", или генераторы, конструкторы генераторов и сканеры (как в Icon). Т

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

PS C:\> robocopy /whatever
PS C:\> "robocopy /whatever" | set-content test.ps1; .\test.ps1
PS C:\> function test { robocopy /whatever }

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

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

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

PS D:\> 1..1mb |foreach { write-verbose -Verbose "incoming number: $_"; $_ } |select -first 3
VERBOSE: incoming number: 1
1
VERBOSE: incoming number: 2
2
VERBOSE: incoming number: 3
3

select завершит конвейер, как только он получит три вещи. Остальной миллион чисел не был передан в foreach . Информация, перемещающаяся по конвейеру, - это модель «проталкивания», но она управляется механизмом PowerShell.

Хотя, будучи оболочкой, непонятно, что это будет означать «сбой ввода для приостановки вычислений», если ввод поступает от собственной команды или чего-то вне командлета PS.

Предоставьте «скомпилированные модули», аналогичные тому, как файлы Py компилируются в файлы pyc для повышения производительности.

Я думаю, что предполагаемое решение для повышения производительности - писать модули на C #. В некоторых ситуациях код PowerShell действительно компилируется с помощью JIT, но члены группы PS заявили, что не планируют предоставлять его конечным пользователям для настройки, например, доклад IIRC

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

Желательно, но кажется маловероятным; $null = 4 - это простая привязка переменных, 4 | out-null требует накладных расходов на запуск конвейера и выполнение разрешения команд - что, если кто-то намеренно сделал out-null прокси-оболочкой, которая добавила журналирование код? Это технический долг, что запрос на запуск конвейера и командлета выполняется медленнее, чем выражение?

Исправить динамическую область видимости:

Если вы имеете в виду «не использовать динамическую область видимости», это был осознанный выбор, например, Брюс Пайетт здесь сказал «динамическая область видимости, она почти никогда не используется; раньше, как и 30 лет назад, в LISP была динамическая область видимости, но она очень редко использовалась сейчас. Причина, по которой мы его используем: это то, что используют оболочки. Оболочки используют эквивалент динамической области видимости, даже Bash, а оболочки Unix используют эквивалент динамической области видимости, где переменные из контекста вызывающей стороны - в их случае переменные из контекста вызывающей стороны копируются в дочерний контекст. [..] С одной модификацией, обычно в динамической области видимости вы просматриваете цепочку вызовов и устанавливаете переменную там, где она существует, мы этого не делаем, мы устанавливаем переменную в текущей области все время, и снова это имитирует поведение оболочек ".

Это может раздражать, но является ли это «техническим долгом» для оболочки, и будет ли это «нулевой технический долг», если он будет изменен?

Что ж, PowerShell основан на .NET, который собирает мусор, поэтому он не должен подвергаться «утечкам» памяти. Это не значит, что у вас не может быть запаса памяти. Поэтому вам нужно быть немного осторожным при обработке больших выходных данных / коллекций, которые назначаются переменной или помещаются в какую-либо хеш-таблицу.

У меня был системный администратор, который не является инженером, который написал некоторую логику, чтобы попытаться свести в таблицу метаданные для всех файлов в общей папке 8 ТБ. Это не закончилось хорошо: он потреблял много памяти, а также привязывал систему к 100% ЦП ... мы не могли даже войти в систему после запуска сценария, и единственное решение _ в производстве_ для сохранения сервера была жесткая перезагрузка.

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

@jzabroski, можете ли вы поделиться подробностями сценария?

Люди Powershell намеренно пытаются поощрять конвейерную потоковую передачу ( get-childitem | foreach-object {} ) вместо предварительной загрузки набора данных ( $files = get-childitem; $files | foreach-object ), чтобы уменьшить использование памяти. Это была предварительная загрузка?

Использовалось ли использование Group-Object для сбора похожих файлов? В последнее время произошли улучшения в производительности Group-Object, которые уменьшили использование ЦП, если не использования памяти.

PowerShell по умолчанию является одноядерным, был ли там код заданий / пространств выполнения, это был одноядерный сервер? PS 6.1 имеет Start-ThreadJob, который позволяет выполнять несколько заданий с меньшими накладными расходами и регулированием, чтобы помочь контролировать использование ЦП.

По моему опыту, PowerShell позволяет легко писать такую ​​чушь.

Все учебные пособия и книги, в которых говорится о написании $files = @(); $files += $f должны были стоить миру целое состояние циклов процессора и памяти. Это медленный паттерн, дорогостоящий для процессора и памяти и удручающе распространенный. Мне любопытно, был ли этот шаблон вообще в сценарии? (И есть ли способ заблокировать его без нарушения обратной совместимости или сделать + = недействительным для массивов в будущих критических изменениях?).

Но здесь есть компромисс. Get-ChildItem -Recurse составляет 22 символа и потребляет 800+ МБ ОЗУ только на моем диске C :, C # для этого без использования тонны памяти составляет 50+ строк и вообще не получает метаданные файлов и будет больше похоже на 80МБ. Это не утечка памяти PS, это PS использует ее для удобства пользователя.

Есть ли какой-нибудь язык, на котором вам не нужно заботиться о деталях того, как он работает, можно писать полезный код, нельзя писать плохой код и не нужно быть опытным программистом? (А что это тоже оболочка?)

Могут ли какие-либо из предложенных вами ранее изменений заставить сценарий работать?

Вы можете написать сценарий Bash для вывода списка файлов и создания процесса для каждого из них, пока ваш сервер не упадет и вы не сможете подключиться к нему даже по SSH. Вы можете написать скрипт Python, который os.walk() s является деревом файлов и вызывает os.stat() для каждого файла, использует меньше памяти и завершает работу быстрее, но занимает 10 строк вместо 1, и вам все равно нужно заботиться о ОС и заботиться о деталях кода (а это все еще не оболочка и не будет работать с поставщиками PS).

Я бы хотел, чтобы PS было больше «ям успеха» и меньше опасностей, связанных с поездками. Быстрый список имен файлов является одним из них, в котором я вижу много пользы. Радикально изменить его на совершенно другой язык и увиливать в тех областях, в которых он хорошо работает, этого не сделать.

Вы хотите, чтобы Python существовал, Python существует, это прекрасный язык, его не затрудняют попытки вписаться в два разных мира и продолжать семантику определения объема и возврата функций оболочки тридцатилетней давности из другой ОС (почему, Microsoft) или обязательствами Microsoft обратной совместимости (и одержимости .Net), поэтому он может уклоняться от всех этих вопросов, а не отвечать на них.

Я бы хотел, чтобы PS было больше «ям успеха» и меньше опасностей, связанных с поездками.

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

For-EachObject - это функция PowerShell для получения коллекций PowerShell и преобразования их в нечитаемые трассировки стека.

Сегодня я взял сценарий, написанный Amazon для вывода списка дисков Windows EC2: https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-windows-volumes.html#windows -list-disks

Угадай, что? У меня не было настроено Initialize-AWSDefaults на этом ПК, и поскольку автор сценария использовал ForEach-Object, моя трассировка стека выглядела так _garbage_:

PS C:\Windows\system32> D:\Installs\PowerShell\List-EC2Disks.ps1
Could not access the AWS API, therefore, VolumeId is not available. 
Verify that you provided your access keys.
ForEach-Object : You cannot call a method on a null-valued expression.
At D:\Installs\PowerShell\List-EC2Disks.ps1:39 char:12
+ Get-disk | ForEach-Object {
+            ~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [ForEach-Object], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull,Microsoft.PowerShell.Commands.ForEachObjectCommand

Это происходит каждый раз, когда люди используют выражения ForEach-Object в своем коде. Трассировки стека всегда ужасны. Переписывать это больно. К счастью, это просто сценарий, который я копирую, вставляю в случайный файл, сохраняю и запускаю. Если это проблема в большом модуле, мне нужно получить исходный код для модуля, переписать скрипт, надеюсь, бог в его рефакторинге Я ничего не сломал в модуле, преобразовав выражение ForEach-Object И надеюсь Я могу выяснить, где НАСТОЯЩАЯ ошибка, просто чтобы я мог _ выполнять свою работу_. И теперь у меня есть собственный код, который я раздвоил из какого-то крупного репозитория, просто чтобы понять, почему я получаю некоторую ошибку, потому что Write-Error PowerShell УЖАСНО по сравнению с простой идиомой C # throw new Exception("message", ex) .

Переписывая это, чтобы использовать for ($var in $list) , накапливая результаты в переменной $results , я получаю следующую ошибку:

PS C:\Windows\system32> D:\Installs\PowerShell\List-EC2Disks.ps1
Could not access the AWS API, therefore, VolumeId is not available. 
Verify that you provided your access keys.
You cannot call a method on a null-valued expression.
At D:\Installs\PowerShell\List-EC2Disks.ps1:58 char:26
+ ... lDevice = If ($VirtualDeviceMap.ContainsKey($BlockDeviceName)) { $Vir ...
+                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

Да, кстати, каждый раз, когда мне приходится это делать, я не могу вспомнить дурацкие правила PowerShell для добавления элементов в списки, поэтому мне нужно в Google https://www.google.com/search?q=powershell+append + to + list и прочитать сообщение в блоге о ком-то, объясняющем, насколько неинтуитивно понятны операции со списком в PowerShell.

Если вы не знаете C # или языка, который хорошо справляется с этим, легко утверждать, что такое поведение нормально. Однако C # разумно решает эту проблему, заключая исключение в AggregateException, так что вы получаете как внутреннее, так и внешнее исключение. PowerShell? Хахахаха. Да, это было бы слишком полезно.

@jzabroski, можете ли вы поделиться подробностями сценария?

К сожалению (_ и к счастью _), я этого не помню. Это был файлообменник, поэтому почти наверняка это было одно или два ядра, самое большее. Если бы это было два ядра, оставшийся процессор, скорее всего, занял Защитник Windows.

Изменить: нашел в чате Teams.

$big32 = Get-ChildItem D:\Data\Website\Data -recurse | Sort-Object length -descending | select-object -first 32 | measure-object -property length –sum

В качестве дополнительного бонуса я только что поговорил с человеком, который запускал эту команду (и чувствовал себя невероятно плохо), и он сказал, что вариант использования «состоит в том, чтобы захватить 32 самых больших файла для первоначального требования к размеру группы репликации для DFS».

Смешивания нет, потому что нет разницы между потоком вывода и возвращаемым значением в PowerShell.

Я еще не видел, чтобы люди использовали это правильно с первой попытки. Опять же, это не то, что делает bash или любая другая оболочка. Хотя это был интересный эксперимент по объединению двух концепций, он был полной и полной катастрофой с точки зрения удобочитаемости. Не помогает то, что Write-Output был сломан в PowerShell v6 в течение 16 месяцев.

@jzabroski из вашего вывода For-EachObject похоже, что вы не используете Powershell Core (это то, для чего предназначен этот репозиторий), не могли бы вы попробовать ядро ​​Powershell и посмотреть, сможете ли вы воспроизвести его. Обязательно используйте последнюю версию. Помните, что функции, специфичные для Windows (например, Get-Disk), не являются частью Powershell Core, вам нужно будет это учитывать при выполнении тестов.

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

$ test () { ls /tmp; ls /etc/pm; return 5; ls /v*; } ; x=$(test)
$ echo "$x"
tmux-1000
sleep.d
$ echo $?
0

Это и результат двух отдельных команд, накапливающихся в функции Bash, и возврат Bash, не функционирующий как функции возврата в C #. Что конкретно «не то, что делает Баш»?

Вы неправильно записываете возвращаемое значение для примера bash. возврат теряется, потому что $? всегда последняя команда. в вашем случае "эхо".

$ test () { ls /tmp; ls /etc/pm; return 5; ls /v*; } ; x=$(test)
$ echo $?
5
$ echo $x
tmux-1000
sleep.d

POWERSHELL делает это иначе

> function test() { ls; return 5 ; ls } ; $x=test
> echo $?
True
> echo $x
    Directory: c:\foo\bar

Mode                LastWriteTime         Length Name
----                -------------         ------ ----

Еще больше странностей PowerShell:

Chocolatey добавляет RefreshEnv.cmd, который является GODSEND. Почему это просто не поставляется с PowerShell? Зачем мне перезапускать оболочку или загружать какой-нибудь дурацкий скрипт из Интернета, чтобы сбросить $ env?

@jzabroski Это было https://github.com/PowerShell/PowerShell-RFC/pull/92. Возможно, вы захотите вмешаться .

Создайте стандартную объектную модель для поставщиков PowerShell: https://github.com/PowerShell/SHiPS/issues/66#issuecomment -368924485

В ссылке на выпуск 66 SHiPS я описываю возможные командлеты-кандидаты. Мне непонятно, почему мы не можем реализовать что-то вроде поведения класса типов Haskell для этих основных командлетов.

Эти API-интерфейсы уже есть в PowerShell.

@iSazonov Не могли бы вы отредактировать и процитировать то, на что вы отвечаете, и добавить некоторый контекст, например гиперссылку на документацию по указанным API? TYVM

@jzabroski Посмотрите файлы в папке srcSystem.Management.Automationnamespaces.

POWERSHELL делает это иначе

bash делает это по-другому - return может устанавливать только (целочисленный) код выхода из процесса (это не то, что означает "возврат" в других языках программирования, это exit ) .

PowerShell тоже может это сделать с помощью exit 5

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

В конце концов, это та же самая причина, по которой определение типа дескриптора stdout бесполезно в PowerShell (и почему «перенаправление» на out-null не то же самое, что приведение к [void] или присвоение $null )

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

поскольку команда _ четко и недвусмысленно исключила_ несовместимую с предыдущими версиями версию

Для меня это новость. Как это ясно? Предоставьте ссылки на сообщения или другую документацию.

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

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

Я повторяю, что команда уже создала версию powershell «без обратной совместимости», переименовав команду из powershell в pwsh. Power (SHELL) - это снаряд. Работа оболочки - быть клеем для людей, связывающим цифровые системы воедино. Это не скомпилированный двоичный файл с минимальными внешними зависимостями. Даже традиционные языки программирования планируют и вносят критические изменения.

POWERSHELL делает это иначе

bash делает это по-другому - return может устанавливать только (целочисленный) код завершения процесса (это не

Мне любопытны другие снаряды. Что они делают? корн, csh и т. д.

Вот статья, в которой обсуждается оператор return на нескольких языках: https://en.wikipedia.org/wiki/Return_statement

Он указывает, что операционная система [оболочки] позволяет возвращать несколько вещей: код возврата и вывод.

В моей команде есть множество сценариев, которые работают только в PowerShell 5, хотя мы используем PowerShell 6 в максимально возможной степени. По моему опыту, предположение о полной обратной совместимости PowerShell определенно неверно. Есть по крайней мере несколько крайних случаев (например: ErrorActionPreference не интуитивно ведет себя), которые определенно следует рассматривать как критические изменения - случаи, когда внесение исправления будет менее "ломающим", чем невыполнение этого.

@chriskuech есть ли проблема с описанием вашей проблемы с ErrorActionPreference ?

@ SteveL-MSFT Я считаю, что мозаика, которую @KirkMunro связал непосредственно под комментариями @chriskuech, - это проблема, которую вы ищете. И да, я втиснул слово мозаика в технический разговор.

Тем не менее, @iSazonov закрыл исходный выпуск @chriskuech 1 октября 2018 г .: см. Https://github.com/PowerShell/PowerShell/issues/7774.

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

@jzabroski обнаружил, что моя основная проблема

В прошлом я также сообщал о проблеме, связанной с одним из симптомов: Invoke-WebRequest вызывает прерывающую ошибку. Я лично был свидетелем того, как несколько человек были совершенно ошарашены вокруг всего шаблона try / catch для обработки неудачных HTTP-запросов, что происходит из-за того, что внутренние методы .NET выдают завершающие ошибки. В каждом из трех разных случаев инженер отвечал ругательством, когда я объяснял лежащее в основе поведение и почему проблема якобы никогда не будет исправлена.

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

(Касательно вопроса выше)

Если PowerShell реализует режим «ZeroTechDebt», я определенно думаю, что $ErrorActionPreference = "Stop" должен быть установлен по умолчанию. Очевидно, что этот параметр не имеет смысла в REPL и поэтому не должен устанавливаться по умолчанию для всех сценариев, но буквально все мои сценарии имеют префикс $ErrorActionPreference = "Stop" чтобы включить «защитное программирование» и вести себя как «нормальный» " язык программирования.

@chriskuech Если вы еще этого не сделали, ознакомьтесь с этой коллекцией RFC: https://github.com/PowerShell/PowerShell-RFC/pull/187. Они напрямую говорят о том, о чем вы здесь говорите, без необходимости в новой версии PowerShell с нулевым техническим долгом.

Вы также можете найти четыре RFC в отдельных выпусках на странице «Проблемы» в этом репозитории, если это облегчит их чтение / дайджест. Просто ищите открытые вопросы, опубликованные мной, и вы их найдете

@ SteveL-MSFT Вот аналогичная проблема, которая снижает мою продуктивность. Это не $ErrorActionPreference а $ConfirmPreference :

Ниже приведен уродливый сценарий, который я написал для установки дисковых томов SQL Server на 64 КБ.

Import-Module Storage;

function Format-Drives
{
    # See https://stackoverflow.com/a/42621174/1040437 (Formatting a disk using PowerShell without prompting for confirmation)
    $currentconfirm = $ConfirmPreference
    $ConfirmPreference = 'none'

    Get-Disk | Where isOffline | Set-Disk -isOffline $false
    # The next line of this script is (almost) copy-pasted verbatim from: https://blogs.technet.microsoft.com/heyscriptingguy/2013/05/29/use-powershell-to-initialize-raw-disks-and-to-partition-and-format-volumes/
    Get-Disk | Where partitionstyle -eq 'raw' | Initialize-Disk -PartitionStyle MBR -Confirm:$false -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize -IsActive | Format-Volume -FileSystem NTFS -AllocationUnitSize 64kb -Confirm:$false

    # See https://stackoverflow.com/a/42621174/1040437 (Formatting a disk using PowerShell without prompting for confirmation)
    $ConfirmPreference = $currentconfirm
}

Format-Drives

Пара сторонних моментов:

  1. Документация для Format-Volume требует большего. Всего два примера? Официальная документация не синхронизирована с сайтом: https://github.com/MicrosoftDocs/windows-powershell-docs/issues/1170
  2. Почему мне нужно перейти на StackOverflow, чтобы узнать, как избежать использования графического интерфейса для языка сценариев?
  3. Тот факт, что это так подвержено ошибкам / до глупости трудно заставить писать "не задумываясь", просто подчеркивает связанные проблемы, такие как https://github.com/PowerShell/PowerShell-RFC/issues/198 - это еще один пример того, как обещание Брюса Пайетта в " PowerShell In Action ", когда вы просто вводите то, что считаете правильным, и оно работает ... полностью и полностью ложно.
  4. См. Также проблему @ mklement0 : https://github.com/PowerShell/PowerShell/issues/4568

Требуется -Version не может указать максимальную версию

См .: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_requires?view=powershell-6

Это раздражает, когда вы пишете расширенные функции, которые загружают библиотеки .NET Framework, в которых API полностью различается между .NET Framework и .NET Core, например, как работает AccessControl API.

@jzabroski Однако вы можете указать издание, чтобы отделить его:

#requires -PSEdition Desktop
# versus
#requires -PSEdition Core

Замечу, что @rjmholt официально начал обсуждение того, как реализовать

Кроме того, # 6817 и # 10967 - это дополнительные варианты поведения, которые стоит пересмотреть после того, как будут разрешены критические изменения.
(У них одна и та же основная причина, описанная в https://github.com/PowerShell/PowerShell/issues/10967#issuecomment-561843650).

Тот факт, что , сильнее, чем + , логичен, поскольку PowerShell больше ориентирован на списки, чем на числа. ИМХО.

@rjmholt официально начал обсуждение

Я должен сказать, что это не более официальное, чем любое другое обсуждение

Я хотел бы иметь строгую проверку импорта и времени редактирования сигнатур функций.
Вы планируете ввести новую семантику импорта, такую ​​как модули EcmaScript?
Больше никакого загрязнения глобального пространства имен. Механика медленного импорта.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги