当从任务计划程序运行PowerShell时,我该如何重定向输出?

65

在任务计划程序中运行简单的PowerShell脚本时,我希望将输出重定向到文件。

有一个关于这个话题的长篇讨论在这里,但不清楚他们最终是否达到了最合适的解决方案。我想知道Stack Overflow上是否有人也解决了这个问题,以及他们是如何做到的?

10个回答

47

我使用转录功能来帮助这个。只需将其包含在您的代码中,它就会将所有(可能是)屏幕内容输出到日志文件中。

Start-Transcript -path $LogFile -append

<Body of the script>

Stop-Transcript

6
当我通过任务计划程序启动命令(作为powershell.exe的参数)时,发现转录的行为与平常不同。具体来说,对Write-Host的调用似乎将我的文本发送到转录未捕获的地方,尽管重定向到Out-Host似乎是有效的。如果有关系的话,我在Windows Server 2012 R2上运行PowerShell 4.0。 - Jay Carlton
9
我必须使用Write-Output而不是Write-Host。 - Naveen Vijay
3
作为 PowerShell 的创建者所说,您不应该使用 write-host,而是应该使用 write-output。详情请见:http://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful/。虽然这样说,但我没有测试过它是否会对您的日志产生影响,但是应该会有所改善。 - Marlon
很酷,我的PowerShell脚本似乎也无法通过任务计划程序在注册表中执行任何操作(由于权限问题),并且即使启用了上述日志记录,它也无法写入磁盘。无论是作为我的用户运行,还是使用“以最大能力/权限运行”选项都不行。 - Henk Poley
我看到的一个问题是,在管道中进行foreach-object时,如果我试图捕获write-host输出,我不能将其切换到write-output,否则它将被写入Success输出流。 - fudge

45

这是对我有效的命令。我不喜欢在脚本中重定向输出,因为这样会使手动运行变得困难。

powershell -windowstyle minimized -c "powershell -c .\myscript.ps1 -verbose >> \\server\myscript.log 2>&1"

2
您可能还想使用-Noninteractive来避免任何提示。 - David
6
你如何为这个加上时间戳? - Anders
如果您想使用空格解析它,请查看此问题 - DarkLite1
5
这似乎是在PowerShell中调用另一个PowerShell? - Jamie Hanrahan
3
好的,像@JamieHanrahan注意到的那样,为什么要两次调用PowerShell? - jschmitter
显示剩余4条评论

31

以下方法适用于我使用的Windows 7操作系统:

 powershell -command c:\temp\pscript.ps1 2>&1 > c:/temp/apickles.log
在 Windows 7 的任务计划程序界面中:
 program = "Powershell"
 arguments = "-command c:\temp\pscript.ps1 2>&1 > c:/temp/apickles.log"
请注意,"-file"不起作用,因为文件名后的所有参数都被解释为文件的参数。 请注意,"2>&1"也会将错误输出重定向到日志文件中。PowerShell的后续版本会以稍微不同的方式执行此操作。

1
感谢您对Windows 7任务计划程序GUI“参数”的评论 - 我想那是放置输出重定向选项的正确位置。其他答案都没有提到这一点。 - Mister_Tom
-1 适用于win10。在我的Windows 10上无法工作。这篇帖子有相同的问题。https://social.technet.microsoft.com/Forums/windowsserver/en-US/985ce84c-ac55-4fe8-b652-259d5373f747/redirect-script-output-to-file-in-task-scheduler?forum=winserverpowershell - eval
2
“-Command”的一个缺点是它是可解释的,因此在路径中存在空格或任何可解释的内容会导致错误。因此最好单独设置工作目录,并仅使用(非特殊字符)文件名来使用“-Command”。 - BaseZen
在GUI中,不要将引号放入输入字段中,只需输入它们之间的内容(上面的内容)。使用工作目录代替日志文件路径。 - Milan Kerslager

4

之前所有回答的结合真的帮了我很多...

我的问题是,我需要在 Packer provisioner 的一部分中通过 WinRM 执行 PowerShell 脚本,但由于权限问题而失败。绕过这个问题的方法是将其作为定时任务执行,但我需要传递参数到脚本并获取输出以确认一切都已经正确执行了。

这段代码片段对我非常有效:

# Generate a unique ID for this execution
$guid = [guid]::NewGuid()
$logFile = "C:\Windows\Temp\$guid.log"

$argument = "-NoProfile -ExecutionPolicy unrestricted -Command ""& {""$ScriptPath"" $ScriptArgs} 2>&1 > $logFile"""

$a = New-ScheduledTaskAction -Execute "powershell.exe" -Argument $argument
Register-ScheduledTask -TaskName $TaskName  -RunLevel Highest -User $username -Password $password -Action $a | Start-ScheduledTask
do {
    Start-Sleep -Seconds 30
    $task = Get-ScheduledTask -TaskName $TaskName
} while ($task.State -eq 4)

完整的脚本可以在这里找到:

https://gist.github.com/dev-rowbot/fa8b8dadf1b3731067a93065db3e1bba


3

也许使用Start-Transcript会更容易,因为可以直接记录到文件中:

# Get script name
$ScriptFullPath = $MyInvocation.MyCommand.Path
# Start logging stdout and stderr to file
Start-Transcript -Path "$ScriptFullPath.log" -Append

[Some PowerShell commands]

# Stop logging to file
Stop-Transcript

日志文件将与脚本位于同一目录中。

2
我会:创建一个函数来调用您的脚本,并将该函数的输出重定向到以下位置:

.ps1:

function test{
    # Your simple script commands
    ls c:\temp -Filter *.JPG
    ls z:\ # Non-existent directory
}

test *> c:\temp\log.txt

这是日志文件:

    Répertoire : C:\temp


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        07/06/2008     11:06     176275 HPIM1427.JPG
-a---        07/06/2008     11:06      69091 HPIM1428.JPG
-a---        07/06/2008     11:06     174661 HPIM1429.JPG


ls : Lecteur introuvable. Il n'existe aucun lecteur nommé « z ».
Au caractère C:\temp\test.ps1:14 : 1
+ ls z:\ #non existent dir
+ ~~~~~~
    + CategoryInfo          : ObjectNotFound: (z:String) [Get-ChildItem], Driv
   eNotFoundException
    + FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.GetC
   hildItemCommand

使用新的V3重定向运算符,您可以控制要输出什么:

Do-Something 3> warning.txt  # Writes warning output to warning.txt
Do-Something 4>> verbose.txt # Appends verbose.txt with the verbose output
Do-Something 5>&1            # Writes debug output to the output stream
Do-Something *> out.txt      # Redirects all streams (output, error, warning, verbose, and debug) to out.txt

但是,如果从计划任务中运行,*>是否有效?因为问题暗示它无效。 - codeulike

2

我在Windows Server 2016上进行了测试,只需调用powershell一次即可。这样,您就可以使用带有空格的文件夹名称:

Powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle minimized "scriptName.ps1 *>> '\\servername\sharename\folder name with space\logfilename.log'"

0

从PowerShell 3开始,可以重定向各个流(输出、详细和错误)。然而,任务计划程序不理解它们。是PowerShell进行重定向。

@cmcginty的解决方案部分有效,因为PowerShell正在调用PowerShell。它仅支持标准流(错误和输出)。如果要使用所有流,则需要使用:

程序或脚本:C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

参数:-windowstyle minimized –NonInteractive –NoProfile -c "powershell -c path_to_ps1.ps1 4>>verbose.log 5>>debug.log"

起始位置:path_to_ps1


0
我受到Anders的评论问题(如何添加时间戳?)的启发,以及多个回复两次调用PowerShell的启示,我认为这是不必要的。任务计划程序显然是“powershell.exe”,对于参数,我建议简单地使用:
-noninteractive -c "scriptpath.ps1 *>>logpath.txt"

为了每天保留一个文件,那么:

-noninteractive -c "scriptpath.ps1 *>>logpath-$((get-date).ToString('yyyy-MM-dd')).txt"

如果你需要带时间戳的日志文件,你可以删除第二个“>”(这表示将内容追加到已有文件的末尾),并扩展时间格式:

-noninteractive -c "scriptpath.ps1 *>logpath-$((get-date).ToString('yyyy-MM-dd_HH-mm-ss-fff')).txt"

-3
以下代码将详细输出发送到屏幕,并记录到文件中。
something you're doing -Verbose 4>&1 | Tee-Object "C:\logs\verb.log" -Append

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接