Author Posts

March 6, 2015 at 11:31 am

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.

March 6, 2015 at 11:52 am

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.

March 6, 2015 at 12:04 pm

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

March 6, 2015 at 12:07 pm

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

Thanks Dave!

March 6, 2015 at 12:17 pm

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.

March 6, 2015 at 12:21 pm

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.

March 6, 2015 at 12:26 pm

Kudos Dave! 😀

Making this a snippet now. 🙂