Правила экранирования для строк, содержащих скрипты, через SSH

Я пытаюсь отправить сценарий PowerShell в виде строки через SSH в PowerShell 5.1. Его цель — изменить содержимое файла конфигурации на удаленном компьютере. Мне удалось исправить проблемы, связанные с экранированием последовательностей специальных символов, благодаря этому ответу в моем предыдущем вопросе. Однако я предполагал, что ssh $Username@$ComputerIP $stringScript будет выполняться аналогично cmd.exe /c $stringScript, но, судя по моему тестированию, это не так, они обрабатываются по-другому на уровне, который я не понимаю, поскольку код с ssh выдает ошибку.

Вот мой предполагаемый код:

$forceOnlyKeysSSH = '`nMatch all`n`tPasswordAuthentication no'
$rmtPSAuthOnlyKeys = "powershell Add-Content -Force -Verbose -Path c:\ProgramData\ssh\sshd_config " +
    "-Value \`"$forceOnlyKeysSSH\`""
ssh -o ConnectTimeout=10 $Username@$ComputerIP $rmtPSAuthOnlyKeys

В идеале он должен изменить файл sshd_config с помощью

Match all
    PasswordAuthentication no

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

Add-Content : A positional parameter cannot be found that accepts argument 'all
        PasswordAuthentication'.
At line:1 char:1
+ Add-Content -Force -Verbose -Path c:\ProgramData\ssh\sshd_config -Val ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Add-Content], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.AddContentCommand

Я ошибочно избегаю строки? Почему эта ошибка не появляется при вызове cmd.exe /c $rmtPSAuthOnlyKeys?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
54
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий
  • Если вы вызываете ssh.exe из Windows PowerShell или PowerShell 7 v7.2.x или ниже, вам, к сожалению, необходимо компенсировать ошибку, которая влияет на аргументы со встроенными символами ".

    • Так получилось, что ошибка устраняется при прямом вызове cmd.exe /c из-за собственных особенностей синтаксического анализа cmd.exe.

    • Однако это затрагивает все остальные внешние программы, включая ssh.exe.

      • Таким образом, при конфигурации SSH-сервера по умолчанию в Windows, даже если команда, переданная клиенту ssh.exe, в конечном итоге передается cmd /c, ошибку необходимо устранить.

      • См. обходной путь ниже.

  • Эта ошибка исправлена ​​в PowerShell (Core) 7 версии 7.3 и выше, поэтому при вызове оттуда не требуется никаких дополнительных усилий.

  • См. этот ответ для получения дополнительной информации.


Обходной путь:

В частности, в Windows PowerShell и PowerShell 7.2 необходимо вручную \-экранировать " символы. (двойные кавычки), встроенные в аргументы.

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

$forceOnlyKeysSSH = '`nMatch all`n`tPasswordAuthentication no'
$rmtPSAuthOnlyKeys = "powershell -NoProfile Add-Content -Force -Verbose -Path c:\ProgramData\ssh\sshd_config " +
    "-Value \`"$forceOnlyKeysSSH\`""
if ($PSVersionTable.PSVersion -lt '7.3') { # Workaround needed
  # Manually add another round of \-escaping to the embedded, escaped \" chars.
  $rmtPSAuthOnlyKeys = $rmtPSAuthOnlyKeys.Replace('\"', '\\\"')
}
ssh -o ConnectTimeout=10 $Username@$ComputerIP $rmtPSAuthOnlyKeys

Примечание:

  • Как написано, значение, хранящееся в $forceOnlyKeysSSH, подлежит нормализации пробелов, так что, например, foo bar будет передано как foo bar; то есть серии из двух или более пробелов сворачиваются в одно пространство каждый.

  • Если это вызывает беспокойство, потребуется дополнительная работа, как подробно описано в ответе на ваш предыдущий вопрос - обратите внимание, что необходимость в дополнительном руководстве \-экранирование в равной степени применима к ситуации; чтобы изложить более громоздкое решение без нормализации пробелов:

    $forceOnlyKeysSSH = '`nMatch all`n`tPasswordAuthentication no'
    # Note the (escaped) "..." enclosure around the (implied) -Command argument
    # and the (escaped) "^""..."^"" enclosure around $forceOnlyKeysSSH
    $rmtPSAuthOnlyKeys = "powershell -NoProfile `"Add-Content -Force -Verbose -Path c:\ProgramData\ssh\sshd_config " +
        "-Value `"^`"`"$forceOnlyKeysSSH`"^`"`"`""
    if ($PSVersionTable.PSVersion -lt '7.3') { # Workaround needed
      # Manually add another round of \-escaping to the embedded " chars.
      $rmtPSAuthOnlyKeys = $rmtPSAuthOnlyKeys.Replace('"', '\"')
    }
    ssh -o ConnectTimeout=10 $Username@$ComputerIP $rmtPSAuthOnlyKeys
    

Даже с дополнительным экранированием $forceOnlyKeysSSH и в начале команды предлагаемые изменения приводят к тому же сообщению об ошибке, как показано в вопросе Add-Content : A positional parameter cannot be found that accepts argument.... Кроме того, цель состоит в том, чтобы строка внутри $forceOnlyKeysSSH сохраняла свой формат, так как же можно избежать нормализации *пробелов? В остальном решение для кросс-редакций выглядит очень полезным.

JackOA 09.08.2024 11:50

@JackOA, решение, позволяющее избежать нормализации пробелов, находится во втором фрагменте кода этого ответа внизу. Я удивлен, что это не работает, но я проверю (необходимо настроить SSH-сервер в Windows).

mklement0 09.08.2024 18:29

@JackOA, я настроил SSH-сервер в Windows, и оба фрагмента кода в этом ответе работают для меня так, как рекламируется при вызове из PowerShell. Вы уверены, что использовали код именно так, как показано?

mklement0 09.08.2024 20:19

Неважно, я неправильно понял, что это условие выполняется для версий новее 7.3. Это действительно успешно работает. Однако я не уверен, что полностью понимаю добавление ^. Чтобы прояснить ответ, поскольку экранирование довольно сложное, не могли бы вы описать, как будет выглядеть строка в $rmtPSAuthOnlyKeys после каждого прохода анализа с помощью PowerShell и командной строки Windows?

JackOA 12.08.2024 11:24

Возьмите принятый ответ от @mklement0 как лучший подход.

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

$forceOnlyKeysSSH = '`nMatch` all`n`tPasswordAuthentication` no'

Другие вопросы по теме