.net 創建計划任務開機后自動以管理員身份啟動運行 win7 ~ win10


假如要啟動 this.exe。以下邏輯中會啟動先后關聯啟動三個實例分別是ABC。先啟動第一個實例A,A啟動實例B,B啟動實例C.

要求:

1.如果沒有以管理員權限運行,則請求管理員權限運行,即使沒有請求成功或請求成功之前,也要先以非管理員權限運行,因為它定時要執行一些任務,不能因阻塞而錯過。

2.如果沒有以管理員權限運行,也要可以動態申請以管理員權限來注冊開機啟動,然后托盤顯示右鍵菜單指示是否已經設置開機啟動。

3.支持Windows XP 到 Windows 10.

4.自啟過程無需人工干預,全自動無阻塞。

5.不能關閉UAC,如果這個都關了,我們就不用討論了。

要實現以上3點,其實並不容易,XP容易實現自不必說,從Vista開始就不那么容易了。

有兩個難點:

1. 以管理員身份開機自啟。注冊表實現不了,啟動菜單目錄也實現不了。因為即使設置了程序的兼容性以管理員身份運行,但彈出的那個UAC確認框誰來點呢?據我所知,用計划任務是目前唯一可以實現以管理員身份啟動並且不需要UAC確認的。

2. 當以非管理員身份運行時,動態申請管理員權限,當然這個是需要UAC確認的。

用來做一些人工設置的時候,這時候人是在電腦旁邊的。比如設置開機自啟,取消開機自啟。

這個解決方案比較簡單,實例A用RunAs方式申請管理員權限啟動一個新實例B,傳入命令行參數,B執行完自動結束。即使申請啟動失敗,A也可以繼續存活,想要申請過程無阻塞就新開一個線程來做。

但有一個問題,B有沒有啟動成功?用戶有沒有在UAC確認時允許?即使是用戶確認了,B成功在計划任務創建了開機以管理員身份啟動。但是A依然無法判斷是否成功設置了開機自啟,托盤無法正確的為用戶指示開機自啟狀態。有人會說查詢一下計划任務里有沒有我們創建的任務就行了,很可惜,因為A沒有管理員權限,所以無法查詢。

我其實也搞不懂,微軟為什么查詢計划任務都需要管理員權限。

既然B都有管理員權限了,它返回一個ExitCode不就行了。當然這樣可以,但是開機自啟是敏感操作,很可能被殺軟干掉,這樣我們的開機自啟狀態指示就變得不可靠。

有一個辦法,B既然已經有了管理員權限,讓它啟動一個C,C就是一個完全有管理員權限的實例,B自我關閉,返回一個ExitCode給A,A收到通知也關閉,一切不就解決了嘛。這就是我的方案。

當然也可以不啟動C,B關閉A,B繼續以管理員權限運行,但是如何返回狀態給A讓A自我結束,或者B干掉A,就不是一個ExitCode可以解決的了,通訊或查找程序可能變得復雜。

下面附上創建、查詢、刪除計划任務的VB.NET代碼:

Public Class Form1
    Private Const TASK_TRIGGER_LOGON = &H9
    Private Const TASK_ACTION_EXEC = &H0
    Private Const TASK_CREATE = &H2
    Private Const TASK_CREATE_OR_UPDATE = &H6
    Private Const TASK_RUNLEVEL_HIGHEST = &H1
    Private Const TASK_LOGON_GROUP = &H4
    Private Const TASK_LOGON_NONE = &H0

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load


    End Sub

    Public Function CreateOrUpdateTask(ByVal strTaskName As String, ByVal strAuthor As String, ByVal strTaskDescription As String, ByVal strPath As String, ByVal strWorkingDir As String, Optional ByVal strArguments As String = "", Optional ByVal bUseHighestSecLevel As Boolean = True) As Long
        Dim objService As Object
        objService = CreateObject("Schedule.Service")
        objService.Connect()

        Dim objTaskFolder As Object
        objTaskFolder = objService.GetFolder("\")

        Dim objTaskDef As Object
        objTaskDef = objService.NewTask(0)

        Dim objPrincipal As Object
        objPrincipal = objTaskDef.principal
        With objPrincipal
            .LogonType = 1
            .RunLevel = TASK_RUNLEVEL_HIGHEST
        End With

        Dim colTriggers As Object
        Dim objTrigger As Object
        Dim colActions As Object
        Dim objAction As Object
        Dim objInfo As Object
        Dim objSettings As Object
        colTriggers = objTaskDef.Triggers
        objTrigger = colTriggers.Create(TASK_TRIGGER_LOGON)
        objTrigger.Enabled = True
        colActions = objTaskDef.Actions
        objAction = colActions.Create(TASK_ACTION_EXEC)
        objAction.Path = strPath
        objAction.WorkingDirectory = strWorkingDir
        objAction.Arguments = strArguments
        objInfo = objTaskDef.RegistrationInfo
        objInfo.Author = strAuthor
        objInfo.Description = strTaskDescription
        objSettings = objTaskDef.Settings
        With objSettings
            .Enabled = True
            .Hidden = False
            .StartWhenAvailable = True
            .DisallowStartIfOnBatteries = False
            .StopIfGoingOnBatteries = False
            .AllowHardTerminate = False
        End With

        Try
            If bUseHighestSecLevel Then
                objTaskFolder.RegisterTaskDefinition(strTaskName, objTaskDef, TASK_CREATE_OR_UPDATE, "Administrators", , TASK_LOGON_GROUP)
            Else
                objTaskFolder.RegisterTaskDefinition(strTaskName, objTaskDef, TASK_CREATE_OR_UPDATE, , , TASK_LOGON_NONE)
            End If
        Catch ex As Exception
            Return Err.Number
        End Try

        CreateOrUpdateTask = 0
        objService = Nothing
        objInfo = Nothing
        objTaskFolder = Nothing
        objTaskDef = Nothing
        objPrincipal = Nothing
    End Function

    Public Function DeleteTask(ByVal strTaskName As String) As Long
        Dim objService As Object
        Dim objTaskFolder As Object

        Try
            objService = CreateObject("Schedule.Service")
            objService.Connect()
            objTaskFolder = objService.GetFolder("\")
            objTaskFolder.DeleteTask(strTaskName, 0)
        Catch ex As Exception
            Return Err.Number
        End Try

        objService = Nothing
        objTaskFolder = Nothing
        DeleteTask = 0
    End Function

    Public Function TaskAvailable(taskName) As Boolean
        Dim service = CreateObject("Schedule.Service")
        Call service.Connect()

        ' Get the task folder that contains the tasks. 
        Dim rootFolder
        rootFolder = service.GetFolder("\")

        Dim taskCollection
        taskCollection = rootFolder.GetTasks(0)

        Dim numberOfTasks
        numberOfTasks = taskCollection.Count

        If numberOfTasks = 0 Then
            Debug.Print("No tasks are registered.")
        Else
            Debug.Print("Number of tasks registered: " & numberOfTasks)

            Dim registeredTask
            For Each registeredTask In taskCollection
                Dim name As String = registeredTask.Name
                Debug.Print("Task Name: " & name)
                Dim taskState
                Select Case registeredTask.State
                    Case "0"
                        taskState = "Unknown"
                    Case "1"
                        taskState = "Disabled"
                        If (name = taskName) Then
                            TaskAvailable = False
                            Exit Function
                        End If
                    Case "2"
                        taskState = "Queued"
                    Case "3"
                        taskState = "Ready"
                    Case "4"
                        taskState = "Running"
                    Case Else
                        taskState = "Unknown"
                End Select
                If (name = taskName) Then
                    TaskAvailable = True
                    Exit Function
                End If
                Debug.Print("    Task State: " & taskState)
            Next
        End If
        TaskAvailable = False
    End Function

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        MsgBox(CreateOrUpdateTask("Test", Interaction.Environ("USERDOMAIN") & "\" & Interaction.Environ("USERNAME"), "a Test Task", Application.ExecutablePath, Application.StartupPath, "", True))
    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        MsgBox(DeleteTask("Test"))
    End Sub
End Class

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM