当前位置: 首页 > 知识库问答 >
问题:

电源外壳中命令提示符命令的错误处理

唐伟
2023-03-14

我的目标是使用Powershell检查、禁用和删除许多Windows服务器上的计划任务。有些服务器是Windows 2008R2,因此获取调度任务是不可能的。我必须使用schtasks

这是我目前掌握的情况

$servers = (Get-ADComputer -Server DomainController -Filter 'OperatingSystem -like "*Server*"').DNSHostname

$servers |
    ForEach-Object {
        if (Test-Connection -Count 1 -Quiet -ComputerName  $_) {
            Write-Output "$($_) exists, checking for Scheduled Task"
            Invoke-Command -ComputerName $_ {
                    If((schtasks /query /TN 'SOMETASK')) {
                        Write-Output "Processing removal of scheduled task`n"
                        schtasks /change /TN 'SOMETASK' /DISABLE
                        schtasks /delete /TN 'SOMETASK' /F
                    }
                    else {
                        Write-Output "Scheduled Task does not exist`n"
                    }
            }
        }
    }

当某个任务存在时,这很好,但当它不存在时,Powershell会抛出一个错误,如下所示:

ERROR: The system cannot find the file specified.
    + CategoryInfo          : NotSpecified: (ERROR: The syst...file specified.:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
    + PSComputerName        : SERVER1

NotSpecified: (:) [], RemoteException
Scheduled Task does not exist

我可以通过将$ErrorActionPreference设置为“静默继续”来规避此行为,但这会抑制我可能感兴趣的其他错误。我也尝试了尝试,捕获,但仍然生成错误。我不认为我可以将 -错误处理参数添加到 IF 语句中。任何人都可以伸出援助之手吗?

谢谢你,

共有3个答案

柯景龙
2023-03-14

这似乎使执行这项工作过于复杂。

为什么禁用和删除vs只是删除,因为这似乎有点多余?

所有计划的任务都是xml文件和reg条目,如果您不再需要该任务,可以删除它们。因此,您可以使用sue Get-ChildItem。

# File system:
(Get-ChildItem -Path "$env:windir\System32\Tasks").FullName

# Results
<#
...
C:\Windows\System32\Tasks\Microsoft
...
C:\Windows\System32\Tasks\MicrosoftEdgeUpdateTaskMachineCore
...
#>

# Registry:
Get-ChildItem -Path 'HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Schedule\Taskcache\Tasks'
# Results
<#
Name                           Property                                                                                                                             
----                           --------                                                                                                                             
{01C5B377-A7EB-4FF3-9C6C-86852 Path               : \Microsoft\Windows\Management\Provisioning\Logon                                                                
...                                                                                                       
#>

Get-ChildItem -Path 'HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Schedule\Taskcache\Tree'
# Results
<#
Name                           Property                                                                                                                             
----                           --------                                                                                                                             
Adobe Acrobat Update Task      SD    : {1...
#>

只需按名称选择任务,然后使用普通文件系统 cmdlet 删除文件和注册表项即可。

申博厚
2023-03-14

就个人而言,我更喜欢使用Scheduler ComObject来管理计划任务。您可以使用它连接到其他服务器,并简单地搜索它们以管理它们的任务。

$Scheduler = New-Object -ComObject Schedule.Service

$servers = (Get-ADComputer -Server DomainController -Filter 'OperatingSystem -like "*Server*"').DNSHostname

$servers |
    ForEach-Object {
        if (Test-Connection -Count 1 -Quiet -ComputerName  $_) {
            Write-Output "$($_) exists, checking for Scheduled Task"
            $Scheduler.Connect($_)
            $RootFolder = $Scheduler.GetFolder("\")
            $TargetTask = $RootFolder.GetTask('SOMETASK')
            # If the task wasn't found continue to the next server
            If(!$TargetTask){
                Write-Output "Scheduled Task does not exist`n"
                Continue
            }
            Write-Output "Processing removal of scheduled task`n"
            $TargetTask.Enabled = $false
            $RootFolder.DeleteTask('SOMETASK')
        }
    }
梁烨
2023-03-14

tl;dr:

使用2

    < li >要解决至少PowerShell [Core] 7.0(见下文)中出现的错误,请确保< code > $ ErrorActionPreferece 未设置为< code >“Stop”。
# Execute with stderr silenced.
# Rely on the presence of stdout output in the success case only
# to make the conditional true.
if (schtasks /query /TN 'SOMETASK' 2>$null) { # success, task exists
  "Processing removal of scheduled task`n"
  # ...
}

有关背景信息和更多一般用例,请继续阅读。

鉴于来自外部程序的 stderr 流的行如何表现,如您的问题所示,这听起来像是在 PowerShell ISE 中运行代码,我建议远离:PowerShell ISE 已经过时,应避免前进(链接答案的底部)。

ISE默认通过PowerShell的错误流显示stderr lines尤其有问题——参见这个GitHub问题。

幸运的是,常规控制台不会这样做 - 它将 stderr 行传递到主机(控制台),并正常打印它们(不是红色),这是正确的做法,因为您通常不能假设所有 stderr 输出都表示错误(尽管流的名称)。

对于表现良好的外部程序,您应该只从其进程退出代码(如自动$LASTEXITCODE变量[1]中反映的那样)获得成功与失败,而不是从 stderr 输出的存在中得出成功与失败: 退出代码 0 表示成功,任何非零退出代码(通常)表示失败。

至于您的具体情况:

在常规控制台中,$ErrorActionPretion首选项变量的值不适用于外部程序,例如schtasks.exe,除非在您还使用2时以错误的形式[在PowerShell 7.2中修复]

由于您的 schtasks /query /TN “SOMETASK” 命令用作测试,因此您可以执行以下操作:

# Execute with all streams silenced (both stdout and stderr, in this case).
# schtask.exe will indicate the non-existence of the specified task
# with exit code 1
schtasks /query /TN 'SOMETASK' *>$null
 
if ($LASTEXITCODE -eq 0) { # success, task exists
  "Processing removal of scheduled task`n"
  # ...
}

# You can also squeeze it into a single conditional, using
# $(...), the subexpression operator.
if (0 -eq $(schtasks /query /TN 'SOMETASK' *>$null; $LASTEXITCODE)) { # success, task exists
  "Processing removal of scheduled task`n"
  # ...
}

在您的特定情况下,可以使用更简洁的解决方案,该解决方案依赖于您的 schtasks 命令 (a) 在成功的情况下生成 stdout 输出(如果任务存在)和 (b) 仅在成功的情况下执行此操作:

# Execute with stderr silenced.
# Rely on the presence of stdout output in the success case only
# to make the conditional true.
if (schtasks /query /TN 'SOMETASK' 2>$null) { # success, task exists
  "Processing removal of scheduled task`n"
  # ...
}

如果 schtasks.exe生成标准输出(映射到 PowerShell 的成功输出流 1),则 PowerShell 的隐式到布尔转换将考虑条件$true(有关 PowerShell 到布尔转换规则的概述,请参阅此答案的底部部分)。

请注意,条件只作用于成功输出流的输出(< code>1),其他流会通过,如stderr输出(< code>2)在这种情况下(正如您所经历的)。

阿拉伯数字

12 分别是 PowerShell 的成功输出/错误流的数量,对于外部程序,它们分别指其标准输出(标准输出)和 stderr(标准错误)流 - 请参阅about_Redirection

您还可以使用<code>2捕获stderr输出

>

  • 阿拉伯数字

    • 正如上述错误所暗示的,您必须确保$ErrorActionPretion未设置为'Stop',因为2

    除了上述错误,使用2

      < li >这两个问题的根本原因是stderr行意外地通过PowerShell的错误流进行路由,尽管没有很好的理由这样做-请参阅GitHub问题#11133。

    [1]请注意,自动$?变量也被设置为布尔值($true/$false),但不可靠:因为stderr输出当前(v7.0)意外地通过PowerShell的错误流路由,如果使用2重定向

  •  类似资料:
    • 我试图用命令提示符用java编译一个程序。我的程序在eclipse中运行良好,但是,当我试图在命令提示符中编译它时,我收到了一条错误消息。任何帮助和指导都将不胜感激。 triton.java:20:错误:不能dind符号循环Loop=new Loop(); 符号:类循环位置:类Triton trion.java:20:错误:找不到符号循环循环=新循环();sybmol:类循环位置:类Triton

    • 我的命令提示符出错了。我从Jupyter尝试了,但出现了一些错误。我感谢任何查看或回答的人,感谢您的时间!

    • 好吧,我是新来的Java,并试图从命令提示符运行一个java程序(因为Sublime编译和运行它的小东西,但不允许用户输入和东西)。 我将命令提示符设置为我有我的文件的文件夹,称为Learner.java. 我在环境变量中为JDK bin设置了一个路径,并创建了一个JAVA_HOME变量,其中包含JDK bin的值(其他一些帖子建议)。 在我讨论这个问题之前,这是我的代码: 如你所见,这是一个以“

    • $ gdb -q `which gdb` Reading symbols from /home/xmj/install/binutils-gdb-git/bin/gdb...done. (gdb) r -q Starting program: /home/xmj/install/binutils-gdb-git/bin/gdb -q [Thread debugging using libthrea

    • 本文向大家介绍通过什么命令指定命令提示符?相关面试题,主要包含被问及通过什么命令指定命令提示符?时的应答技巧和注意事项,需要的朋友参考一下 答案: \u:显示当前用户账号 \h:显示当前主机名 \W:只显示当前路径最后一个目录 \w:显示当前绝对路径(当前用户目录会以~代替) $PWD:显示当前全路径 $:显示命令行’$'或者’#'符号 #:下达的第几个命令 \d:代表日期,格式为 week da

    • 我是刚到爪哇的。我正在尝试将大型机代码转换为Java。我在命令行下面运行。 我可以知道如何设置res.jar。 命令行代码