18/10/2024

Active Directory : comment gérer les horaires d’accès en PowerShell ?

I. Présentation

Dans ce chapitre, nous allons apprendre à gérer les horaires d'accès des utilisateurs de l'Active Directory à l'aide d'un script PowerShell ! Chaque compte utilisateur de l'Active Directory contient un attribut nommé LogonHours qui indique quand un utilisateur est autorisé à ouvrir sa session avec son compte (ou à s'authentifier, de manière générale).

Par défaut, il n'y a aucune restriction : tous les utilisateurs peuvent se connecter tous les jours de la semaine, à n'importe quelle heure. Il serait légitime de se poser la question suivante : est-il normal qu'un utilisateur du service comptabilité cherche à se connecter à sa session à 3h du matin dans la nuit de samedi à dimanche ? Pas certain... Et peut être même que ce sera le début des ennuis...

Horaire accès par défaut Active Directory

Il est recommandé de limiter les horaires d'accès en fonction des horaires et jours travaillés des salariés de l'entreprise (avec un peu de souplesse pour éviter les blocages si un utilisateur arrive plus tôt le matin, par exemple).

Si vous cherchez à restreindre les périodes pendant lesquelles un utilisateur peut ouvrir sa session, vous pouvez intervenir sur chaque compte utilisateur (bon courage), ou sélectionner plusieurs utilisateurs à partir de la console "Utilisateurs et ordinateurs Active Directory" (ou du "Centre d'administration Active Directory") afin de modifier plusieurs comptes en masse, via un clic droit "Propriétés" après avoir sélectionné les comptes. Sinon, vous pouvez également utiliser PowerShell et c'est ce que nous allons voir.

Nous allons nous fixer l'objectif de déployer la configuration suivante :

  • Autoriser l'ouverture de session du lundi au vendredi de 06h00 à 20h00
  • Interdire l'ouverture de session du lundi au vendredi de 20h00 à 06h00, et intégralement le week-end

À partir de la console Active Directory, cela nous donne :

Restriction ouverture session AD Windows avec PowerShell

II. L'attribut LogonHours

Si vous ouvrez la console "Utilisateurs et ordinateurs Active Directory", que vous basculez en affichage avancé (Affichage > Fonctionnalités avancées), vous pourrez lire la valeur de l'attribut logonHours. Si la valeur est non définie (c'est le cas si vous n'avez jamais touché à cette fonction), cliquez sur l'onglet "Comptes" puis "Horaires d'accès..." et cliquez sur "OK".

Basculez le format de valeur sur "Binaire" et vous allez obtenir une vue comme celle-ci :

Active Directory logonHours exemple

Il faut savoir que :

  • Chaque bit (0 ou 1) représente une heure
  • Chaque octet, soit un groupe de 8 bits, représente 8 heures
  • Donc, trois octets, soit 24 bits au total, représentent une journée
  • L'ordre des jours est le suivant : dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi

Afin de pouvoir effectuer la modification des horaires d'accès avec PowerShell, il sera nécessaire de reproduire ce schéma pour que la valeur soit acceptée et bien interprétée.

III. Premiers pas pour éditer l'attribut logonHours

Pour définir la valeur de l'attribut logonHours, nous devons un tableau d'octets, et non un tableau d'entiers (integer), afin que ce soit accepté par l'annuaire Active Directory.

Ainsi, pour atteindre l'objectif évoqué précédemment, la définition est la suivante :

[byte[]]$Heures = @(0,0,0,224,255,7,224,255,7,224,255,7,224,255,7,224,255,7,0,0,0)

Vous allez me dire, c'est quoi ça ? Et bien, de la conversion entre octets/bits. En gros :

  • Quand il y a 0, cela signifie que l'octet est à 0, donc il y aura 8 bits à 0 : il est donc logique de commencer par trois octets à zéro, car ce sont les trois octets pour dimanche
  • Quand il y a 255, cela signifie que l'octet est à 1, donc il y aura 8 bits à 1 afin d'autoriser une plage de 8 heures

Ce qui veut dire que pour refuser l'ouverture de session tout le temps, nous aurions :

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

Et pour autoriser tout le temps afin de revenir à la configuration par défaut, nous aurions :

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

J'en conviens, ce n'est pas le plus intuitif...!

Pour aller au bout de notre idée, sachez que la commande ci-dessous (qui s'appuie sur la variable $Heures) permet de configurer les horaires d'accès sur tous les comptes de l'Active Directory situés sous la base "OU=Personnel,DC=it-connect,DC=local" (à vous d'utiliser le filtre que vous souhaitez).

[byte[]]$Heures = @(0,0,0,224,255,7,224,255,7,224,255,7,224,255,7,224,255,7,0,0,0)
Get-ADUSer -SearchBase "OU=Personnel,DC=it-connect,DC=local" -Filter * | Foreach{ Set-ADUser -Identity $_ -Replace @{logonhours = $Heures} -Server SRV-ADDS-01.it-connect.local }

Quelques secondes plus tard, le tour est joué !

IV. Modifier les horaires d'accès avec un script PowerShell

Pour ne pas vous embêter avec le calcul binaire et si vos besoins sont différents de cet exemple, sachez que vous pouvez utiliser le script PowerShell ci-dessous (mis à disposition généreusement sur cette page). Il présente l'avantage de vous permettre de sélectionner les heures et les jours à autoriser simplement, et il tient compte aussi du fuseau horaire du contrôleur de domaine (donc à exécuter sur le DC), car sinon ceci peut vous créer des décalages.

Function Set-LogonHours{
   [CmdletBinding()]
   Param(
   [Parameter(Mandatory=$True)][ValidateRange(0,23)]$TimeIn24Format,
   [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True,Position=0)]$Identity,
   [parameter(mandatory=$False)][ValidateSet("WorkingDays", "NonWorkingDays")]$NonSelectedDaysare="NonWorkingDays",
   [parameter(mandatory=$false)][switch]$Sunday,
   [parameter(mandatory=$false)][switch]$Monday,
   [parameter(mandatory=$false)][switch]$Tuesday,
   [parameter(mandatory=$false)][switch]$Wednesday,
   [parameter(mandatory=$false)][switch]$Thursday,
   [parameter(mandatory=$false)][switch]$Friday,
   [parameter(mandatory=$false)][switch]$Saturday
)
Process{
   $FullByte=New-Object "byte[]" 21
   $FullDay=[ordered]@{}
   0..23 | foreach{$FullDay.Add($_,"0")}
   $TimeIn24Format.ForEach({$FullDay[$_]=1})
   $Working= -join ($FullDay.values)
   Switch ($PSBoundParameters["NonSelectedDaysare"])
   {
    'NonWorkingDays' {$SundayValue=$MondayValue=$TuesdayValue=$WednesdayValue=$ThursdayValue=$FridayValue=$SaturdayValue="000000000000000000000000"}
    'WorkingDays' {$SundayValue=$MondayValue=$TuesdayValue=$WednesdayValue=$ThursdayValue=$FridayValue=$SaturdayValue="111111111111111111111111"}
   }
   Switch ($PSBoundParameters.Keys)
   {
    'Sunday' {$SundayValue=$Working}
    'Monday' {$MondayValue=$Working}
    'Tuesday' {$TuesdayValue=$Working}
    'Wednesday' {$WednesdayValue=$Working}
    'Thursday' {$ThursdayValue=$Working}
    'Friday' {$FridayValue=$Working}
    'Saturday' {$SaturdayValue=$Working}
   }

   $AllTheWeek="{0}{1}{2}{3}{4}{5}{6}" -f $SundayValue,$MondayValue,$TuesdayValue,$WednesdayValue,$ThursdayValue,$FridayValue,$SaturdayValue

   # Timezone Check
   if ((Get-TimeZone).baseutcoffset.hours -lt 0){
    $TimeZoneOffset = $AllTheWeek.Substring(0,168+ ((Get-TimeZone).baseutcoffset.hours))
    $TimeZoneOffset1 = $AllTheWeek.SubString(168 + ((Get-TimeZone).baseutcoffset.hours))
    $FixedTimeZoneOffSet="$TimeZoneOffset1$TimeZoneOffset"
   }
   if ((Get-TimeZone).baseutcoffset.hours -gt 0){
    $TimeZoneOffset = $AllTheWeek.Substring(0,((Get-TimeZone).baseutcoffset.hours))
    $TimeZoneOffset1 = $AllTheWeek.SubString(((Get-TimeZone).baseutcoffset.hours))
    $FixedTimeZoneOffSet="$TimeZoneOffset1$TimeZoneOffset"
   }
   if ((Get-TimeZone).baseutcoffset.hours -eq 0){
    $FixedTimeZoneOffSet=$AllTheWeek
   }

   $i=0
   $BinaryResult=$FixedTimeZoneOffSet -split '(\d{8})' | Where {$_ -match '(\d{8})'}

   Foreach($singleByte in $BinaryResult){
    $Tempvar=$singleByte.tochararray()
    [array]::Reverse($Tempvar)
    $Tempvar= -join $Tempvar
    $Byte = [Convert]::ToByte($Tempvar, 2)
    $FullByte[$i]=$Byte
    $i++
   }
   Set-ADUser -Identity $Identity -Replace @{logonhours = $FullByte} 
}
end{
   Write-Output "All Done :)"
}
}

Avec la fonction Set-LogonHours, cette syntaxe :

[byte[]]$Heures = @(0,0,0,224,255,7,224,255,7,224,255,7,224,255,7,224,255,7,0,0,0)

Devient :

Set-LogonHours -TimeIn24Format @(6,7,8,9,10,11,12,13,14,15,16,17,18,19) -Monday -Tuesday -Wednesday -Thursday -NonSelectedDaysare NonWorkingDays

Il faut savoir que :

  • -TimeIn24Format permet de définir les heures pour autoriser l'ouverture de session. Le fait d'indiquer "6", permet d'autoriser le créneau de 6h à 7h.
  • -Monday -Tuesday -Wednesday -Thursday permet de spécifier tous les jours sur lesquels ajouter cette autorisation
  • -NonSelectedDaysare NonWorkingDays permet de déterminer une politique pour les jours non spécifiés (dans la liste précédente). Avec la valeur "NonWorkingDays", on considère que ce sont des jours non travaillés, et donc, que l'on refuse l'ouverture de session. Sinon, vous pouvez utiliser la valeur "WorkingDays"

Donc, pour appliquer les règles sur les comptes utilisateurs de l'OU "OU=Personnel,DC=it-connect,DC=local", cela donnera la commande suivante :

Get-ADUser -SearchBase "OU=Personnel,DC=it-connect,DC=local" -Filter *| Set-LogonHours -TimeIn24Format @(6,7,8,9,10,11,12,13,14,15,16,17,18,19) -Monday -Tuesday -Wednesday -Thursday -NonSelectedDaysare NonWorkingDays

Quelques secondes plus tard, la configuration sera modifiée sur tous les comptes.

Note : ce chapitre n'est pas intégré à l'édition actuelle de l'eBook.

author avatar
Florian BURNEL Co-founder of IT-Connect
Ingénieur système et réseau, cofondateur d'IT-Connect et Microsoft MVP "Cloud and Datacenter Management". Je souhaite partager mon expérience et mes découvertes au travers de mes articles. Généraliste avec une attirance particulière pour les solutions Microsoft et le scripting. Bonne lecture.
Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Envoyer par mail

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.