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.
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.