Custom Task Scheduler Service

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
I have been working for some time on a service that will act as a task scheduler and perform a shutdown action at one of 3 given shutdown times. Before you cringe and ask why not use the task scheduler, I should explain that permissions do not allow users
to "create" scheduled tasks and therefore a creative work-around is required. In any case, I am still new to VB, but am including my code below. I want the service to check an alarm time every minute and launch a shutdown application (in the users
context - if logged in) if that time is NOW. There is probably a great deal I am missing, but any suggestions, or help will be much appreciated.
Imports System<br/>
Imports Microsoft.Win32<br/>
Imports System.Runtime.InteropServices<br/>
Imports System.Security<br/>
Imports System.ServiceProcess<br/>
Imports System.Timers
Public Class ECSService<br/>
Private AlarmTime1 As Date<br/>
Private AlarmTime2 As Date<br/>
Private AlarmTime3 As Date<br/>
Dim regKey As RegistryKey<br/>
Dim regRoot As RegistryKey = Registry.LocalMachine<br/>
Dim user As System.Security.Principal.WindowsIdentity<br/>
Dim Timer_1 As New System.Timers.Timer(60000) One minute interval timer<br/>
Dim Timer_2 As New System.Timers.Timer(60000) One minute interval timer<br/>
Dim Timer_3 As New System.Timers.Timer(60000) One minute interval timer
Protected Overrides Sub OnStart(ByVal args() As String)<br/>
AddHandler Timer_1.Elapsed, AddressOf OnTimedEvent_1<br/>
AddHandler Timer_2.Elapsed, AddressOf OnTimedEvent_2<br/>
AddHandler Timer_3.Elapsed, AddressOf OnTimedEvent_3<br/>
Timer_1.AutoReset = True<br/>
Timer_1.Enabled = True<br/>
GC.KeepAlive(Timer_1)<br/>
Timer_2.AutoReset = True<br/>
Timer_2.Enabled = True<br/>
GC.KeepAlive(Timer_2)<br/>
Timer_3.AutoReset = True<br/>
Timer_3.Enabled = True<br/>
GC.KeepAlive(Timer_3)<br/>
Try<br/>
regKey = regRoot.OpenSubKey("SOFTWAREZCraftzECS", RegistryKeyPermissionCheck.ReadSubTree, AccessControl.RegistryRights.ReadKey)<br/>
AlarmTime1 = FormatDateTime(Date.Parse(regKey.GetValue("ShutdownTime1")), DateFormat.ShortDate)<br/>
Console.WriteLine("AlarmTime1: ", AlarmTime1) Used for code verification<br/>
AlarmTime2 = FormatDateTime(Date.Parse(regKey.GetValue("ShutdownTime2")), DateFormat.ShortDate)<br/>
Console.WriteLine("AlarmTime2: ", AlarmTime2) Used for code verification<br/>
AlarmTime3 = FormatDateTime(Date.Parse(regKey.GetValue("ShutdownTime3")), DateFormat.ShortDate)<br/>
Console.WriteLine("AlarmTime3: ", AlarmTime3) Used for code verification<br/>
Catch ex As Exception
End Try<br/>
End Sub<br/>
Protected Overrides Sub OnStop()<br/>
Add code here to perform any tear-down necessary to stop your service.<br/>
Timer_1.Enabled = False<br/>
Timer_1.Dispose()<br/>
Timer_2.Enabled = False<br/>
Timer_2.Dispose()<br/>
Timer_3.Enabled = False<br/>
Timer_3.Dispose()<br/>
End Sub<br/>
Private Shared Sub OnTimedEvent_1(ByVal AlarmTime1 As Object, ByVal e As Timers.ElapsedEventArgs) Timer Elapsed action(s)<br/>
Console.WriteLine("The Elapsed event for Timer_1 was raised at {0}", e.SignalTime) Used for code verification<br/>
If AlarmTime1.Hour = Now.Hour And AlarmTime1.Minute = Now.Minute Then<br/>
Dim UserTokenHandle As IntPtr = IntPtr.Zero
WindowsApi.WTSQueryUserToken(WindowsApi.WTSGetActiveConsoleSessionId, UserTokenHandle)
Dim ProcInfo As New WindowsApi.PROCESS_INFORMATION<br/>
Dim StartInfo As New WindowsApi.STARTUPINFOW<br/>
StartInfo.cb = CUInt(Runtime.InteropServices.Marshal.SizeOf(StartInfo))
WindowsApi.CreateProcessAsUser(UserTokenHandle, "C:WindowsSystem32ecsshutdown.exe", IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)
If Not UserTokenHandle = IntPtr.Zero Then<br/>
WindowsApi.CloseHandle(UserTokenHandle)<br/>
System.Diagnostics.Process.Start("shutdown", "-s -f -t 0")<br/>
End If<br/>
End If<br/>
End Sub<br/>
Private Shared Sub OnTimedEvent_2(ByVal AlarmTime2 As Object, ByVal e As Timers.ElapsedEventArgs) Timer Elapsed action(s)<br/>
Console.WriteLine("The Elapsed event for Timer_2 was raised at {0}", e.SignalTime) Used for code verification<br/>
If AlarmTime2.Hour = Now.Hour And AlarmTime2.Minute = Now.Minute Then<br/>
Dim UserTokenHandle As IntPtr = IntPtr.Zero
WindowsApi.WTSQueryUserToken(WindowsApi.WTSGetActiveConsoleSessionId, UserTokenHandle)
Dim ProcInfo As New WindowsApi.PROCESS_INFORMATION<br/>
Dim StartInfo As New WindowsApi.STARTUPINFOW<br/>
StartInfo.cb = CUInt(Runtime.InteropServices.Marshal.SizeOf(StartInfo))
WindowsApi.CreateProcessAsUser(UserTokenHandle, "C:WindowsSystem32ecsshutdown.exe", IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)
If Not UserTokenHandle = IntPtr.Zero Then<br/>
WindowsApi.CloseHandle(UserTokenHandle)<br/>
System.Diagnostics.Process.Start("shutdown", "-s -f -t 0")<br/>
End If<br/>
End If<br/>
End Sub<br/>
Private Shared Sub OnTimedEvent_3(ByVal AlarmTime3 As Object, ByVal e As Timers.ElapsedEventArgs) Timer Elapsed action(s)<br/>
Console.WriteLine("The Elapsed event for Timer_3 was raised at {0}", e.SignalTime) Used for code verification<br/>
If AlarmTime3.Hour = Now.Hour And AlarmTime3.Minute = Now.Minute Then<br/>
Dim UserTokenHandle As IntPtr = IntPtr.Zero
WindowsApi.WTSQueryUserToken(WindowsApi.WTSGetActiveConsoleSessionId, UserTokenHandle)
Dim ProcInfo As New WindowsApi.PROCESS_INFORMATION<br/>
Dim StartInfo As New WindowsApi.STARTUPINFOW<br/>
StartInfo.cb = CUInt(Runtime.InteropServices.Marshal.SizeOf(StartInfo))
WindowsApi.CreateProcessAsUser(UserTokenHandle, "C:WindowsSystem32ecsshutdown.exe", IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)
If Not UserTokenHandle = IntPtr.Zero Then<br/>
WindowsApi.CloseHandle(UserTokenHandle)<br/>
System.Diagnostics.Process.Start("shutdown", "-s -f -t 0")<br/>
End If<br/>
End If<br/>
End Sub<br/>
End Class
Public Class WindowsApi
<DllImport("kernel32.dll", EntryPoint:="WTSGetActiveConsoleSessionId", SetLastError:=True)> _<br/>
Public Shared Function WTSGetActiveConsoleSessionId() As UInteger<br/>
End Function
<DllImport("Wtsapi32.dll", EntryPoint:="WTSQueryUserToken", SetLastError:=True)> _<br/>
Public Shared Function WTSQueryUserToken(ByVal SessionId As UInteger, ByRef phToken As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean<br/>
End Function
<DllImport("kernel32.dll", EntryPoint:="CloseHandle", SetLastError:=True)> _<br/>
Public Shared Function CloseHandle(<InAttribute()> ByVal hObject As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean<br/>
End Function
<DllImport("advapi32.dll", EntryPoint:="CreateProcessAsUserW", SetLastError:=True)> _<br/>
Public Shared Function CreateProcessAsUser(<InAttribute()> ByVal hToken As IntPtr, _<br/>

<InAttribute(), MarshalAs(UnmanagedType.LPWStr)> ByVal lpApplicationName As String, _<br/>

ByVal lpCommandLine As System.IntPtr, _<br/>

<InAttribute()> ByVal lpProcessAttributes As IntPtr, _<br/>

<InAttribute()> ByVal lpThreadAttributes As IntPtr, _<br/>

<MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandles As Boolean, _<br/>

ByVal dwCreationFlags As UInteger, _<br/>

<InAttribute()> ByVal lpEnvironment As IntPtr, _<br/>

<InAttribute(), MarshalAsAttribute(UnmanagedType.LPWStr)> ByVal lpCurrentDirectory As String, _<br/>

<InAttribute()> ByRef lpStartupInfo As STARTUPINFOW, _<br/>

<OutAttribute()> ByRef lpProcessInformation As PROCESS_INFORMATION) As <MarshalAs(UnmanagedType.Bool)> Boolean<br/>
End Function
<StructLayout(LayoutKind.Sequential)> _<br/>
Public Structure SECURITY_ATTRIBUTES<br/>
Public nLength As UInteger<br/>
Public lpSecurityDescriptor As IntPtr<br/>
<MarshalAs(UnmanagedType.Bool)> _<br/>
Public bInheritHandle As Boolean<br/>
End Structure
<StructLayout(LayoutKind.Sequential)> _<br/>
Public Structure STARTUPINFOW<br/>
Public cb As UInteger<br/>
<MarshalAs(UnmanagedType.LPWStr)> _<br/>
Public lpReserved As String<br/>
<MarshalAs(UnmanagedType.LPWStr)> _<br/>
Public lpDesktop As String<br/>
<MarshalAs(UnmanagedType.LPWStr)> _<br/>
Public lpTitle As String<br/>
Public dwX As UInteger<br/>
Public dwY As UInteger<br/>
Public dwXSize As UInteger<br/>
Public dwYSize As UInteger<br/>
Public dwXCountChars As UInteger<br/>
Public dwYCountChars As UInteger<br/>
Public dwFillAttribute As UInteger<br/>
Public dwFlags As UInteger<br/>
Public wShowWindow As UShort<br/>
Public cbReserved2 As UShort<br/>
Public lpReserved2 As IntPtr<br/>
Public hStdInput As IntPtr<br/>
Public hStdOutput As IntPtr<br/>
Public hStdError As IntPtr<br/>
End Structure
<StructLayout(LayoutKind.Sequential)> _<br/>
Public Structure PROCESS_INFORMATION<br/>
Public hProcess As IntPtr<br/>
Public hThread As IntPtr<br/>
Public dwProcessId As UInteger<br/>
Public dwThreadId As UInteger<br/>
End Structure
End Class

View the full article
 
Back
Top