Power Off Unused PCs

Author Message
TomRiddle

  • Total Posts : 620
  • Scores: 12
  • Reward points : 0
  • Joined: 2/7/2008
  • Location: Australia
  • Status: offline
Power Off Unused PCs Wednesday, July 01, 2009 1:23 AM (permalink)
0

Use this script and be rewarded for helping your company implement their green IT visions.

 
 'Script by tomriddle 2009
 'Power Saving Script
 
 'GreenNights.vbs
 
 
 
 'Run this script as a scheduled task against all domain workstations at night. 
 'checks target computer is not a server and optionally not in a certain IP range, 
 'has protection against users inadvertently clicking on script directly shutting down computers during the day. 
 'Script gets it's list of computers to shutdown by reading members of an Active Directory OU and sub OUs
 'If logged on, screensaver active 20 minutes and is not a member of exclude list, shutdown cmd is sent. 
 'or If logged off and is not a member of exclude list, shutdown cmd is sent. 
 'both users and computers can be added to the exclude group
 'creates a comprehensive log file to examine the following morning. 
 
 
 'Notes:- 
 'if a user leaves a document open on a computer over night, then that document will be lost. 
 'Screen savers need to be enforced with grouppolicy for that check to be used effectively. 
 'With positive publicity before implementing offering users an opt out, reception is good. 
 'We timed the full implementation of this script with Earth Hour with great success. 
 'No complaints from users. 
 
 
 'usage:-
 'set scheduled task to run from a server at night. 
 'run command:- cscript.exe script.vbs
 
 
 
 
 
 'Variables that can be changed
    ScreenSaverTime=20  'Time screen saver has been left on in minutes before script acts on computer. 
    strServer="\\server\share\"  'location where script is stored - change to your server
    strLog=strServer&"done.txt" 'list of computers that have been acted upon. 
    GShutDownSkip = "cn=GShutDownSkip,OU=Groups,dc=domain,dc=com"   'change to your domain
    GShutDownPilot = "cn=GShutDownPilot,OU=Groups,dc=domain,dc=com"
 
 
    If Not WScript.FullName = WScript.Path & "\cscript.exe" Then 
       msgbox "!!! WARNING !!!" &vbcrlf&vbcrlf& "YOU ARE NOT TO MANUALLY RUN THIS SCRIPT" &vbcrlf& "AS IT TURNS OFF MACHINES ON THE DOMAIN" 
       wscript.quit
    end if
 
 
 'Enumerate ALL 'Computer' Accounts in Active Directory
    Const ADS_SCOPE_SUBTREE = 2
 
    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand =   CreateObject("ADODB.Command")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Open "Active Directory Provider"
 
    Set objCommand.ActiveConnection = objConnection
    objCommand.CommandText = _
        "Select Name, Location from 'LDAP://OU=Workstations,DC=domain,DC=com' " _
            & "Where objectClass='computer'"  
    objCommand.Properties("Page Size") = 1000
    objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 
    Set objRecordSet = objCommand.Execute
    objRecordSet.MoveFirst
 
    Do Until objRecordSet.EOF
       strComputer = objRecordSet.Fields("Name").Value
       objRecordSet.MoveNext
       SCRCGreen strComputer, strLog
    Loop
 
 
 '---------------------------------------------------
 
 Sub SCRCGreen(strcomputer, strLog)
 'Main script logic
 
 
 
 
    'for testing place pilot computers in GShutDownPilot group.
    'exit sub if computer not in group. 
    'if inGroup(strcomputer, GShutDownPilot)=false then 
    '   'WriteLog strLog, StrComputer&vbtab&now&vbtab&" "&vbtab&" "&vbtab&"Not in pilot group"
    '   exit sub
    'end if
 
 
 
    on error resume next
 
    'Can ping
    If Reachable(strComputer) then
 
       'Is not in skip group i.e. special can't turn off type computer 
       if inGroup(strcomputer, GShutDownSkip) then 
          WriteLog strLog, StrComputer&vbtab&now&vbtab&Uptime(strComputer)&vbtab&"computer in exclude group"&vbtab&"Shutdown Aborted" 
          on error goto 0
          exit sub
       end if
 
          'Is not a server
          if isServer(strComputer)=false then 
 
             'Skip if has an IP starting with the following three octets 172 16 71
             if instr(NetProperties(strComputer), "172.16.71.")=0 then
 
                'User logged on check
                if UserLoggedIn(strComputer)<>"" then
                   
                   'Is in skip group i.e. special user - exit sub routine
                   if inGroup(UserLoggedIn(strcomputer), GShutDownSkip) then  'skip computer based on userid
                      WriteLog strLog, StrComputer&vbtab&now&vbtab&Uptime(strComputer)&vbtab&"Special user "&UserLoggedIn(strcomputer)&" is logged in"&vbtab&"Shutdown Aborted"               
                      on error goto 0
                      exit sub
                   end if
                   
                   'Screen saver running time check
                   if ScreenSaverRunning(strComputer)>=ScreenSaverTime then
 
                      'Check for Errors in script
                      if err=0 then
                         WriteLog strLog, StrComputer&vbtab&now&vbtab&Uptime(strComputer)&vbtab&"Screen Saver on "&ScreenSaverRunning(strComputer)&" Mins"&vbtab&"Shutdown initiated"
                         shutdown strComputer
                      else
                         WriteLog strLog, StrComputer&vbtab&now&vbtab&Uptime(strComputer)&vbtab&"Screen Saver on "&ScreenSaverRunning(strComputer)&" Mins - script error"&vbtab&"Shutdown aborted"
                      end if
                   else
                      WriteLog strLog, StrComputer&vbtab&now&vbtab&Uptime(strComputer)&vbtab&"User Logged in - ScreenSaver active "&ScreenSaverRunning(strComputer)&" Mins"&vbtab&"Shutdown aborted"  
                   end if
                else
                   if err=0 then
                      WriteLog strLog, StrComputer&vbtab&now&vbtab&Uptime(strComputer)&vbtab&"computer Logged Off"&vbtab&"Shutdown Initiated"
                      shutdown strComputer
                   else
                      WriteLog strLog, StrComputer&vbtab&now&vbtab&Uptime(strComputer)&vbtab&"computer Logged Off - script error"&vbtab&"Shutdown Aborted"
                   end if
                end if   
             end if
          end if
    end if
 
    on error goto 0
 
 End sub
 
 
 '---------------------------------------------------
 
 
 Function isServer(strComputer)
 'Check OS version and return 'true' if OS is Server, 'false' if not.
 'Function by tomriddle 2009
 
    On Error Resume Next
 
    Const wbemFlagReturnImmediately = &h10
    Const wbemFlagForwardOnly = &h20
 
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
    Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_OperatingSystem", "WQL", _
                                           wbemFlagReturnImmediately + wbemFlagForwardOnly)
 
    For Each objItem In colItems
       If InStr(1,objItem.Caption,"Server") Then       
          if err<>0 then 
             isServer=true    ' Just in case 
             WriteLog strLog, StrComputer&vbtab&now&vbtab&Uptime(strComputer)&vbtab&"SERVER - or can't read WMI"&vbtab&"Shutdown aborted"
             exit function
          else   
             isServer=true
             WriteLog strLog, StrComputer&vbtab&now&vbtab&Uptime(strComputer)&vbtab&"SERVER? "&vbtab&"Shutdown aborted"
          end if   
       else
          isServer=false
       end if
    next
 
 
    on error goto 0
 
 End function
 
 
 '---------------------------------------------------
 
 Function UserLoggedIn(strcomputer)
 'Return true if a user is logged in
 
    UserLoggedIn=""
 
    on error resume next
 
    Set objWMIService = GetObject("winmgmts:" _ 
        & "{impersonationLevel=impersonate}!\\" _ 
        & strComputer & "\root\cimv2") 
 
    Set colProcessList = objWMIService.ExecQuery _ 
        ("Select * from Win32_Process Where Name = 'explorer.exe'") 
 
    For Each objProcess in colProcessList 
        objProcess.GetOwner strUserName, strUserDomain 
        UserLoggedIn=strUserName
    Next 
 
    on error goto 0
 
 End Function
 
 '---------------------------------------------------
 
 sub Shutdown(strComputer) 
 'Forced Shutdown 
 'The following code will force a system to shutdown, regardless of any applications open at the time. 
 
 
 '****************
 'exit sub '*******  TESTING - unremark out this line and sub is made safe for testing. 
 '****************
 
 
    on error resume next
 
    Const Force_Shutdown = 5 
    Set OpSysSet = GetObject("winmgmts:{(Shutdown)}//"&strComputer&"/root/cimv2").ExecQuery("select * from Win32_OperatingSystem where Primary=true") 
    For Each OpSys In OpSysSet 
       OpSys.Win32Shutdown(Force_Shutdown) 
    Next 
 
    on error goto 0
 
 end sub 
 
 '---------------------------------------------------
 
 Function Reachable(strComputer)
 'Return true if can ping
 
    Dim wmiQuery : wmiQuery = "Select * From Win32_PingStatus Where Address = '" & _
                              strComputer & "'"
    Dim objWMIService : Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
    Dim objPing : Set objPing = objWMIService.ExecQuery(wmiQuery)
    Dim objStatus
    For Each objStatus in objPing
        If IsNull(objStatus.StatusCode) Or objStatus.Statuscode<>0 Then
            Reachable = False
        Else
            Reachable = True
        End If
    Next
 
 End Function
 
 '---------------------------------------------------
 
 Function ScreenSaverRunning(strComputer)
 'Returns the number of minutes the screen saver has been running for, else 0
 
    ScreenSaverRunning=0
 
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    Set colProcesses = objWMIService.ExecQuery("Select * from Win32_Process")
 
    For Each objProcess in colProcesses
       If Right(objProcess.Name, 4) = ".scr" Then
          ScreenSaverRunning = datediff("n", WMIDateStringToDate(objProcess.CreationDate), now)
       End If
    Next
 
 End Function
 
 '---------------------------------------------------
 
 Function inExcludedArray(strComputer)
 'Returns true if strComputer is in array of computers to exclude
 
    For i = 0 to Ubound(arrServiceList)-1
 
       if arrServiceList(i)=strComputer then 
          inExcludedArray=true
          exit function
       else
          inExcludedArray=false
       end if
   
    Next
 
 End function
 
 '---------------------------------------------------
 
 Function WMIDateStringToDate(dtmBootup)
     WMIDateStringToDate =  CDate(Mid(dtmBootup, 7, 2) & "/" & _
         Mid(dtmBootup, 5, 2) & "/" & Left(dtmBootup, 4) _
             & " " & Mid (dtmBootup, 9, 2) & ":" & _
                 Mid(dtmBootup, 11, 2) & ":" & Mid(dtmBootup,13, 2))
 End Function
 
 '---------------------------------------------------
 
 sub WriteLog(strLog, StrContent) 
 'Write output to log file
 
    Dim objFSO
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    objFSO.OpenTextFile(strLog, 8, True).WriteLine strContent
 
 End Sub
 
 '---------------------------------------------------
 
 Function Uptime(strComputer)
 'Return uptime of the operating system of this computer
 
    on error resume next
 
    Set objWMIService = GetObject("winmgmts:" _
       & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
    Set colOperatingSystems = objWMIService.ExecQuery _
       ("Select * from Win32_OperatingSystem")
  
    For Each objOS in colOperatingSystems
       dtmBootup = objOS.LastBootUpTime
       dtmLastBootupTime = WMIDateStringToDate(dtmBootup)
       dtmSystemUptimeD = DateDiff("d", dtmLastBootUpTime, Now)
       dtmSystemUptimeM = DateDiff("n", dtmLastBootUpTime, Now)
 
       x=dtmSystemUptimeM mod 60
       dtmSystemUptimeH = (dtmSystemUptimeM-x)/60
       dtmSystemUptimeM = x
 
       if dtmSystemUptimeH >= 24 then
          dtmSystemUptimeH = dtmSystemUptimeH mod 24
       end if
 
       If dtmSystemUptimeD = 1 then
          D="Day "
       else
          D="Days "
       end if
 
       If dtmSystemUptimeH = 1 then
          H="Hour "
       else
          H="Hours "
       end if
 
       If dtmSystemUptimeM = 1 then
          M="Minute "
       else
          M="Minutes "
       end if
 
       Uptime = dtmSystemUptimeD & D & dtmSystemUptimeH & H & dtmSystemUptimeM & M 
    Next
 
    if err.number <> 0 then 
       Uptime = "Error Reading WMI" 
    end if 
 
    on error goto 0
 
 end function
 
 
 '---------------------------------------------------
 
 
 function inGroup(strComputer, ShutdownGroup)
 
 
    On Error Resume Next
 
    Set objGroup = GetObject("LDAP://" & ShutdownGroup)
 
    objGroup.GetInfo
  
    arrMemberOf = objGroup.GetEx("member")
  
    For Each strMember in arrMemberOf
 
        if instr(strMember, strComputer)>0 then
           inGroup=true
           exit function
        end if
 
        Set objUser = GetObject ("LDAP://"&strMember)
        if lcase(strComputer)=lcase(objUser.sAMAccountName) then
           inGroup=true
           exit function          
        end if
 
    Next
 
    inGroup=false
 
    on error goto 0
 
 end function
 
 
 '---------------------------------------------------
 
 
 Function NetProperties(strComputer) 
 
 'Return remote computer's Network properties
 
 on error resume next
 
 Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2") 
 Set colItems = objWMIService.ExecQuery("SELECT * FROM " & _ 
  "Win32_NetworkAdapterConfiguration WHERE IPEnabled = True") 
 For Each objItem In colItems 
 
    XIP= Join(objItem.IPAddress, ",")
 
 Next 
 
 
 'Return ip computer has
 if err.number <> 0 then 
    NetProperties = ""
 else
    NetProperties=XIP
 end if
 
 
 on error goto 0
 
 end Function
 
 
 
 


Here is another quick freebie, more printers the better, log into the print server and change the defaults to double sided. Users can override this to print single sided if they want, instead of the other way around.


 
#1
    Zak

    • Total Posts : 2
    • Scores: 0
    • Reward points : 0
    • Joined: 5/11/2010
    • Status: offline
    Re:Power Off Unused PCs Tuesday, May 11, 2010 4:00 PM (permalink)
    0
    HI Thanks,

    my intentions are same for Green IT  but the script provided by you is very very long and am not having any access to Group policy.

    I am system admin and in need of a VB script which does following functions mentioned below and FYI am a newbie to the forum and scripting.

    a) Script should ping the list of computers(hostnames/netbios names) from a txt file and on ping basis a message popup should appear on desktop with a countdown timer giviing options of OK and CANCEL
    b)If PC dosnt ping then it should go to next PC from list.
    b) If a user is using the PC then he will click cancel if he does that he can carry on with his work else if the PC is idle after countdown the PC should go for shutdown status.

    This activity should be scheduled.Pls help me am in need of this script
     
    #2
      TomRiddle

      • Total Posts : 620
      • Scores: 12
      • Reward points : 0
      • Joined: 2/7/2008
      • Location: Australia
      • Status: offline
      Re:Power Off Unused PCs Tuesday, May 11, 2010 4:21 PM (permalink)
      0
      This script does not need grouppolicy, but it uses an AD group which the script checks against before shutting the target machine down. I needed some mechanism to exclude important machines that can not be shut down and thought this would be cool and allow other admins to maintain as an exclude list.
       
      Also the script does not use a text file but loops through all the machines found in AD, this saves me maintaining such a text file of machines to shut down. Ie machines are added and removed form network all the time and any static list will quickly become outdated.
       
      Also the script does not prompt the user if they want to carry on with their work or shut down but just shuts down the machine. The logic I use is if the machine has a screen saver activated for more than 20 mins after 9pm then the machine is unattended. Also if the machine is logged off at this time then it can also be shut down without any prompts.
       
      I am however thinking of writing version 2 soon and will keep you in the loop. The next version will run 10 times quicker (getting through the list of machines to shut down quicker) It will also display a popup allowing the user to defer the shutdown, and having this interaction will allow me to run it from my scheduled task at an earlier time in the evening.
      -join([int[]][char[]]'Ut|jwXmjqq%Wzqjx'|%{[char]($_-5)})
       
      #3
        jjackson

        • Total Posts : 2
        • Scores: 0
        • Reward points : 0
        • Joined: 5/26/2010
        • Status: offline
        Re:Power Off Unused PCs Wednesday, May 26, 2010 8:00 AM (permalink)
        0
        What really kills me about this script is the document thing.
         
        Currently I use SCCM to push this command line
         
            %windir%\system32\rundll32.exe powrprof.dll,SetSuspendState Hibernate
         
        which works great for labs and classroom computers but for staff desktops I don't want to force the hibernation if they are working late or remoting in from home.
         
        Do you know if there is a way to ask the user yes or no and then continue with the operation if nobody responds? A time out of sorts?
         
        Thanks a lot.
         
        #4
          TomRiddle

          • Total Posts : 620
          • Scores: 12
          • Reward points : 0
          • Joined: 2/7/2008
          • Location: Australia
          • Status: offline
          Re:Power Off Unused PCs Wednesday, May 26, 2010 11:18 PM (permalink)
          0
          We have 2000+ computers on our network that are targeted for the nightly shutdown command and I have not had a complaint yet. Initially I got a flurry of users asking me to exclude their machine because of some reason or what not. But the rest, if the computer has a screen saver on for an extended time after 9pm then it is shutdown, unsaved work lost.

          The next version... hmm, The thing is, every one of my workstations have a screensaver policy set, so it is pointless asking, "Can I shut your computer down?" When I know it is in use (When I can’t detect logon.scr process running). Also Popups are pointless when the machine is locked, screensaver active or at logon prompt because the user does not see them.

          Maybe in the interest of saving the planet I could make the popup mod (for people that don't have an enforced screen saver policy) It would be just a bit of code to remote execute a popup script. I am thinking short message, XXmin countdown, and the options to defer for 1 hour or abort completely?
          But then what would your logic be if you hit a computer that has been locked and idle for some time after hours? Leave it? Send the user a nasty email? Shut it down anyway?

          I say shut it down, But to be fair, do a bit of PR beforehand, If you want I can send anyone the posters and propaganda that we used. I was monitoring the number of computers left on before and after the PR campaign and I have to say a lot of people started shutting their machines down themselves after that.
          -join([int[]][char[]]'Ut|jwXmjqq%Wzqjx'|%{[char]($_-5)})
           
          #5
            jjackson

            • Total Posts : 2
            • Scores: 0
            • Reward points : 0
            • Joined: 5/26/2010
            • Status: offline
            Re:Power Off Unused PCs Thursday, May 27, 2010 5:15 AM (permalink)
            0
            I think we are just in different enviroments. I absolutly despise screen savers. It's just a preference.
             
            The logic behind asking is, if they don't answer, i.e. they aren't or haven't been on the computer for a while, my command would just hibernate the machine. Power saved, no documents lost, no work interupted. I'm just trying to be curteous to the few professors/administrators that work wierd hours and remote in from home.
             
            Ultimatley what I am doing now is working for most part I was just hoping to add a little more convienience. I also have the luxury of having SCCM. Software distribution gives a nice little bubble telling the user they are targeted for hibernation.
             
            #6
              TomRiddle

              • Total Posts : 620
              • Scores: 12
              • Reward points : 0
              • Joined: 2/7/2008
              • Location: Australia
              • Status: offline
              Re:Power Off Unused PCs Thursday, May 27, 2010 10:45 AM (permalink)
              0
              Ok give me a week and I will find time to write a popup version. Cheers.
              -join([int[]][char[]]'Ut|jwXmjqq%Wzqjx'|%{[char]($_-5)})
               
              #7
                TomRiddle

                • Total Posts : 620
                • Scores: 12
                • Reward points : 0
                • Joined: 2/7/2008
                • Location: Australia
                • Status: offline
                Re:Power Off Unused PCs Thursday, July 08, 2010 3:15 PM (permalink)
                0
                I have tottally re-written the code and it seems to be working fine on my domains (2500 computers) though JJackson is yet to test it. 

                I tried to post it here but got an error so it now lives on TechNet instead.
                http://gallery.technet.microsoft.com/ScriptCenter/en-us/96b8c8b9-91e2-4d63-b62f-59f2330de540

                Next version maybe PowerShell now that that's my focus. Getting a remote popup to work in this was a real hack and I have only tested on XP.

                Go Green...
                -join([int[]][char[]]'Ut|jwXmjqq%Wzqjx'|%{[char]($_-5)})
                 
                #8

                  Online Bookmarks Sharing: Share/Bookmark

                  Jump to:

                  Current active users

                  There are 0 members and 1 guests.

                  Icon Legend and Permission

                  • New Messages
                  • No New Messages
                  • Hot Topic w/ New Messages
                  • Hot Topic w/o New Messages
                  • Locked w/ New Messages
                  • Locked w/o New Messages
                  • Read Message
                  • Post New Thread
                  • Reply to message
                  • Post New Poll
                  • Submit Vote
                  • Post reward post
                  • Delete my own posts
                  • Delete my own threads
                  • Rate post

                  2000-2012 ASPPlayground.NET Forum Version 3.9