对 ScriptBlock 中的变量使用 Invoke-Command

问题描述

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}

调用命令:无法使用指定的命名参数解析参数集。


do
{
try {
[Validaterange(1,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}

调用命令:无法使用指定的命名参数解析参数集。


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',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

调用命令:无法验证参数“ScriptBlock”上的参数。参数为空。为参数提供一个有效值,然后再次尝试运行该命令。

我只是想让用户输入他们想要查看多远事件日志、将其保存到何处以及如何命名。到目前为止,我已经能够完成所有工作,直到我点击 Invoke-Command 行并且无法通过它。我更喜欢 1 和 2 的单行样式而不是参数样式,但是在使用 help_Invoke-Command-full 和谷歌搜索花了太多时间之后,我认输了,我确信这是我的一个简单错误语法。

解决方法

您可以在脚本块中使用 $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] 作为第二个参数,依此类推...

,

这对我有用。计算机是 localhost 作为测试,在提升的提示下,无论如何您都需要系统日志。 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,$filename
,

为了使用 Invoke-Command-AsJob 开关,您必须远程执行代码,例如通过使用-ComputerName-Session 参数。

如果没有此类参数,您的命令将本地运行,但由于上述语法限制而失败。

如果您想本地运行作业,请直接使用Start-Job

$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 - 有关背景信息,请参阅 this answer。另一种方法是通过 -ArgumentList (-Args) 参数将 arguments 传递给脚本块,尽管 $using: 方法通常更简单。

Start-Job 返回一个 job-information 对象 (System.Management.Automation.Job),您可以使用它来监视进程并获取后台作业的输出,使用各种 { {1}} cmdlet,特别是 Wait-JobReceive-Job - 请参阅 about_Jobs 概念帮助主题。

通常,使用 *-Job 进行本地代码执行,虽然技术上支持,但很少需要
对于命令或脚本块的直接、同步调用(不是作为作业),请使用 Invoke-Commandcall operator(单个命令不需要,只要命令名称未引用或通过变量指定),或者,为了直接在调用者的范围内执行,&dot-sourcing operator (.)。

,

您有几个选择。由于您仅在本地计算机上运行此程序,因此您可以使用 Start-Job 而不是 Invoke-Command

话虽如此,您遇到的问题是 2 倍。首先,如果您正在运行 Invoke-Command cmdlet,则需要指定 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,$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,$filename

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...