Is there a wscript.timeout equivalent in PowerShell?

Q: Is there a powershell equivalent of wscript.timeout from vbscript?

I’m writing a script that will run at the domain level during computer or user startup. I want to ensure that it doesn’t hang around too long. In vbscript, I just used wscript.timeout to ensure the script never went past a maximum run time. Just wondering if there is a powershell equivalent.

Wow… I don’t know how many years I was writing VBScripts, and never knew about that feature.

I don’t know if there’s a built-in way to do this in PowerShell, but it’s certainly something that your script could do itself, using events and the Timer class. At first I tried to do this with Register-ObjectEvent, but it turns out that a long-running command can still hang a PowerShell script, and the event handler script block won’t be invoked until after that command is done. However, embedding a bit of C# for the event handler seems to work just fine:

Add-Type -TypeDefinition @'
    using System;
    using System.Timers;
    using System.Diagnostics;

    public static class TimerUtil
    {
        private static Timer timer;
        
        private static Timer GetTimer()
        {
            if (timer == null)
            {
                timer = new Timer();
                timer.Elapsed += (sender,eventArgs) => { Process.GetCurrentProcess().Kill(); };
            }

            return timer;
        }

        public static void KillThisProcessAfter(double interval)
        {
            GetTimer().Interval = interval;
            GetTimer().Start();
        }
    }
'@

[TimerUtil]::KillThisProcessAfter(5000)

Start-Sleep -Seconds 20

Write-Host 'Should not get here.'

Quick note, though: this kills the whole process (powershell.exe or the ISE, typically), not just the current script.

Not really, no. You could track time internally, though, and write an abort clause.

That works. Was hoping for a one-liner like we had in vbscript (PS has me so spoiled with one-liners!)

Thanks Dave!

Well I thought this Dave’s solution was going to work but it’s only v3+. I’m writing this in v2 for compatibility and it doesn’t like Add-Type.

I could add some internal checks like Don mentioned but I’m mostly worried about a cmdlet hanging.

All you need to do to make that example work in v2 is add -Language CSharpVersion3 to the call to Add-Type:

Add-Type -Language CSharpVersion3 -TypeDefinition @'
    using System;
    using System.Timers;
    using System.Diagnostics;

    public static class TimerUtil
    {
        private static Timer timer;
        
        private static Timer GetTimer()
        {
            if (timer == null)
            {
                timer = new Timer();
                timer.Elapsed += (sender,eventArgs) => { Process.GetCurrentProcess().Kill(); };
            }

            return timer;
        }

        public static void KillThisProcessAfter(double interval)
        {
            GetTimer().Interval = interval;
            GetTimer().Start();
        }
    }
'@

[TimerUtil]::KillThisProcessAfter(5000)

Start-Sleep -Seconds 20

Write-Host 'Should not get here.'

It just didn’t like the lambda expression I used to set up the event handler. Could also revise the code so it uses an older method that’s compatible with C# v2.

Kudos Dave! :smiley:

Making this a snippet now. :slight_smile: