invotes-command powershell обновляет содержимое файла с несколькими строками содержимого - PullRequest
0 голосов
/ 08 ноября 2018

Мне нужно обновить имена серверов в куче файлов конфигурации на нескольких серверах. У меня есть быстрый скрипт, чтобы сделать это, но я не хочу входить на каждый сервер индивидуально и перемещать скрипт на него локально, просто чтобы запустить его. Поэтому я использую Invoke-Command. Все работает, получая содержимое файлов и обновляя его, но когда я пытаюсь записать новое содержимое обратно в файл, я получаю ошибку PositionalParameterNotFound в Set-Content. Я предполагаю, потому что это многострочный?

Вот блок кода, который перебирает файлы и пытается выписать их обратно:

ForEach($file in $Files){
    $content = Invoke-command -computerName $computerName -ScriptBlock {get-Content $args[0] -raw} -argumentlist $($file.FullName)
    $content = $content -replace $serverRegEx, $newServer
    Invoke-command -computerName $computerName -ScriptBlock {Set-Content -path $args[0] -value "$($args[1])"} -argumentList $($file.FullName) $content
}

Как передать этот многострочный контент обратно в параметр удаленной команды?

Ответы [ 4 ]

0 голосов
/ 08 ноября 2018

Таким образом, проблема здесь действительно проста ... -ArgumentList принимает массив объектов, но вы не передаете его как массив. Вот что у вас есть:

Invoke-command -computerName $computerName -ScriptBlock {Set-Content -path $args[0] -value "$($args[1])"} -argumentList $($file.FullName) $content

Вот, как я полагаю, ваше намерение по параметрам:

-computerName = $computerName
-ScriptBlock = {Set-Content -path $args[0] -value "$($args[1])"}
-argumentList = $($file.FullName), $content

Проблема в том, что у вас нет запятой между $($file.FullName) и $content, поэтому он не видит их как массив объектов, он видит $($file.FullName) как значение для -argumentList, а затем видит $content как отдельный объект, который пытается оценить как позиционный параметр, но не может определить, каким позиционным параметром он может быть. Решение состоит в том, чтобы добавить запятую между двумя элементами:

Invoke-command -computerName $computerName -ScriptBlock {Set-Content -path $args[0] -value "$($args[1])"} -argumentList $($file.FullName),$content
0 голосов
/ 08 ноября 2018

Это проблема объема.

Вы не можете использовать локальные переменные в удаленном сеансе без указания на это. Для этого требуется PowerShellv3 + и выше.

Пример:

Invoke-Command -ComputerName Server01 -ScriptBlock {
   Write-Output The value of variable a is: $using:a
   Write-Output The value of variable b is: $using:b
}


Get-Help about_remote_variables -Full

Об удаленных переменных

ПОЛНОЕ ОПИСАНИЕ

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

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

ИСПОЛЬЗОВАНИЕ МЕСТНЫХ ПЕРЕМЕННЫХ

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

Начиная с Windows PowerShell 3.0, вы можете использовать область Использование модификатор для определения локальной переменной в удаленной команде.

0 голосов
/ 08 ноября 2018

Аргумент Invoke-command argumentList принимает массив, при вашем втором использовании Invoke-command вы передаете только один аргумент ($($file.FullName)) argumentList. Переменная $content передается как отдельный аргумент Invoke-command, а не блоку скрипта.

Исправьте это, передав 2 аргумента в виде массива:

Invoke-command -computerName $computerName -ScriptBlock {Set-Content -path $args[0] -value "$($args[1])"} -argumentList @($($file.FullName),$content)
0 голосов
/ 08 ноября 2018

Я думаю, что вы случайно конвертируете массив в строку с "$ ($ args [1])". Попробуйте это.

Invoke-Command -ScriptBlock {
    ForEach($file in $using:Files){
        $content = get-Content $file.FullName
        $content = $content %{$_ -replace $serverRegEx,$newServer}
        Set-Content -path $file.FullName -value $content
    }
}
...