【问题标题】:Start-Sleep pauses entire functionStart-Sleep 暂停整个功能
【发布时间】:2019-08-28 12:50:57
【问题描述】:

我有一个 PowerShell 脚本,该脚本具有在有人输入计算机名称时提取 LAPS 信息的功能。我想要的是在 60 秒后清除输出,以免有人不小心在屏幕上留下密码。

似乎无论在函数中的什么位置(甚至之后),脚本都会暂停 60 秒,然后显示信息并且永远不会清除。

等待和清除的脚本部分:

Start-Sleep -s 60
$WPFOutputbox.Clear()

(在下方查找我的#TRIED HERE cmets)

function GETLAPS {
    Param ($computername = $WPFComputer.Text)

    try {
        $LAPSComputer = Get-AdmPwdPassword -ComputerName $computername |
                        Select-Object -ExpandProperty computername
        $LAPSDistinguished = Get-AdmPwdPassword -ComputerName $computername |
                             Select-Object -ExpandProperty distinguishedname
        $LAPSPassword = Get-AdmPwdPassword -ComputerName $computername |
                        Select-Object -ExpandProperty Password
        $LAPSExpire = Get-AdmPwdPassword -ComputerName $computername |
                      Select-Object -ExpandProperty Expirationtimestamp
    } catch {
        $ErrorMessage = $_.Exception.Message
    }
    if ($ErrorMessage -eq $null) {
        $WPFOutputBox.Foreground = "Blue"
        $WPFOutputBox.Text = "Local Admin Information for: $LAPSComputer

    Current: $LAPSPassword

    Exipiration: $LAPSExpire

    SCREEN WILL CLEAR AFTER 60 SECONDS"
        #TRIED HERE
    } else {
        $WPFOutputBox.Foreground = "Red"
        $WPFOutputBox.Text = $ErrorMessage
    }
    #TRIED HERE
}

相反,脚本将等待 60 秒以显示信息,并且永远不会清除屏幕。

【问题讨论】:

  • $WpFOutputBox.Text = "" ?
  • 这是一个 WPF 窗口,以更友好的帮助台方式显示输出。不过它会在 powershell 上运行。
  • 尝试将文本设置为空字符串,而不是 Clear()。 $WpFOutputBox.Text = ""
  • 这不是主要问题,而是在显示信息之前等待 60 秒。我可以用其他命令清屏就好了。
  • 我想说,你需要定义一段 C#/.Net 代码,然后使用类似 [System.Threading.Tasks.Task]::Run(delegate) 的东西在后台启动它。或者在 C# 中制作自己的自动关闭对话框窗口,使用 Add-Type 加载此 DLL。或者,在本地主机上运行整个输出任务。

标签: powershell


【解决方案1】:

除非您创建一个单独的线程,否则我强烈建议您不要在Windows FormsWindows Presentation Foundation 中使用Start-Sleep cmdlet,因为它显然会停止用户界面。

相反,我建议使用 (Windows.Forms.Timer) 事件。

为此,我写了一个小函数来延迟一个命令:

延迟命令

Function Delay-Command([ScriptBlock]$Command, [Int]$Interval = 100, [String]$Id = "$Command") {
    If ($Timers -isnot "HashTable") {$Global:Timers = @{}}
    $Timer = $Timers[$Id]
    If (!$Timer) {
        $Timer = New-Object Windows.Forms.Timer
        $Timer.Add_Tick({$This.Stop()})
        $Timer.Add_Tick($Command)
        $Global:Timers[$Id] = $Timer
    }
    $Timer.Stop()
    $Timer.Interval = $Interval
    If ($Interval -gt 0) {$Timer.Start()}
}; Set-Alias Delay Delay-Command

示例

Delay {$WpFOutputBox.Text = ''} 60000

参数

-Command
要延迟的命令。

-Interval
执行command之前的等待时间。
如果-Interval 设置为0 或更小,command(以及相关的Id)将被重置。
默认值为100(稍许延时以使其他事件有可能开始)。

-Id
延迟命令的Id。可以同时执行不同Id 的多个命令。如果相同的Id 用于尚未执行的命令,则间隔计时器将被重置(或在设置为0 时取消)。
命令字符串中的默认Id

【讨论】:

    【解决方案2】:

    调用函数,休眠 60 秒,然后清除。不要把你的睡眠放在函数里面,把它放在你调用函数的地方。比如:

    $WPFGetLAPSButton.add_click({
        GETLAPS
        # If no error, wait 60 seconds and clear the text box
        If($WPFOutputBox.Foreground -eq "Blue"){
            Start-Sleep 60
            $WPFOutputBox.Text = ''
        }
    })
    

    很确定它会满足您的需求。

    【讨论】:

    • 如果它和 GUI 在同一个线程中运行,它仍然会阻塞 60 秒。
    猜你喜欢
    • 1970-01-01
    • 2017-01-08
    • 2021-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多