【问题标题】:Using Invoke-Command with Variables in ScriptBlock在 ScriptBlock 中使用 Invoke-Command 和变量
【发布时间】:2021-01-04 19:01:48
【问题描述】:

刚接触 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 和谷歌搜索之后,我对我确信这是一个简单的错误认输了语法。

【问题讨论】:

    标签: powershell variables parameters invoke-command scriptblock


    【解决方案1】:

    你可以在脚本块中使用$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] 作为第二个参数......

    【讨论】:

    • $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 这仍然给出相同的错误,我没有列出单独的 args /argumentlist 正确吗?
    【解决方案2】:

    这对我有用。该计算机是 localhost 作为测试,在提升的提示下,无论如何您都需要系统日志。 3 级是警告。如果它是用于同一台计算机,则根本不需要调用命令。

    $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
    

    【讨论】:

      【解决方案3】:

      要使用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) 参数将参数 传递给脚本块,尽管$using: 方法通常更简单。

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

      一般而言,使用Invoke-Command 执行本地代码虽然在技术上得到支持,但很少需要
      对于命令或脚本块的直接同步调用(不是作为作业),使用&call operator(对于单个命令不需要,只要命令名称不是通过变量引用或指定),或者直接在调用者的范围内执行,.dot-sourcing operator (. { ... })。

      【讨论】:

      • 不用担心,我觉得我在寻找正确的答案,因为我有正确的想法,只是没有正确地将各个部分组合在一起,例如使用 $using: 但直到我才发现在我停止尝试 Start-Job 并开始尝试 Invoke-Command 之后。我开始执行 Start-Job/Invoke-Command 道路的唯一原因是我正在考虑在继续执行脚本之前需要完成命令输出,因为我想在完成输出后执行 Write-Host(思考如果我需要将这个想法用于长时间运行的脚本,请转发)。感谢您的帮助!
      • 我很高兴,@tigger。不确定这是否是您遇到的问题,但请注意,有一个微妙的输出同步问题甚至会影响同步命令:请参阅stackoverflow.com/a/43691123/45375
      【解决方案4】:

      您有几个选择。由于您只在本地计算机上运行它,因此您可以使用 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, $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
      

      【讨论】:

      • 我想我有时走在正确的轨道上,但在错误的时间得到了正确的答案,例如在我开始尝试 Start-Job 时错过了 args,然后在错误尝试时得到了 args调用命令。谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-16
      • 1970-01-01
      • 2012-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      相关资源
      最近更新 更多