Remote Shutdown / Logoff Script using WMI

Have you ever been sitting at your desk working very hard trying to getting some business analytics report finished for your administrative team, only to be interrupted by the everyday user unable to log on the machine because someone else locked it. Then you have to get up and walk down there and manually login and unlock the workstation. Well this is now a thing of the past for you if you have enabled WMI and have a domain or common credentials on your network. This script will simply allow you to unlock a workstation with out getting up from your desk. Unfortunately, I didn’t write this script but I use it about every other day to unlock a workstation. It has a few good options to allow you to either Logoff / Reboot / Shutdown the workstation. This can also be helpful when the user has locked up the PC and can’t get it to restart, you can send a command from the workstation you are at for that one to restart. In way you end up using this script it will only save you time, I found it to be very reliable and super fast for resolving the locked computer situation. Also, please browse though the code as it is well commented and you can get a greater understanding of how it exactly works.

'|| Remote Shutdown.vbs
'||
'|| Created by Harvey Hendricks, MCSE, A+,
'|| March 2001
'||
'|| email: hhendrks@aramco.com
'|| hhend@swbell.net
'||
'||
'|| Based on techniques and ideas from:
'|| SMS admin, SMS Installer, & WMI forums -> http://www.myITforum.com/forums
'|| Win32 Scripting -> http://cwashington.netreach.net/
'|| Microsoft Windows Script Technologies -> http://msdn.microsoft.com/scripting
'|| Microsoft Online Library -> http://msdn.microsoft.com/library/default.asp
'|| Microsoft VBScript 5.5 documentation
'|| and Microsoft WMI SDK
'||
'||~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'|| SCRIPT LOGIC FLOW:
'|| Collects computername from user, calls function to ping the computername
'|| to determine if it is accessible, if not then display message and exit
'|| otherwise continue.
'|| Collects desired action to perform from the user, does error checking on
'|| the input to determine if it is acceptable, if not then display message
'|| and exit otherwise continue.
'|| Set variables and output messages based on the action chosen. Calls
'|| Win32Shutdown with the appropriate variable. Displays success message
'|| and exits
'||
'|| Uses WMI Win32Shutdown method from the Win32_OperatingSystem class
'|| to perform different logoff / powerdown / reboot functions
'||
'|| Testing found the following values to be effective on Win32Shutdown:
'|| Action decimal binary
'|| Logoff 0 0000
'|| Force Logoff 4 0100
'|| Reboot 2 0010
'|| Force Reboot 6 0110
'|| Powerdown 8 1000
'|| Force Powerdown 12 1100
'||
'|| Notice that the third bit from the right appears to be the "FORCE" bit.
'||
'|| A value of 1 will do a shutdown, ending at the "It is safe to turn
'|| off your computer" screen. I have no use for this and did not test it.
'||
'||
'||NOTES: - tested under Windows 2000 Pro. with ACPI compliant systems -
'|| SHOULD work under Windows NT4 without modification IF the
'|| system has compatible versions of WSH / WMI / VBscripting
'||
'||Logoff / Powerdown / Reboot:
'|| Does not work if a password protected screen saver is active or
'|| there is data to save. Either way the system waits for user input.
'||
'||Force Logoff / Force Powerdown / Force Reboot:
'|| Does not work if a password protected screen saver is active, will wait
'|| for user input. Otherwise will close open applications without saving data.
'||
'\/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


'/\/\/\/\/\/\/\/\/\/\/\/\/\/\ start function /\/\/\/\/\/\/\/\/\/\/\/\/\/'\/\/\/\/\/\/\/\/\/\/\/\/\/\/\______________/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
function Ping(byval strName)
dim objFSO, objShell, objTempFile, objTS
dim sCommand, sReadLine
dim bReturn

set objShell = WScript.CreateObject("Wscript.Shell")
set objFSO = CreateObject("Scripting.FileSystemObject")

'Set default return value
bReturn = false

'Create command line to ping and save results to a temp file
sCommand = "cmd /c ping.exe -n 3 -w 1000 " & strName & " > temp.txt"

'Execute the command
objShell.run sCommand, 0, true

'Get the temp file
set objTempFile = objFSO.GetFile("temp.txt")
set objTS = objTempFile.OpenAsTextStream(1)

'Loop through the temp file to see if "reply from" is found,
'if it is then the ping was successful
do while objTs.AtEndOfStream <> true
sReadLine = objTs.ReadLine
if instr(lcase(sReadLine), "reply from") > 0 then
bReturn = true
exit do
end if
loop

'Close temp file and release objects
objTS.close
objTempFile.delete
set objTS = nothing
set objTempFile = nothing
set objShell = nothing
set objFSO = nothing

'Return value
Ping = bReturn
end function
'/\/\/\/\/\/\/\/\/\/\/\/\/\/\ end function /\/\/\/\/\/\/\/\/\/\/\/\/\/'\/\/\/\/\/\/\/\/\/\/\/\/\/\/\______________/\/\/\/\/\/\/\/\/\/\/\/\/\/\/



'/\/\/\/\/\/\/\/\/\/\/\ Start Main body of script /\/\/\/\/\/\/\/\/\/\/\/'\/\/\/\/\/\/\/\/\/\/\/\_________________________/\/\/\/\/\/\/\/\/\/\/\/\/
'Get computer name to operate on
ComputerName=InputBox("Enter the Machine name of the computer" & vbCRLF _
& "you wish to Shutdown / Reboot / Logoff", _
"Remote Shutdown / Reboot / Logoff", _
"ComputerName")

'if Cancel selected - exit
If (ComputerName = "") Then Wscript.Quit

'change the name to uppercase
ComputerName=UCase(ComputerName)

'ping the computername to see if it is accessible
bPingtest = ping(Computername)

If bPingtest = FALSE Then
y = msgbox ("'" & ComputerName & "' is not accessible!" & vbCRLF _
& "It may be offline or turned off." & vbCRLF _
& "Check the name for a typo." & vbCRLF, _
vbCritical, ComputerName & " NOT RESPONDING")
Wscript.Quit
end IF

'Get the action desired
Action=InputBox( _
"Select Action to perform on " & ComputerName & vbCRLF & vbCRLF _
& " 1 - Logoff" & vbCRLF _
& " 2 - Force Logoff ( NO SAVE )" & vbCRLF _
& " 3 - Powerdown" & vbCRLF _
& " 4 - Force Powerdown ( NO SAVE )" & vbCRLF _
& " 5 - Reboot" & vbCRLF _
& " 6 - Force Reboot ( NO SAVE )" & vbCRLF & vbCRLF _
& "NOTE:" & vbCRLF _
& " Using Force will close windows" & vbCRLF _
& " without saving changes!", _
"Select action to perform on " & ComputerName, "")

'if Cancel selected - exit
If (Action = "") Then Wscript.Quit

'error check input
If (INSTR("1234567",Action)=0) OR (Len(Action)>1) then
y = msgbox("Unacceptable input passed -- '" & Action & "'", _
vbOKOnly + vbCritical, "That was SOME bad input!")
Wscript.Quit
end if

' set flag to disallow action unless proper input is achieved, 1 => go 0 => nogo
flag = 0

'set variables according to computername and action
Select Case Action
Case 1 'Logoff
x = 0
strAction = "Logoff sent to " & ComputerName
flag = 1
Case 2 'Force Logoff
x = 4
strAction = "Force Logoff sent to " & ComputerName
flag = 1
Case 3 'Powerdown
x = 8
strAction = "Powerdown sent to " & ComputerName
flag = 1
Case 4 'Force Powerdown
x = 12
strAction = "Force Powerdown sent to " & ComputerName
flag = 1
Case 5 'Reboot
x = 2
strAction = "Reboot sent to " & ComputerName
flag = 1
Case 6 'Force Reboot
x = 6
strAction = "Force Reboot sent to " & ComputerName
flag = 1
Case 7 'Test dialog boxes
y = msgbox("Test complete", vbOKOnly + vbInformation, "Dialog Box Test Complete")
flag = 0
Case Else 'Default -- should never happen
y = msgbox("Error occurred in passing parameters." _
& vbCRLF & " Passed '" & Action & "'", _
vbOKOnly + vbCritical, "PARAMETER ERROR")
flag = 0
End Select

'check flag
' if equal 1 (TRUE) then perform Win32Shutdown action on remote PC
' and display a confirmation message
' if not equal 1 (FALSE) then skip the action and script ends
if flag then
Set OpSysSet=GetObject("winmgmts:{(Debug,RemoteShutdown)}//" _
& ComputerName & "/root/cimv2").ExecQuery( _
"Select * from Win32_OperatingSystem where Primary=true")
for each OpSys in OpSysSet
OpSys.Win32Shutdown(x)
y = msgbox(strAction,vbOKOnly + vbInformation,"Mission Accomplished")
next
end If

'Release objects
set OpSys = nothing
set OpSysSet = nothing

Read More

Showing Active Directory Location

I have a very simple script for you today that will allow you to configure settings based on where a users and computers are within your Active Directory. This is very helpful when you are determining internet settings, file / printer connections and even desktop icons, but before you do all that you need a simple script to look up what your location / membership is in the directory. It will provide you with at path that is easily searched with string commands and can help diagnose why some users don’t get all the correct settings. This script returns to popup events, the first one gives you computer location: cn=nameofcomputer,ou=admin,dc=domain,dc=local and user location cn=username,ou=it,dc=domain,dc=local these are the strings you would search to determine who got which settings. Later I will show you how to use these settings to add icons, map drives, and map printers.

Set Network = WScript.CreateObject("WScript.Network")
Set objNetwork = CreateObject("WScript.Network") 
 compname = Network.ComputerName
 domname  = "domain"

 Set oNet = CreateObject("Wscript.Network")
 Set oTrans = CreateObject("NameTranslate")
 oTrans.Init 1, domname
 oTrans.Set 3, domname &"\"& compname &"$"
 sAdsPath = oTrans.Get(1)
 Set oNet = Nothing
 Set oTrans = Nothing
 sAdsPath = LCase(sAdsPath)
wscript.echo "Computer Location: " & sAdsPath


Set objNetwork = CreateObject("WScript.Network") 
Set objUser = CreateObject("ADSystemInfo")
Set CurrentUser = GetObject("LDAP://" & objUser.UserName)
colGroups = CurrentUser.memberOf
userlocation = lcase(objUser.UserName)

wscript.echo "User Location: "  & userlocation

Read More

Allow Users on Domain to Control Power Settings

In some domain environments you need to allow some control back to the users where they can manage it best. A perfect example of this is Power Settings, by default a normal domain user does not have the rights to control the power settings on the PC. This can lead to the computer turning off the monitor or going to standby at inopportune times. A way to solve this problem is by modifying the registry so any user authenticated / interactive user can modify these settings. To do this you need to use the regini.exe, it allows you to modify permissions in the registry from command line. Basically anything under registry key: (HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\) need to be given permissions to be modify by the user. Below I have included some code that needs to be placed in a text file for parameters to pass to regini.exe during workstation start up.

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\GlobalPowerPolicy [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\PowerPolicies [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\PowerPolicies\0 [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\PowerPolicies\1 [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\PowerPolicies\2 [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\PowerPolicies\3 [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\PowerPolicies\4 [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\PowerPolicies\5 [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\ProcessorPolicies [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\ProcessorPolicies\0 [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\ProcessorPolicies\1 [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\ProcessorPolicies\2 [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\ProcessorPolicies\3 [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\ProcessorPolicies\4 [1 5 7 11 17 21]
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Controls Folder\PowerCfg\ProcessorPolicies\5 [1 5 7 11 17 21]

Once you have this file made save it Machine Startup Scripts directory for Group Policy. Then add the following entry to the Group Policy (shown below) and the users should now be able to modify their computers power settings.

Regini.exe with Parameter
Regini.exe with Parameter

For more detail on parameters or what exactly regini.exe can do for you hop on over to Microsoft KB 237607.

Read More

List Local Accounts from Computers in Active Directory

When you finally take the plunge and decided that the only way to take your business to the next level is to setup a true client/server environment, here is a script to help you clean up those old accounts. When you convert to an Active Directory structure, you need to remove all the old local user accounts. This will reduce the security risks by removing accounts that you can’t force to conform to the rules setup by Group Policy. Also, if you were running these users as Administrators or Power Users and now have limited them down to a Standard user, without removing their old local accounts they may have elevated rights that they don’t need. Using this script you can query every computer in you Active Directory and get a list in CSV that you can use to know where that accounts are that need to be removed. In this script you can modify the output file so you can save the file where you want. You will also need to modify the Active Directory information to match your Domain configuration.

Tip: You can remotely connect other computers on your domain using “compmgmt.msc /computer:[remote computer]” from there you can manage user accounts in Local Users and Groups.

Const ADS_SCOPE_SUBTREE = 2

Set objConnection = CreateObject("ADODB.Connection")
Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "MYDomainController" 'put domain controller here

Set objCOmmand.ActiveConnection = objConnection
objCommand.CommandText = _
    "Select Name, Location from LDAP://DC=subdomain,DC=zim,DC=local' " _  'update this with your AD information
        & "Where objectClass='computer'"  
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 
Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst

Do Until objRecordSet.EOF
	LocalUsers objRecordSet.Fields("Name").Value, "C:\localaccounts.csv" 'adjust output file name as needed
    objRecordSet.MoveNext
Loop

Sub LocalUsers(strComputer, strFilename)
	On Error Resume Next
	Set StdOut = WScript.StdOut
	 
	Set objFSO = CreateObject("scripting.filesystemobject")
	Set logStream = objFSO.opentextfile(strFilename, 8, True)
	 
	Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\default:StdRegProv")
	If Err.Number Then
	      logStream.writeline(strComputer & ",Offline")
	      Err.Clear
	Else
		Set colAccounts = GetObject("WinNT://" & strComputer)
		colAccounts.Filter = Array("user")

		For Each objUser In colAccounts
		        logStream.writeline(strComputer & ",Online," & objUser.Name & "," & objUser.AccountDisabled) 
		Next
	End If

	logStream.Close
End Sub

Read More

Remove Old Windows Updates Automatically using Logoff Script

This is a great script that helps you keep those patched boxes on your network running longer and faster. This script checks to see how old the Microsoft Windows Update Uninstall folders are and deletes them based on a parameter in the script. This reduces clutter on your PC and reduces one of the major disk hogs in a corporate environment. This script should be included in the Computers Group Policy so it has Administrative access to the PC so it can actually remove the files.

Set oShell = CreateObject("Wscript.Shell")
strWindows = oShell.ExpandEnvironmentStrings("%WINDIR%")

On Error Resume Next
Set fsoFolder = CreateObject("Scripting.FileSystemObject")

Set objFolder = fsoFolder.GetFolder(strWindows)
Set colSubfolders = objFolder.Subfolders

For Each objSubfolder in colSubfolders
	If (DateDiff("D", objSubfolder.DateCreated, Date()) > 90) AND ((Left(objSubfolder.Name,3)) = "$Nt") then
		fsoFolder.DeleteFolder strWindows & "\" & objSubfolder.Name, TRUE
	End If
Next

Read More