Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Script Doesn't Always Complete Successfully

Status
Not open for further replies.

Phylum

IS-IT--Management
Aug 16, 2004
36
US
I've written a script that runs via a Scheduled Task under a user account that has full local admin privileges on all workstations and sufficient access in AD. When I initially tested the script, I ran it as a normal user account that also had full local admin privileges but very limited AD access, yet it ran fine. (The script doesn't rely on or access AD at all actually.) However I've found that when its run via the Scheduled Task it doesn't always complete successfully and I don't know why.

I suspect it has to do with the state the machine is in. I want it to be able to run regardless of the system state:
[ul]
[li]a user logged on locally & actively working[/li]
[li]a user logged on locally but screen locked[/li]
[li]a user logged on remotely & actively working[/li]
[li]a user logged on remotely but screen locked[/li]
[li]at the login screen with no user logged on[/li]
[/ul]

What am I trying to accomplish? Its actually very simple really: to perform a specific type of reboot depending on whether or not the system is being used. My thought process is as follows:
[ul]Script checks for local users:
[li]If found: Run shutdown with the appropriate switches to give them a warning.[/li]
[li]If not found: Check for remote users.[/li]
[ul]
[li]If found: Run shutdown with the appropriate switches to give them a warning.[/li]
[li]If not found: Shutdown the workstation immediately.[/li]
[/ul]
[/ul]

Most of the machines stalled on the local user check, never making it to the remote user check.
On others it got past the local & remote user checks (not sure why) but never rebooted.

So I'm mainly wondering if there are restrictions as to what WMI functions are not exposed or are otherwise not available depending on the state of the machine or who is trying to access it.

Code:
This code I'm using is a mash-up of code acquired from various sources. and while it works when run manually or run under the current user's context, I've seen inconsistent results when run via Scheduled Task.
Code:
Function UpdateReboot

	If (DetectLocalLoggedOnUser) or (DetectRemoteLoggedOnUser) Then
		Dim f_iRestartDelaySeconds, f_iRestartDelayMinutes
		
		f_iRestartDelaySeconds = 900
		f_iRestartDelayMinutes = f_iRestartDelaySeconds / 60
		
		wscript.echo "User Detected - Notifying user via 'shutdown' & restarting computer in " & f_iRestartDelayMinutes & " minutes (" & f_iRestartDelaySeconds & " seconds)."
		wso.Run "cmd /c shutdown -r -f -t " & f_iRestartDelaySeconds & " -c ""COMPUTER UPDATED!  Your computer was recently updated & will reboot in " & f_iRestartDelayMinutes & " minutes!  Please save your work & prepare for a restart!"""
	Else
		wscript.echo "No User(s) Detected - Forcing Immediate Shoutdown"
		
		Dim f_oWMIService, f_colOperatingSystem, f_oOperatingSystem
		
		Set f_oWMIService = GetObject("winmgmts:{impersonationLevel=impersonate, (RemoteShutdown)}!\\.\root\cimv2")

		Set f_colOperatingSystem = f_oWMIService.ExecQuery("Select * from Win32_OperatingSystem")
		'Set f_colOperatingSystem = f_oWMIService.ExecQuery("Select * from Win32_OperatingSystem where Primary=true")
    
		For Each f_oOperatingSystem in f_colOperatingSystem
			'Value		Meaning
			'0 (0x0)	Log Off
			'4 (0x4)	Forced Log Off (0 + 4)
			'1 (0x1)	Shutdown
			'5 (0x5)	Forced Shutdown (1 + 4)
			'2 (0x2)	Reboot
			'6 (0x6)	Forced Reboot (2 + 4)
			'8 (0x8)	Power Off
			'12 (0xC)	Forced Power Off (8 + 4)
			f_oOperatingSystem.Win32Shutdown(6)
			'f_oOperatingSystem.Reboot()
	    	Next

	End If
End Function

Function DetectLocalLoggedOnUser
	Dim f_oWMIService, f_colComputer, f_oComputer, f_sLoggedOn, f_sUserName
	
	'Get currently logged on user's username (local)
	Set f_oWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
	Set f_colComputer = f_oWMIService.ExecQuery("Select * from Win32_ComputerSystem")

	For Each f_oComputer in f_colComputer
		If IsNull(f_oComputer.UserName) Then 'If no one is logged On
    			f_sLoggedOn=False
		        f_sUserName=f_oComputer.Username
	    	Else
        		f_sLoggedOn=True
        		f_sUserName=f_oComputer.Username
		End If
	Next

	DetectLocalLoggedOnUser=f_sLoggedOn
End Function

Function DetectRemoteLoggedOnUser
	Dim f_oWMIService, f_colSessions, f_oSession, f_sLoggedOn, f_sUserName
	
	Set f_oWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
	Set f_colSessions = f_oWMIService.ExecQuery("Select * from Win32_LogonSession Where LogonType = 10")
	
	If (f_colSessions.Count = 0) Then
		f_sLoggedOn=False
	Else
		If (f_colSessions.Count = 1) Then debuglog f_colSessions.Count & "Remote User Detected!"
		If (f_colSessions.Count > 1) Then debuglog f_colSessions.Count & "Remote Users Detected!"
		
		Dim f_colList, f_oItem
		
		For Each f_oSession in f_colSessions
			Set f_colList = f_oWMIService.ExecQuery("Associators of {Win32_LogonSession.LogonId=" & f_oSession.LogonId & "} Where AssocClass=Win32_LoggedOnUser Role=Dependent" )
			for each f_oItem In f_colList
				f_sLoggedOn=True
	    		next
		Next
	End If
	
	DetectRemoteLoggedOnUser = f_sLoggedOn
End Function
 
Thanks for the response Geates.

As I mentioned before, the user has full local admin rights and more than enough AD rights. As for the 'start' in directory, the script resides in a directory on the local machine which the user has full access to.

I forgot to add two things:

I added a secondary 'shutdown' command just after the 'No User(s) Detected - Forcing Immediate Shoutdown' text is displayed which in some cases, that doesn't seem to actually reboot the machine.
Code:
wso.Run "cmd /c shutdown -r -f -t 30 -c ""COMPUTER UPDATED!  Your computer was recently updated & will reboot IMMEDIATELY!"""

In every case, however the script executes successfully as the log file is created or updated on every execution. I don't understand why its hit or miss.
Is there anything I can add to the functions to get an idea as to why it may be failing? Maybe an 'on error resume next' then check for an error 'if err.number <> 0' ?
 
A bit of semantics but 30 secs is not immediately :)

OERN might work to narrow things down but, personally, I would not use it.

It's possible, the script is always executed but runs into a circustance where it cannot complete. I would monitor Task Manager to see how wscript.exe is behaving. Perhaps you should have pause the script (a msgbox) until the machine has completely loaded, then run it. Any difference?

-Geates

 
Happy Monday to you Geates - I hope you had a pleasant weekend.
Thanks also again for the reply.

Hah yeah its not immediate - I wanted to give the user notice *just in case* - there's a 'shutdown -a' script they can execute in an emergency situation. :) I tried to add that as a fail safe in the event the other part (f_oOperatingSystem.Win32Shutdown(6)) failed.

It might help if I shed a bit more light about what this script does!
[ul]
[li]The script is scheduled to run at 2AM local time. So presumably the system is on and has been on for some time.[/li]
[li]The script triggers the Windows Update Agent (WUA) agent to query the WSUS server, download & install any approved Windows Updates.[/li]
[li]The script determines whether or not a reboot is required depending on either the argument issued when run (/reboot) or if the installed update(s) require a reboot.[/li]
[ul][li]If yes, then it calls the updatereboot function (or technically sub).[/li][/ul]
[/ul]

This statement is completely accurate:
Geates said:
It's possible, the script is always executed but runs into a circustance where it cannot complete.
And that's what I'm trying to figure out: Under what circumstances would (might) the script fail? Why might the
[ul]
[li]'cmd /c shutdown...' command fail or execute but not reboot?[/li]
[li]'f_oOperatingSystem.Win32Shutdown(6)' command fail?[/li]
[li]detect users functions fail?[/li]
[/ul]

I'm hoping to come up with some ideas to add more verbose logging to the script so that I can see exactly where it failed. For instance, I believe in one situation I had some 'logging' surrounding statements like these
Code:
...
	wscript.echo "preparing to set f_oWMIService..."
	Set f_oWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
	wscript.echo "successfully set f_oWMIService!"

	wscript.echo "preparing to set f_colComputer..."
	Set f_colComputer = f_oWMIService.ExecQuery("Select * from Win32_ComputerSystem")
	wscript.echo "successfully set f_colComputer!"
...
But I never saw an entry in the log stating it 'successfully set f_colComputer'. So in that situation, why might the script not be able to do that? And of course I'm asking the same questions for other areas of the script. I suppose the next step is to do something like this:
Code:
...
	wscript.echo "preparing to set f_oWMIService..."
	on error resume next
	Set f_oWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
	if (err.number<>0) then
		wscript.echo "Error " & err.number & " setting f_oWMIService: ' & err.description
		err.clear
	end if
	on error goto 0
	wscript.echo "successfully set f_oWMIService!"

	wscript.echo "preparing to set f_colComputer..."
	on error resume next
	Set f_colComputer = f_oWMIService.ExecQuery("Select * from Win32_ComputerSystem")
	if (err.number<>0) then
		wscript.echo "Error " & err.number & " setting f_colComputer: ' & err.description
		err.clear
	end if
	on error goto 0
	wscript.echo "successfully set f_colComputer!"
...
 
Ohh and one more thing, something I touched on before: The script runs at 2AM but we won't necessarily know the state of the machine. We won't know if its locked (not used), unlocked (actively used) or just sitting at the login screen. The script should execute under any of those circumstances.
 
Logging is a great idea. So is, what I call, "Dark Logging" (This term is an excellent candidate for a semantics debate!)

Essentially, comment out everything and execute as intended. One at a time, add the commented lines back in the script and execute it again. Keep doing this until the error is more evident.

I've had a similar problem (where it works for me and user X but not for anyone else when launched by the system). I wasn't able to figure out the cause until I did some dark logging. Sorry I can't offer much else.

Perhaps start with
Code:
Function UpdateReboot

	If (DetectLocalLoggedOnUser) or (DetectRemoteLoggedOnUser) Then
		wscript.echo "User Detected - Notifying user via 'shutdown' & restarting computer in " & f_iRestartDelayMinutes & " minutes (" & f_iRestartDelaySeconds & " seconds)."
	Else
		wscript.echo "No User(s) Detected - Forcing Immediate Shoutdown"
	End If
End Function

-Geates

PS: If there already is a term for "Dark Logging", please let me know so I don't sound like and idiot :)

 
Geates said:
If there already is a term for "Dark Logging", please let me know so I don't sound like and idiot :)

Debugging?
 
Geates: If you use debugging tools (which I have not done with VBScript), it would be called "stepping through the code
 
Phylum: Your logic seems sound, and debugging / logging is a good idea. You might also check the event log for the machines that stop responding to your script, maybe there is a clue there. If you know which user was using the machine, it can't hurt to ask them what they were doing at the time.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top