Использование Invoke-Command с переменными в ScriptBlock

Новичок в PowerShell и обучение путем написания случайных сценариев с использованием справочной информации. Я пробовал следующие 3 способа правильно ввести переменные в ScriptBlock (вместе со слишком большим количеством мелких вариаций для перечисления) с указанным сообщением об ошибке, заключенным в **:

do
{
try {
[ValidateRange(1,7)][int]$days = Read-Host "Let's pull up some Warning event logs. How many days back would you like to go back? (1-7)"
} catch {}
} until ($?)

do
{
try {
[ValidateSet('desktop','documents',IgnoreCase)]$location = Read-Host "Would you like me to save the log on your Desktop or in your Documents?"
} catch {}
} until ($?)
$filename = Read-Host "What would you like to name the file?"
$DaysAgo = [datetime]::Now.AddDays(-$days)
Invoke-Command -AsJob -Jobname JobEventLog -ScriptBlock {Get-EventLog -logname system | Where-Object EntryType -eq Warning | where TimeGenerated -ge $DaysAgo | Out-File $HOME\$location\$filename.txt}

Invoke-Command: набор параметров не может быть разрешен с использованием указанных именованных параметров.


do
{
try {
[ValidateRange(1,7)][int]$days = Read-Host "Let's pull up some Warning event logs. How many days back would you like to go back? (1-7)"
} catch {}
} until ($?)

do
{
try {
[ValidateSet('desktop','documents',IgnoreCase)]$location = Read-Host "Would you like me to save the log on your Desktop or in your Documents?"
} catch {}
} until ($?)
$filename = Read-Host "What would you like to name the file?"
$DaysAgo = [datetime]::Now.AddDays(-$days)
Invoke-Command -AsJob -Jobname JobEventLog -ScriptBlock {Get-EventLog -logname system | Where-Object EntryType -eq Warning | where TimeGenerated -ge $Using:$DaysAgo | Out-File $Using:HOME\$Using:location\$Using:filename.txt}

Invoke-Command: набор параметров не может быть разрешен с использованием указанных именованных параметров.


do
{
try {
[ValidateRange(1,7)][int]$days = Read-Host "Let's pull up some Warning event logs. How many days back would you like to go back? (1-7)"
} catch {}
} until ($?)
do
{
try {
[ValidateSet('desktop','documents',IgnoreCase)]$location = Read-Host "Would you like me to save the log on your Desktop or in your Documents?"
} catch {}
} until ($?)
$filename = Read-Host "What would you like to name the file?"
Write-Host "Processing..."
$DaysAgo = [datetime]::Now.AddDays(-$days)
$parameters = @{
    ScriptBlock = { Param ($Arg1,$Arg2,$Arg3) Invoke-Command -AsJob -Jobname JobEventLog -ScriptBlock {Get-EventLog -logname system | Where-Object source -eq DCOM | where TimeGenerated -ge $Arg1 | Out-File "$HOME\$Arg2\$Arg3.txt"}}
    JobName = "DCOM"
    ArgumentList = ($DaysAgo,$location,$filename)
}
Invoke-Command @parameters

Invoke-Command: не удается проверить аргумент параметра ScriptBlock. Аргумент равен нулю. Укажите допустимое значение аргумента, а затем попробуйте запустить команду еще раз.

Я просто хочу, чтобы пользователь ввел, как далеко они хотят просматривать журналы событий, где их сохранить и как назвать. Я смог проработать все до сих пор, пока не нажал на строку Invoke-Command и не смог пройти через это. Я предпочитаю однострочный стиль 1 и 2, а не стиль параметров, однако, потратив слишком много времени на help_Invoke-Command-full и поиск в Google, я бросаю полотенце на то, что, я уверен, является простой ошибкой на моем синтаксис.


person tigger    schedule 04.01.2021    source источник


Ответы (4)


Чтобы использовать Invoke-Command -AsJob, вы должны выполнить код удаленно, например, указав другой компьютер с аргументами -ComputerName или -Session.

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

Если вы хотите запустить задание локально, используйте _ 5_ напрямую:

$job = Start-Job -Name JobEventLog -ScriptBlock {
    Get-EventLog -logname system | 
      Where-Object EntryType -eq Warning | 
        Where-Object TimeGenerated -ge $using:DaysAgo | 
          Out-File $HOME\$using:location\$using:filename.txt
  }

Примечание. Поскольку ваш блок фонового сценария ссылается на переменные из области вызывающего, на них необходимо ссылаться через область $using: (как вы также делали в своей последней попытке на основе Invoke-Command ). Это требование также применяется к блокам скриптов, выполняемым удаленно, например через Invoke-Command -ComputerName - см. этот ответ для исходная информация. Альтернативой является передача аргументов в блок скрипта с помощью параметра -ArgumentList (-Args), хотя подход $using: обычно проще.

Start-Job возвращает объект информации о задании (_ 14_), который можно использовать для отслеживания хода выполнения и получения выходных данных фонового задания с помощью различных *-Job командлетов, в частности _ 16_ и _ 17_ - см. about_Jobs концептуальный раздел справки.

Как правило, использование Invoke-Command для локального выполнения кода, хотя и поддерживается технически, редко требуется.
Для прямого синхронного вызова (не как задание) команды или блока сценария используйте &, оператор вызова (не требуется для отдельных команд, если имя команды не заключено в кавычки или не указано через переменную) или, для выполнения непосредственно в области действия вызывающего, . , точка -сорсинговый оператор (. { ... }).

person mklement0    schedule 04.01.2021
comment
Не беспокойтесь, мне кажется, что я флиртовал с правильным ответом, поскольку у меня были правильные идеи, просто не складывала части должным образом, например, использование $: но я не обнаружил этого, пока не перестал пробовать Start-Job и начал пробовать Invoke-Command. Единственная причина, по которой я начал путь по пути Start-Job / Invoke-Command, заключалась в том, что я думал о необходимости завершения вывода команды, прежде чем двигаться дальше в скрипте, поскольку я хотел выполнить Write-Host после того, как он завершит вывод (думая foward, если мне нужно было использовать эту идею для долго работающего скрипта). Спасибо за помощь! - person tigger; 05.01.2021
comment
С удовольствием, @tigger. Не уверен, что вы столкнулись с этим, но обратите внимание на небольшую проблему синхронизации вывода, которая влияет даже на синхронные команды: см. stackoverflow.com/ a / 43691123/45375 - person mklement0; 05.01.2021

Вы можете использовать $args внутри блока сценария, см. Пример:

$DaysAgo = [datetime]::Now.AddDays(-$days)
Invoke-Command -AsJob -Jobname JobEventLog -ScriptBlock {
Get-EventLog -logname system | Where-Object EntryType -eq Warning | 
where TimeGenerated -ge $args[0] | 
Out-File $HOME\$location\$filename.txt
} -ArgumentList $DaysAgo

Добавьте аргументы в конец Invoke-Command, как в примере, и используйте $args[0] для первого аргумента, $ args [1] для второго и так далее ...

person Avshalom    schedule 04.01.2021
comment
$ DaysAgo = [datetime] :: Now.AddDays (- $ days) Invoke-Command -AsJob -Jobname JobEventLog -ScriptBlock {Get-EventLog -logname system | Where-Object EntryType -eq Предупреждение | где TimeGenerated -ge $ args [0] | Out-File $ args [1] \ $ args [2] \ $ args [3] .txt} -ArgumentList $ DaysAgo, $ HOME, $ location, $ filename Это по-прежнему дает ту же ошибку, я не перечисляю отдельные аргументы / список аргументов правильно? - person tigger; 04.01.2021

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

$location = 'foo'
$filename = 'myfile'
$date = get-date
$daysago = $date.adddays(-1) 
invoke-command localhost { param($daysago, $location, $filename)
  get-winevent @{logname = 'system'; level = 3; starttime = $daysago} |
  out-file $home\$location\$filename.txt } -args $daysago,$location,$filename
person js2010    schedule 04.01.2021

У вас есть несколько вариантов. Поскольку вы запускаете это только на своем локальном компьютере, вы можете использовать Start-Job вместо Invoke-Command.

При этом проблема, с которой вы столкнулись, двоякая. Во-первых, если вы используете командлет Invoke-Command, вам нужно указать параметр ComputerName. Несмотря на то, что это необязательный параметр, вам нужно будет использовать его, чтобы сообщить Powershell, какой набор параметров вы используете, иначе он запутается.

Во-вторых, вам нужно передать аргументы в блок сценария. Это связано с тем, что Start-Job и Invoke-Command являются частью PSRemoting и фактически будут искать переменные среды на указанном компьютере, а не переменные, которые вы объявили в своем скрипте.

Вот что у меня сработало:

Invoke-Command -ComputerName $(hostname) -AsJob -JobName "TestJob" -ScriptBlock { Get-EventLog -logname system | Where-Object EntryType -eq Warning | Where-Object -property TimeGenerated -ge $args[0] | Out-File "$HOME\$($args[1])\$($args[2]).txt" } -ArgumentList $DaysAgo, $location, $filename

Параметр Invoke-Command очень эффективен, если вы хотите получать эту информацию от других устройств в вашей сети.

А вот и Start-Job версия:

Start-Job -Name "TestJob2" -ScriptBlock { Get-EventLog -logname system | Where-Object EntryType -eq Warning | Where-Object -property TimeGenerated -ge $args[0] | Out-File "$HOME\$($args[1])\$($args[2]).txt" } -ArgumentList $DaysAgo, $location, $filename
person Bryan Mulvey    schedule 04.01.2021
comment
Я полагаю, что время от времени я был на правильном пути, но получал правильные ответы в неподходящее время, например, пропускал аргументы, когда я пытался запустить Start-Job в начале, а затем имел аргументы при неправильной попытке Invoke-Command. Спасибо! - person tigger; 05.01.2021