Description

This script will shutdown PCs that are logged in after the permitted login hours as well as PCs that do not have users logged in. A simple modification could be made to simply report PCs that are turned on but don't have a user logged in rather than shutting them down.

The script only performs network shutdowns if it's run after hours, during business hours it will generate a report for testing purposes. If the script is run once a day the log files will be kept for one week and then overwritten.

The script searches Active Directory starting at a specified OU for computers to check.

Exceptions can be defined for users and machines that are exempt from the shutdown procedure.

Script

PowerShell
Edit|Remove
# 
# ComputerContainer - Active Directory Container node at which search for Computers subjected to forced shutdown starts  
# ExceptionAccounts - List of usernames exempt from forced shutdowns 
# ExceptionMachines - List of computers exempt from forced shutdowns (only if no one is logged in) 
# LogPath - Path for Logfile, overwritten weekly 
# NonDomainHours - Logon Hours byte array representing permitted logon hours for non-domain (typically local) accounts 
#                   ( M:7-M:22 Tu:7-Tu:22 W:7-W:22 Th:7-Th:22 F:7-F:22 Sa:7-Sa:16 ) EST 
# 
$ComputerContainer = "ou=Computers," 
$ExceptionAccounts = "domain\user1,domain\admin1,domain\admin2,domain\user2,domain\user3" 
$ExceptionMachines = "PC001,PC002,PC003" 
$LogPath = "\\SERVER\shared\IT_Monitoring\" 
[byte[]]$NonDomainHours = @(0,0,0,0,240,255,7,240,255,7,240,255,7,240,255,7,240,255,7,240,31) 
 
 
# 
# Function to evaluate whether current time is an authorized login time 
# 
Function Check-Hours ( [byte[]]$HoursArray ) { 
 
    for ($i=0; $i -le 167; $i++) { 
        $LogonArray[$i] = ([int] ([math]::pow(2,($i % 8))) -band ([int]($HoursArray[([math]::truncate($i/8))]))) 
        if ($LogonArray[$i-ne 0) {$LogonArray[$i] = 1} 
    } 
 
    if ($LogonArray[(($dayhash.item(($today.ToUniversalTime().DayofWeek).tostring())*24)+$today.ToUniversalTime().hour)] -eq 0) { 
        $False 
    } else { 
        $True 
    } 
} 
 
$userDomain = New-Object System.DirectoryServices.DirectoryEntry 
$Domain = $userDomain.distinguishedName.tostring() 
$DomLength = $Domain.IndexOf(","- 3 
 
for ($i=0; $i -le 167; $i++) {$LogonArray += @(0)} 
$DayHash = @{} 
$DayHash.Add("Sunday",0) 
$DayHash.Add("Monday",1) 
$DayHash.Add("Tuesday",2) 
$DayHash.Add("Wednesday",3) 
$DayHash.Add("Thursday",4) 
$DayHash.Add("Friday",5) 
$DayHash.Add("Saturday",6) 
 
$today = get-date 
$RptFileName = $LogPath+"ForcedLogoffs"+$today.DayofWeek.ToString().SubString(0,3)+".txt" 
$ReportFile = New-Item -type file -force $RptFileName 
 
" " | Out-File $ReportFile -encoding ASCII -append 
"Nightly Forced Log Offs " + $today.DateTime | Out-File $ReportFile -encoding ASCII -append 
 
# 
# Forced Shutdowns only performed M-F, after 10:00pm and before 6:00am, Sat after 4:00pm or anytime Sun 
# Since Logon Hours attribute is checked this is not really necessary but adds extra protection against 
# accidental shutdowns during testing 
# 
if ( $today.hour -ge 22 -or $today.hour -lt 6 -or $today.DayofWeek -eq "Sunday" -or ($today.DayofWeek -eq "Saturday" -and $today.hour -ge 16) ) { 
    $AfterHours = $True 
} else { 
    $AfterHours = $False 
} 
if ($AfterHours -eq $False) {" - Run during allowed hours **** Reporting Only ****" | Out-File $ReportFile -encoding ASCII -append} 
 
" " | Out-File $ReportFile -encoding ASCII -append 
" " | Out-File $ReportFile -encoding ASCII -append 
 
$ObjFiler = "(objectCategory=Computer)" 
$objSearch = New-Object System.DirectoryServices.DirectorySearcher 
$objSearch.SearchRoot = "LDAP://"+$ComputerContainer+$Domain 
$ObjProp = "name" 
$objSearch.Filter = $ObjFiler 
$AllObj = $objSearch.FindAll() 
 
 
foreach ($Obj in $AllObj) { 
 
    $objItem = $Obj.Properties 
    [string]$compname = $objItem.name 
 
    $ping = gwmi Win32_PingStatus -filter "Address='$compname'" 
 
    if ($ping.StatusCode -eq 0) { 
         
        $UserName = (gwmi -computer $compname Win32_ComputerSystem).Username 
        if (([int]$UserName.Length) -gt 0) { 
            if ($ExceptionAccounts.Contains( $UserName.ToLower() ) -eq $False) { 
 
                $strUserName = $UserName.SubString( ($DomLength+1) ) 
 
                $userSearcher = New-Object System.DirectoryServices.DirectorySearcher 
                $strFilter = "(&(objectCategory=User)(samAccountName=" + $strUserName + "))" 
                $userSearcher.SearchRoot = $userDomain 
                $userSearcher.PageSize = 1000 
                $userSearcher.Filter = $strFilter 
                $userSearcher.SearchScope = "Subtree" 
                $colResults = $userSearcher.FindAll() 
 
                $user = [ADSI]$colResults[0].Path 
                $LogonHours = $user.logonHours 
                $UserPermitted = $True 
 
                if ([int]$colResults[0].Path.Length -eq 0) { 
                    $LogonHours += @($Null) 
                } 
                if ($LogonHours[0] -eq $Null) { 
                    if ($UserName.Substring(0,($DomLength+1)) -eq ($Domain.substring(3,$DomLength)+"\")) { 
                        $UserPermitted = $True 
                    } else { 
                        $UserPermitted = Check-Hours $NonDomainHours 
                    } 
                } else { 
                    $UserPermitted = Check-Hours $LogonHours[0] 
                } 
 
                if ($UserPermitted) { 
                    $compname + ":" + $UserName + " permitted to be logged in at this time"  | Out-File $ReportFile -encoding ASCII -append 
                } else { 
                    $cmd = "Shutdown /s /f /m \\" + $compname 
                    $cmd + " (" + $UserName + ")"  | Out-File $ReportFile -encoding ASCII -append 
                    if ($AfterHours) {Invoke-Expression $cmd} 
                } 
            } else { 
                "Shutdown Exception made: " + $compname + ":" + $UserName | Out-File $ReportFile -encoding ASCII -append 
            } 
        } else { 
            if ($ExceptionMachines.Contains( $compname.ToUpper() ) -eq $False) { 
                $cmd = "Shutdown /s /f /m \\" + $compname 
                $compname + ": turned on but logged out - " + $cmd | Out-File $ReportFile -encoding ASCII -append 
                if ($AfterHours) {Invoke-Expression $cmd} 
            } else { 
                $compname + ": turned on but logged out - Shutdown Exception made"  | Out-File $ReportFile -encoding ASCII -append 
            } 
        } 
    } 
 
}