' LogonHours.vbs
' VBScript program to document hours of the week when a given Active
' Directory user is allowed to logon, using the logonHours attribute.
'
' ----------------------------------------------------------------------
' Copyright (c) 2002-2010 Richard L. Mueller
' Hilltop Lab web site - http://www.rlmueller.net
' Version 1.0 - November 10, 2002
' Version 1.1 - February 19, 2003 - Standardize Hungarian notation.
' Version 1.2 - May 19, 2003 - Bug fixes.
' Version 1.3 - January 25, 2004 - Modify error trapping.
' Version 1.4 - November 6, 2010 - No need to set objects to Nothing.
' Version 1.5 - September 19, 2012 - Modify rounding of local time
'               zone bias to handle fractions of hour properly.
'
' This script is designed to be run at a command prompt, using the
' Cscript host. For example:
' cscript //nologo LogonHours.vbs DistinguishedName
' DistinguishedName can be similar to:
'     "cn=TestUser,ou=Sales,dc=MyDomain,dc=com"
'
' You have a royalty-free right to use, modify, reproduce, and
' distribute this script file in any way you find useful, provided that
' you agree that the copyright owner above has no warranty, obligations,
' or liability for such use.

Option Explicit

Dim objShell, lngBias, arrstrDayOfWeek, strUserDN
Dim arrbytLogonHours(20)
Dim arrintLogonHoursBits(167)
Dim bytLogonHours, lngBiasKey
Dim bytLogonHour, intLogonHour, strLine
Dim objUser, k, intCounter, intLoopCounter, j, m

' Check for required argument.
If (Wscript.Arguments.Count = 0) Then
    Wscript.Echo "Error, required argument missing."
    Wscript.Echo "LogonHours.vbs"
    Wscript.Echo "Program to document allowed logon hours"
    Wscript.Echo "Syntax:"
    Wscript.Echo "cscript LogonHours.vbs DN"
    Wscript.Echo "where DN is the DistinguishedName of an AD user."
    Wscript.Echo "For example, DN could be:"
    Wscript.Echo "  cn=TestUser,ou=Sales,dc=MyDomain,dc=com"
    Wscript.Quit(1)
End If

strUserDN = Wscript.Arguments(0)

' Bind to the specified user object with the LDAP provider.
On Error Resume Next
Set objUser = GetObject("LDAP://" & strUserDN)
If (Err.Number <> 0) Then
    On Error GoTo 0
    Wscript.Echo "User not found in Active Directory"
    Wscript.Echo strUserDN
    Wscript.Quit(1)
End If
On Error GoTo 0

' Determine the time zone bias from the local registry.
' This bias does not change with Daylight Savings Time.
Set objShell = CreateObject("Wscript.Shell")
lngBiasKey = objShell.RegRead("HKLM\System\CurrentControlSet\Control\" _
    & "TimeZoneInformation\Bias")
If (UCase(TypeName(lngBiasKey)) = "LONG") Then
    lngBias = lngBiasKey
ElseIf (UCase(TypeName(lngBiasKey)) = "VARIANT()") Then
    lngBias = 0
    For k = 0 To UBound(lngBiasKey)
        lngBias = lngBias + (lngBiasKey(k) * 256^k)
    Next
End If
' Modified September 19, 2012, to handle fractions of an hour properly.
lngBias = Round((lngBias/60) + .1)

arrstrDayOfWeek = Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")

Wscript.Echo "User: " & objUser.name

' Retrieve the user's logonHours attribute.
objUser.GetInfoEx Array("logonHours"), 0
bytLogonHours = objUser.Get("logonHours")

' Populate a byte array.
For k = 1 To LenB(bytLogonHours)
    arrbytLogonHours(k - 1) = AscB(MidB(bytLogonHours, k, 1))
Next

' Populate a bit array, offset by the time zone bias.
j = 0
For Each bytLogonHour In arrbytLogonHours
    For k = 7 To 0 Step -1
        m = 8*j + k - lngBias
        If (m < 0) Then
            m = m + 168
        End If
        If (bytLogonHour And 2^k) Then
            arrintLogonHoursBits(m) = 1
        Else
            arrintLogonHoursBits(m) = 0
        End If
    Next
    j = j + 1
Next

' Output the bit array, one day per line, 24 hours per day.
intCounter = 0
intLoopCounter = 0
Wscript.Echo "Day"
Wscript.Echo "of   ------- Hour of the Day -------"
Wscript.Echo "Week M-3 3-6 6-9 9-N N-3 3-6 6-9 9-M"
For Each intLogonHour In arrintLogonHoursBits
    If (intCounter = 0) Then
        strLine = arrstrDayOfWeek(intLoopCounter) & "  "
        intLoopCounter = intLoopCounter + 1
    End If
    strLine = strLine & intLogonHour
    intCounter  = intCounter + 1
    If (intCounter = 3) Or (intCounter = 6) Or (intCounter = 9) _
            Or (intCounter = 12) Or (intCounter = 15) Or (intCounter = 18) _
            Or (intCounter = 21) Then
        strLine = strLine & " "
    End If
    If (intCounter = 24) Then
        Wscript.Echo strLine
        intCounter = 0
    End If
Next