首页 > 解决方案 > PowerShell 的测试路径超时

问题描述

我正在尝试定期检查我们域中数百台计算机上的文本文件中是否存在特定字符串。

foreach ($computer in $computers) {
    $hostname = $computer.DNSHostName
    if (Test-Connection $hostname -Count 2 -Quiet) {
        $FilePath = "\\" + $hostname + "c$\SomeDirectory\SomeFile.txt"
        if (Test-Path -Path $FilePath) {
            # Check for string
        }
    }
}

在大多数情况下Test-Connection,然后的模式Test-Path是有效且快速的。但是,有些计算机可以 ping 成功,但Test-Path需要大约 60 秒才能解析为FALSE. 我不确定为什么,但这可能是域信任问题。

对于这样的情况,我希望有一个超时Test-Path,默认为FALSE如果它需要超过 2 秒。

不幸的是,相关线程中的解决方案(How can I wrap this Powershell cmdlet into a timeout function?)不适用于我的情况。建议的 do-while 循环被挂在代码块中。

我一直在尝试乔布斯,但似乎即使这样也不会强制退出Test-Path命令:

Start-Job -ScriptBlock {param($Path) Test-Path $Path} -ArgumentList $Path | Wait-Job -Timeout 2 | Remove-Job -Force

作业继续在后台挂起。这是我可以达到上述要求的最干净的方法吗?有没有更好的方法来超时 Test-Path 以便脚本除了产生异步活动之外不会挂起?非常感谢。

标签: powershell

解决方案


将您的代码包装在一个[powershell]对象中并调用BeginInvoke()以异步执行它,然后使用关联的 WaitHandle 等待它仅在设定的时间内完成。

$sleepDuration = Get-Random 2,3
$ps = [powershell]::Create().AddScript("Start-Sleep -Seconds $sleepDuration; 'Done!'")

# execute it asynchronously
$handle = $ps.BeginInvoke()

# Wait 2500 milliseconds for it to finish
if(-not $handle.AsyncWaitHandle.WaitOne(2500)){
    throw "timed out"
    return
}

# WaitOne() returned $true, let's fetch the result
$result = $ps.EndInvoke($handle)

return $result

在上面的示例中,我们随机休眠 2 秒或 3 秒,但设置了 2 秒半的超时时间 - 尝试运行几次以查看效果 :)


推荐阅读