4/06/2011

Switch from Local System to User context

Sometimes there’s a need to switch from Local System context to the current logged on User.
The following article describes how to achieve this.

In short words the following happens:
1. Something is executed in local system context
2. At the end a EventLog entry is written
3. A Scheduled Tasks gets trigged by the created EventLog entry
4. The Scheduled Tasks which is running in User context executes another script

One example is e.g. to inform Users about an Installation which was executed from the Local System Account. The Application Deployment process executes the CreateEventToInform.vbs Script at the end of the installation to create the EventLog entry for informing the User

CreateEventToInform.vbs
  1. Dim objShell : Set objShell = CreateObject("WScript.Shell")  
  2. Dim strMessage : strMessage = "Dear User this is a message from your local system"  
  3. objShell.LogEvent(4, strMessage)  


InformUser.vbs
  1. Dim strMessage  
  2. Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & "."  
  3. "\root\cimv2")  
  4. Set colLoggedEvents = objWMIService.ExecQuery("Select * from Win32_NTLogEvent Where Logfile = 'Application' and SourceName='WSH' and EventCode=4 and Type='Information'")  
  5.   
  6. For Each objEvent In colLoggedEvents  
  7. strMessage = objEvent.Message  
  8. Exit For  
  9. Next  
  10.   
  11. MsgBox(strMessage, vbInformation + vbOKOnly, "Your Company")  


It could also be used as an immediately executed “ActiveSetup” for the current logged User. The Application Deployment process executes the CreateEventToExecute.vbs Script at the end of the installation to create the EventLog entry for performing a Active Setup for the current User

CreateEventToExecute.vbs
  1. Dim objShell : Set objShell = CreateObject("WScript.Shell")  
  2. Dim strCommandLine : strCommandLine = "msiexex /fup <msi>"  
  3. objShell.LogEvent(4, strCommandLine)  
  4. </msi>  


ExecuteUserPart.vbs
  1. Dim objShell : Set objShell = CreateObject("Wscript.Shell")  
  2. Dim strCommandLine  
  3. Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & "." & "\root\cimv2")  
  4. Set colLoggedEvents = objWMIService.ExecQuery("Select * from Win32_NTLogEvent Where Logfile = 'Application' and SourceName='WSH' and EventCode=4 and Type='Information'")  
  5.   
  6. For Each objEvent In colLoggedEvents  
  7. strCommandLine = objEvent.Message  
  8. Exit For  
  9. Next  
  10.   
  11. objShell.Run(strCommandLine, 1, False)  


To make the whole think work we have to create a trigger which reacts to the EventLog Entry which was created. Create a Scheduled Tasks which is executed in the User context as listed below for this

Note: You can deploy scheduled tasks to many computer automatically e.g. with Group Policies

Now as soon as the EventID is written the Scheduled Tasks executes the below listed command



Further thoughts:
You could create a whole Application which is written variable so that you can perform different actions in User context. To achieve this easily you could tag the EventLog Message with specific keywords. Later the Application parses the EventLog Message and you can react on this. So you can use it for different scenarios. Example:

WriteEventLog.vbs
  1. Dim objShell : Set objShell = CreateObject("WScript.Shell")  
  2. Dim strMessage : strMessage = "[Inform]Dear User now there's happening something" &vbNewLine &"[Execute]msiexex /fup <msi>"  
  3. objShell.LogEvent 4, strMessage  
  4. </msi>  


PerformInUserContext.vbs
  1. Dim objShell : objShell = CreateObject("Wscript.Shell")  
  2. Dim strMessage, arrEventEntry  
  3. Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & "." & "\root\cimv2")  
  4. Set colLoggedEvents = objWMIService.ExecQuery("Select * from Win32_NTLogEvent Where Logfile = 'Application' and SourceName='WSH' and EventCode=4 and Type='Information'")  
  5.   
  6. For Each objEvent In colLoggedEvents  
  7. strMessage = objEvent.Message  
  8. Exit For  
  9. Next  
  10.   
  11. arrEventEntry = Split(strMessage, vbNewLine)  
  12.   
  13. For Each strLine In arrEventEntry  
  14. If InStr(strLine, "[Inform]"Then  
  15. MsgBox(Replace(strLine, "[Inform]"""))  
  16. ElseIf InStr(strLine, "[Execute]"Then  
  17. objShell.Run(Replace(strLine, "[Execute]"""), 1, False)  
  18. End If  
  19. Next  

No comments: