none
Set-ADUser : The specified attribute is already present on the object Logon Hours. RRS feed

  • Question

  • Hello team,

    Thank you for passing by, i tried to google the solution for this for the last hour but not found nothing relevant, all the solutions provided are not working for me...

    I'm trying to set the logonhours for some one user, getting the logon hours from a template is not an option. (What if this user leaves the company?)

    The script used is the following:

    [array]$logonHours =  @(128,255,15,128,255,15,128,255,15,128,255,15,128,255,15,128,255,15,128,255,15)
    set-aduser userexample -replace @{logonHours = $logonHours }

    I tried as well with:

    [array]$old = (Get-ADUser ExampleUser -Properties logonhours).logonhours
    
    Get-ADUser exampleuser -Properties logonhours | Set-ADUser -replace @{logonhours = $logonHours,$old}
    
    #Same outcome:
    
    Set-ADUser : The specified attribute is already present on the object
    At line:1 char:46
    + ... ogonhours | Set-ADUser -replace @{logonhours = $logonHours.replace("  ...
    +                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (CN=xxx:ADUser) [Set-ADUser], ADException
        + FullyQualifiedErrorId : ActiveDirectoryServer:8318,Microsoft.ActiveDirectory.Management.Commands.SetADUser

    I tried different variables (string,arrays and bytes) but no good.

    I tried to clear the field too, no error shown but same outcome, i tried to remove the field too, same.

    The quest roles(qadusers cmdlets as seen on the post PowerShell change user working time in AD) is not an option either since my adm account is limited for this forest. 

    Thanks in advance. 

    Tuesday, December 17, 2019 10:40 AM

Answers

  • The logonHours attribute is a byte array, not an array of integers. It is an array of 21 bytes, equal to 168 bits, one for each hour in a week. Also, the time is in UTC (Coordinated Universal Time), so it must be adjusted for the time zone bias in the local registry. A PowerShell script to assign 0 to all 21 bytes, so the user cannot logon during any hour, would be similar to below:

    # Create an array of 21 bytes, each of 8 bits,
    # representing the 168 hours in a week.
    $LH = New-Object 'Byte[]' 21
    
    # Populate binary array with all zeros.
    # The user cannot logon during any hour of the week.
    # Since the array is all zeros, no conversion into UTC needed.
    For ($k = 0; $k -le 20; $k = $k + 1)
    {
        $LH[$k] = 0
    } 
    # Assign 21 byte array of all zeros to the logonHours attribute of the user.            
    Set-ADUser jsmith -Replace @{logonHours=$LH}
    

    But this only assigns the bytes, 21 of them. Each byte is 0, which is 8 bits of zeros. The trick is to create the byte array of 168 bits for some other settings, taking UTC into account. Here is a link to a script I wrote a few years ago to assign the logon hours given a comma delimited file, one line for each day of the week, each line with 24 bits (0 or 1).

    https://gallery.technet.microsoft.com/fd6a340b-ed8b-4787-8d12-3c6fcb822104

    This shows how the byte array can be created.


    Richard Mueller - MVP Enterprise Mobility (Identity and Access)

    • Marked as answer by TamboleoA Tuesday, December 17, 2019 3:06 PM
    Tuesday, December 17, 2019 12:16 PM
    Moderator

All replies

  • The logonHours attribute is a byte array, not an array of integers. It is an array of 21 bytes, equal to 168 bits, one for each hour in a week. Also, the time is in UTC (Coordinated Universal Time), so it must be adjusted for the time zone bias in the local registry. A PowerShell script to assign 0 to all 21 bytes, so the user cannot logon during any hour, would be similar to below:

    # Create an array of 21 bytes, each of 8 bits,
    # representing the 168 hours in a week.
    $LH = New-Object 'Byte[]' 21
    
    # Populate binary array with all zeros.
    # The user cannot logon during any hour of the week.
    # Since the array is all zeros, no conversion into UTC needed.
    For ($k = 0; $k -le 20; $k = $k + 1)
    {
        $LH[$k] = 0
    } 
    # Assign 21 byte array of all zeros to the logonHours attribute of the user.            
    Set-ADUser jsmith -Replace @{logonHours=$LH}
    

    But this only assigns the bytes, 21 of them. Each byte is 0, which is 8 bits of zeros. The trick is to create the byte array of 168 bits for some other settings, taking UTC into account. Here is a link to a script I wrote a few years ago to assign the logon hours given a comma delimited file, one line for each day of the week, each line with 24 bits (0 or 1).

    https://gallery.technet.microsoft.com/fd6a340b-ed8b-4787-8d12-3c6fcb822104

    This shows how the byte array can be created.


    Richard Mueller - MVP Enterprise Mobility (Identity and Access)

    • Marked as answer by TamboleoA Tuesday, December 17, 2019 3:06 PM
    Tuesday, December 17, 2019 12:16 PM
    Moderator
  • Thank you very much! It will work for me :) 
    Tuesday, December 17, 2019 3:06 PM
  • Create a byte array filled with all zeros:

    $b = [byte[]]::New(21)

    There is no need to fill it with zeros.  It will be created filled with all zeros.


    \_(ツ)_/

    Tuesday, December 17, 2019 3:33 PM