Setting a users logon hours

By default a user can logon 24/7.  Is this acceptable – should users be able to logon during the night or weekends. AD Users and Computers has a GUI to set the hours users can logon. But we don’t need a GUI we can do this

if (-not (Get-Module ActiveDirectory)){            
  Import-Module ActiveDirectory            
}            
            
$ou = "OU=England,DC=Manticore,DC=org"            
            
## allow logon 8am - 6pm Monday to Friday            
[byte[]]$hours = @(0,0,0,0,255,3,0,255,3,0,255,3,0,255,3,0,255,3,0,0,0)            
            
"`nMicrosoft"            
$name = "UserA"            
Get-ADUser -Identity $name |            
Set-ADUser -Replace @{logonhours = $hours}            
            
"`nAD provider"            
$name = "UserB"            
$dn = "cn=$name,$ou"            
Set-ItemProperty -Path AD:\$dn  -Name logonhours -Value $hours -Force            
            
"`nQuest"            
$name = "UserC"            
Get-QADUser -Identity $name |            
Set-QADUser -ObjectAttributes @{logonhours = $hours}            
            
"`nScript"            
$name = "UserD"            
$dn = "cn=$name,$ou"            
$user = [adsi]"LDAP://$dn"            
$user.logonhours[0] = $hours            
$user.SetInfo()

We’ll use the four test users we created earlier in the England OU.

The important point is how we represent the hours users can logon.

The information is stored as a byte array – 3bytes per day with 1 bit per hour

We want to restrict the users to 8am-6pm Monday to Friday so we use

[byte[]]$hours = @(0,0,0,0,255,3,0,255,3,0,255,3,0,255,3,0,255,3,0,0,0)

Sunday is the start of the week – no logons allowed so first three bytes are 0. Monday’s three bytes starts with a 0 as don’t want logons between midnight and 8am. The 8 hours of logons followed by two hours. etc

A few other examples might help

Deny all logon

[byte[]]$hours = @(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)

 

Allow logon at all hours

[byte[]]$hours = @(255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255)

 

Allow 8am-6pm – 7 days a week

[byte[]]$hours = @(0,255,3,0,255,3,0,255,3,0,255,3,0,255,3,0,255,3,0,255,3)

 

If you are in doubt about generating the array – set in the GUI then copy the values using ADSIEdit

The scripts are straightforward – the cmdlets get the user and pipe to set. The difference is the parameter we use

The provider uses Set-Itemproperty and the only oddity in the script is we use logonhours[0] as the property. This forces acceptance of the byte array

This entry was posted in PowerShell and Active Directory. Bookmark the permalink.

12 Responses to Setting a users logon hours

  1. Fetz says:

    Very useful and works perfectly. This is what i was looking for. Thank you !

  2. Lars says:

    Hi,

    I know this is an older topic, but it’s one of the first that comes up when searching for settign logon hours.

    When I tried to set it with the values you provided, I get a one hour shift when looking at the GUI.
    255,0,0 sets time from 1AM to 9AM.
    0,255,0 sets time from 9AM to 5PM
    0,0,255 sets time from 5PM to 1AM next day.

    Is this normal behavior? Or is there something wrong with the GUI?
    Even Set-ADUser (example 6) at Microsofts technet tells me this should not be correct.

    I’m using PowerShell 4.0 on Windows Server 2008 R2.

    • What time zone is your server in? and is it different to other machines? Also is one of the machines stuck on daylight saving time?

      • Lars says:

        Timezone is UTC+1 – Brussels with automatic adjustment to daylight saving time.
        It is on a Virtualbox virtual machine, connected via a bridged network to the host network adapter and to the internet.

      • Is there any difference between the time settings on the machine running Virtualbox, the problem machine and the client used to access the machines?

      • Lars says:

        No difference between vitrual machine and the host running virtualbox.
        The only difference is in what is described in how PowerShell should work, and the user interface in the account of which the hours are set on the same machine.

  3. Juan Ballard says:

    I am in EST time zone and the values in the script above did not set the correct hours for me. What I found is that the first number (byte) in each day contains hours from the day before. For example my goal was to set logon hours to: M-F 7am – 8pm Sat 7am – 3pm. My PowerShell code looks like this:

    ## allow logon 7am – 8pm Monday to Friday and 7am – 3pm Saturday ##
    [byte[]]$hours = @(0,0,0,0,240,255,1,240,255,1,240,255,1,240,255,1,240,255,1,240,15)

    Byte Hour Span Sunday Mon Tues Wed Thurs Fri Saturday
    1st 7pm-2am 0 0 1 1 1 1 1
    2nd 3am-10am 0 240 240 240 240 240 240
    3rd 11am-6pm 0 255 255 255 255 255 15

    At first I struggled with the idea that Monday started with 0 when every other weekday starts with a 1. Then I realized that in the 1st byte for each day there were hours that carried over from the day before. So in Monday’s 1st byte the first five bits represent Sunday Night 7pm-12!

    This is the firsy byte broken down into bits:
    Hours Bit Numeric Value
    7pm-Yesterday 1
    8pm-Yesterday 2
    9pm-Yesterday 4
    10pm-Yesterday 8
    11pm-Yesterday 16
    Midnight 32
    1am Current day 64
    2am Current day 128

    This also goes for each consecutive day until you get to Saturday where the hours between 7pm-12 are represented in Sunday’s first byte.

  4. Jos Bonthuis says:

    Hello,

    here is a TIP!

    because timezoning make the above calculation word only for standard timezone running env.
    you need to recalculate al logon hourts with timezone + / – hours.

    What i do is:

    first set one user logonhours via dsa.msc

    then use adsiedit to read the user logonhours property of the earlier set useraccount with the preset hours.

    When you edit the logonhours property in ADSIedit, (display it as decimal).

    it looks like this:

    000 000 000 224 255 031 224 255 031 224 255 031 224 255 031 224 255 031 000 000 000,

    now remove pre zero’s add seperators ending up like this :

    0,0,0,224,255,31,224,255,31,224,255,31,224,255,31,224,255,31,0,0,0

    now add it like this:

    [byte[]]$hours = @(0,0,0,224,255,31,224,255,31,224,255,31,224,255,31,224,255,31,0,0,0)

    Now use this to set the same logonhours to other users, voila you don’t have to figure out / calculate settings.

    You can repeat above to addmultiple logonhour profiles to your script:

    [byte[]]$hours1 = @(0,0,0,224,255,31,224,255,31,224,255,31,224,255,31,224,255,31,0,0,0)
    [byte[]]$hours2 = @(0,0,0,224,255,31,224,255,31,224,255,31,224,255,31,224,255,31,0,0,0)
    [byte[]]$hours3 = @(0,0,0,224,255,31,224,255,31,224,255,31,224,255,31,224,255,31,0,0,0)

  5. KC says:

    How would one go about resetting it, i.e. putting it back to ?

  6. KC says:

    OK, I see that the Quest cmdlet accepts $null (unlike the MS one).

  7. Pingback: Archiving AD Accounts with PowerShell - SCCMF12TWICE

Leave a comment