The way this works is that it assumes the web page (running on a trusted intranet server) takes user input via a form and then evokes some sort of modification to the user account in Active Directory via an LDAP expression. As an example, I'm using an account attribute called "customAttrib" and checking if it is empty (is-null or empty-string) or contains a string value (more than one character). If the value is empty, the web form is launched and the script waits until the user closes the IE session. It doesn't matter how many other IE windows or tabs are open. It fetches the processID for the one it launches and watches to see when it vanishes from the process stack (using a do-while loop). When the process is closed, the script continues and simply re-checks the attribute to see if it was modified. The end-game being that it checks if the user successfully completed the form, or simply closed it and tried to ignore it (bad news for the user). Enjoy!
'****************************************************************
' Filename..: IE_Wait.vbs
' Author....: skatterbrainz.blogspot.com (you know who)
' Date......: 02/23/2011
' Purpose...: launch web page and wait for it to close
'****************************************************************
' comment: check for previous attrib in AD (LDAP query)
' comment: launch ie and navigate to the web page
' comment: check AD again to see if user completed the form
' comment: if not, force a logoff
'****************************************************************
Const enableLogoff = True
Const dndc = "LDAP://DC=contoso,DC=msft"
'----------------------------------------------------------------
' comment: DO NOT MODIFY ANY CODE BELOW THIS POINT!!!
'----------------------------------------------------------------
Const ADS_SCOPE_SUBTREE = 2
Const SW_HIDE = 0
Const SW_NORMAL = 1
Const SW_SHOWMINIMIZED = 2
Const SW_SHOWMAXIMIZED = 3
Const wbemFlagForwardOnly = 32
Const wbemFlagBidirectional = 0
Const wbemFlagReturnImmediately = 16
Const wbemFlagReturnWhenComplete = 0
Const wbemQueryFlagPrototype = 2
Const wbemFlagUseAmendedQualifiers = 131072
Const osLogoff = 0
Const osForcedLogoff = 4
Const osShutdown = 1
Const osForcedShutdown = 5
Const osRestart = 2
Const osForcedRestart = 6
Const strCommand = "C:\Program Files\Internet Explorer\iexplore.exe http://intranet.contoso.msft/stuff"
Dim wshNetwork, uid, objShell, groupPriority, wmi_flags
wmi_flags = wbemFlagForwardOnly + wbemFlagReturnImmediately
Set wshNetwork = CreateObject("Wscript.Network")
Set objShell = CreateObject("Wscript.Shell")
uid = wshNetwork.UserName
Set wshNetwork = Nothing
custVal = GetAttribute(uid, "customAttrib")
If IsNull(groupPriority) Then
LaunchWebForm()
custVal = GetAttribute(uid, "customAttrib")
If IsNull(custVal) Then
MsgBox "Form was not filled out properly!" & _
vbCRLF & "You will now be logged off...", vbOkOnly+vbCritical, "Web Form"
If enableLogoff = True Then
Logoff()
End If
End If
End If
Sub LaunchWebForm()
Dim objWMIService, objStartup, objConfig, objProcess
Dim intReturn, query, colItems, objItem, intProcessID
Dim colMonitoredProcesses, objLatestProcess, processEnded
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\.\root\cimv2")
' comment: configure the new process as visible
Set objStartup = objWMIService.Get("Win32_ProcessStartup")
Set objConfig = objStartup.SpawnInstance_
objConfig.ShowWindow = SW_NORMAL
' comment: create a new process (iexplore.exe)
Set objProcess = objWMIService.Get("Win32_Process")
intReturn = objProcess.Create(strCommand, Null, objConfig, intProcessID)
If intReturn <> 0 Then
'wscript.echo "fail: unable to launch process!"
wscript.quit(1)
End If
'wscript.echo "info: process id is " & intProcessID
Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
query = "SELECT ProcessId FROM Win32_Process WHERE ProcessId='" & intProcessID & "'"
Set colItems = objWMIService.ExecQuery(query,,wmi_flags)
For Each objItem in colItems
intProcessID = objItem.ProcessId
Next
If intProcessID <> "" Then
'wscript.echo "info: waiting for process terminate..."
Set colMonitoredProcesses = objWMIService.ExecNotificationQuery _
("Select * From __InstanceDeletionEvent Within 1 Where TargetInstance ISA 'Win32_Process'")
Do Until processEnded = True
Set objLatestProcess = colMonitoredProcesses.NextEvent
If objLatestProcess.TargetInstance.ProcessID = intProcessID Then
processEnded = True
End If
Loop
If processEnded = True Then
'wscript.echo "info: process was terminated"
End If
Else
'wscript.echo "fail: unable to obtain process id..."
End If
End Sub
'----------------------------------------------------------------
' function: get LDAP user attribute from AD
'----------------------------------------------------------------
Function GetAttribute(uid, att)
Dim query, objConnection, objCommand, objRecordSet, retval
On Error Resume Next
query = "SELECT " & att & " FROM '" & dndc & "' " & _
"WHERE objectCategory='user' AND sAMAccountName='" & uid & "'"
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
objCommand.CommandText = query
Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
retval = objRecordSet.Fields(att).value
objRecordSet.MoveNext
Loop
GetAttribute = retval
End Function
'----------------------------------------------------------------
' function: force logoff from local computer
'----------------------------------------------------------------
Function Logoff()
Logoff = -1
wscript.Echo "Logging off..."
On Error Resume Next
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate,(Shutdown)}!\\.\root\cimv2")
Set colOs = objWMI.ExecQuery("Select * from Win32_OperatingSystem")
If err.Number = 0 Then
For Each objOs in colOs
' See: http://msdn.microsoft.com/en-us/library/aa394058(VS.85).aspx
Logoff = objOs.Win32Shutdown(osForcedLogoff,0)
' WScript.Echo objOs.Name
Next
End If
End Function
1 comment:
Hi David,
Great script! It's the only one I can find to monitor and wait until a command is done before it moves on. :)
However, one little problem: it isn't waiting in my script. It shows me the process ID but nothing more.
I added some debug echoes and confirm it gets here:
If intProcessID <> "" Then
It also executes the echo statement(s) next, but it does not seem to go past the next line:
Set colMonitoredProcesses = objWMIService.ExecNotificationQuery _
& ("Select * From __InstanceDeletionEvent Within 1 Where TargetInstance ISA 'Win32_Process'")
Any ideas what I could be doing wrong?
Post a Comment