Automatiser la détection des comptes d’utilisateurs inactifs avec PowerShell

Points à retenir

  • Protocole de sécurité automatisé: Le script automatise l’identification des comptes d’utilisateurs inactifs, ce qui renforce la sécurité.
  • Seuil personnalisable: Ajustez le seuil d’inactivité en fonction des politiques de l’organisation.
  • Compatibilité multi-environnementale: Capable de gérer des comptes locaux, Active Directory et Azure AD.
  • Efficace en termes de temps et de ressources: Automatise un processus manuel qui prendrait beaucoup de temps.
  • Gestion proactive des risques: Permet d’éviter les failles de sécurité en gérant les vulnérabilités potentielles.
  • Transparence et flexibilité: Comme il s’agit d’un script PowerShell, il est transparent et personnalisable pour répondre à des besoins spécifiques.
  • Audits programmés: Il peut être configuré pour fonctionner à intervalles réguliers pour une surveillance continue.
  • Desrapports complets: Génère des rapports détaillés sur les comptes inactifs, ce qui facilite la prise de décision.
  • Intégration avec les outils de gestion: Complète et s’intègre à des solutions de gestion informatique telles que NinjaOne.

Dans le paysage dynamique de la gestion informatique, la sécurité et l’efficacité de la gestion des comptes utilisateurs restent primordiales. Contrôler et traiter régulièrement les comptes d’utilisateurs inactifs n’est pas seulement une bonne pratique, c’est aussi une nécessité pour maintenir un environnement informatique sûr. C’est là que les scripts PowerShell, comme celui dont nous parlons aujourd’hui, deviennent des outils inestimables pour les professionnels de l’informatique et les fournisseurs de services gérés (MSP).  

Contexte

Le script en question est conçu pour identifier et alerter les administrateurs sur les comptes inactifs ou inutilisés dans un environnement Windows. Les comptes inactifs peuvent représenter un risque important pour la sécurité, en servant de points d’entrée potentiels pour un accès non autorisé s’ils sont compromis. Pour les professionnels de l’informatique et les MSP, ces scripts sont essentiels pour remédier de manière préventive aux failles de sécurité et garantir la conformité avec les différentes politiques et réglementations en matière d’informatique.

Le script :

<#
.SYNOPSIS
    Alerts when there is an inactive / unused account that has not logged in or has not had their password set in the specified number of days.
.DESCRIPTION
    Alerts when there is an inactive / unused account that has not logged in or has not had their password set in the specified number of days.
.EXAMPLE
    -IncludeDisabled
    
    Action completed: Run Monitor Account Last Logon Result: FAILURE Output: Action: Run Monitor Account Last Logon, Result: Failed
    WARNING: Inactive accounts detected!

    Username       PasswordLastSet       LastLogon              Enabled
    --------       ---------------       ---------              -------
    Administrator  4/12/2023 9:05:18 AM  11/28/2023 10:31:06 AM    True
    Guest                                12/31/1600 4:00:00 PM    False
    DefaultAccount                       12/31/1600 4:00:00 PM    False
    kbohlander     11/29/2023 1:49:51 PM 12/5/2023 1:09:43 PM      True
    tuser1         12/1/2023 5:59:58 PM  12/4/2023 9:34:32 AM      True
    krbtgt         11/27/2023 3:40:20 PM 12/31/1600 4:00:00 PM    False
    tuser2         12/4/2023 3:40:27 PM  12/31/1600 4:00:00 PM     True
.EXAMPLE
    -Days 60
    
    Action completed: Run Monitor Account Last Logon Result: FAILURE Output: Action: Run Monitor Account Last Logon, Result: Failed
    WARNING: Inactive accounts detected!

    Username       PasswordLastSet       LastLogon              Enabled
    --------       ---------------       ---------              -------
    Administrator  4/12/2023 9:05:18 AM  11/28/2023 10:31:06 AM    True
    kbohlander     11/29/2023 1:49:51 PM 12/5/2023 1:09:43 PM      True
    tuser1         12/1/2023 5:59:58 PM  12/4/2023 9:34:32 AM      True
    tuser2         12/4/2023 3:40:27 PM  12/31/1600 4:00:00 PM     True
.OUTPUTS
    None
.NOTES
    Minimum OS Architecture Supported: Windows 7, Windows Server 2012
    Exit code 1: Found users that haven't logged in over X days and are enabled.
    Exit code 2: Calling "net.exe user" or "Get-LocalUser" failed.
    Release Notes: Renamed script, added Script Variable support, improved ad support, removed requires statement.
By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
    Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
    Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
    Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
    Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
    Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
    Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
    EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
#>

[CmdletBinding()]
param (
    [Parameter()]
    [int]$Days = 90,
    [Parameter()]
    [switch]$IncludeDisabled = [System.Convert]::ToBoolean($env:includeDisabled)
)

begin {
    # Use script variables if available.
    if ($env:days -and $env:days -notlike "null") {
        $Days = $env:Days
    }

    # Change negative days to the expected positive days
    if ($Days -lt 0) {
        $Days = 0 - $Days
    }

    # Date where an account is considered inactive.
    $InactivityCutOff = (Get-Date).AddDays(-$Days)

    function Test-IsDomainJoined {
        if ($PSVersionTable.PSVersion.Major -lt 5) {
            return $(Get-WmiObject -Class Win32_ComputerSystem).PartOfDomain
        }
        else {
            return $(Get-CimInstance -Class Win32_ComputerSystem).PartOfDomain
        }
    }

    function Test-IsDomainController {
        $OS = if ($PSVersionTable.PSVersion.Major -lt 5) {
            Get-WmiObject -Class Win32_OperatingSystem
        }
        else {
            Get-CimInstance -ClassName Win32_OperatingSystem
        }

        if ($OS.ProductType -eq "2") {
            return $true
        }
    }

    # We'll want to warn that we're unable to check the actual Azure AD account 
    # (it requires O365 credentials and a powershell module both of which are not supported by this script).
    function Test-IsAzureJoined {
        try {
            $dsreg = dsregcmd.exe /status | Select-String "AzureAdJoined : YES"
        }
        catch {
            return $False
        }
        if ($dsreg) { return $True }
    }

    # For Non-Domain Controllers we'll check net user for the information we need.
    function Get-NetAccountInfo {
        [CmdletBinding()]
        param(
            [Parameter()]
            [string]$User,
            [Parameter()]
            [switch]$Domain
        )
        process {
            # Get user info from net.exe user
            $netuser = if ($Domain) { net.exe user $user /Domain }else { net.exe user $user }

            $success = $netuser | Select-String 'The command completed successfully.'
            if (-not $success) {
                throw "Failed to retrieve account info for user $user!"
            }

            #Pre-formatted Object
            $Object = New-Object psobject -Property @{
                Username        = $User
                Name            = "$(($netuser | Select-String 'Full Name') -split '  ' | Select-Object -Last 1)".Trim()
                Enabled         = "$(($netuser | Select-String 'Account active') -split '  ' | Select-Object -Last 1)".Trim()
                LastLogon       = "$(($netuser | Select-String 'Last logon') -split '  ' | Select-Object -Last 1)".Trim()
                PasswordLastSet = "$(($netuser | Select-String 'Password last set') -split '  ' | Select-Object -Last 1)".Trim()
            }

            # Formatted object using PowerShell datatypes (for easier parsing later).
            New-Object psobject -Property @{
                Username        = $Object.Username
                Name            = $Object.Name
                Enabled         = if ($Object.Enabled -eq "Yes") { $True }elseif ($Object.Enabled -eq "No") { $False }else { $Object.Enabled }
                LastLogon       = try { Get-Date $Object.LastLogon }catch { $Object.LastLogon };
                PasswordLastSet = try { Get-Date $Object.PasswordLastSet }catch { $Object.PasswordLastSet }
            }
        }
    }
}
process {

    # If it's an azure joined machine we should warn that we're not checking any of the Azure AD Accounts.
    if (Test-IsAzureJoined) {
        Write-Warning -Message "This script is unable to check Azure AD accounts however this script will check the local accounts on this machine."
    }

    $Report = New-Object System.Collections.Generic.List[object]

    # Warn if ad accounts are not able to be checked.
    if (-not (Test-IsDomainController) -and (Test-IsDomainJoined) -and -not (Test-ComputerSecureChannel)) {
        Write-Warning "Domain is not reachable! We'll be unable to check active directory accounts!"
    }

    # There are two ways this script will check for an inactive account one of which uses the Active Directory PowerShell module which is only availalbe on Domain Controllers / machines with RSAT installed.
    if (-not (Test-IsDomainController)) {

        # Compile a list of users to check.
        $Users = if ($PSVersionTable.PSVersion.Major -lt 5) {
            Get-WmiObject -Class "win32_UserAccount"        
        }
        else {
            Get-CimInstance -Class "win32_UserAccount"
        }

        # Grab the account info using net user (which is slightly different if it's a domain account or not).
        $Accounts = foreach ($User in $Users) {
            if ($User.Domain -ne $env:COMPUTERNAME ) {
                Get-NetAccountInfo -User $User.Name -Domain
            }
            else {
                Get-NetAccountInfo -User $User.Name
            }
        }
    }
    else {
        # Older OS's need to have the module manually imported.
        try {
            Import-Module ActiveDirectory
        }
        catch {
            Write-Error -Message "[Error] Failed to import PowerShell Active Directory Module. Is RSAT installed?" -Category DeviceError -Exception (New-Object System.Exception)
        }

        # Compile a list of users with the relevant attributes
        $Users = Get-AdUser -Filter * -Properties SamAccountName, DisplayName, PasswordLastSet, lastLogonTimestamp, lastLogon, Enabled
        
        # Convert that into a more parseable object
        $Accounts = foreach ($User in $Users) {
            $LastLogon = [datetime]::FromFileTime($User.lastLogon)
            $LastLogonTimeStamp = [datetime]::FromFileTime($User.LastLogonTimestamp)
            New-Object psobject -Property @{
                Username        = $User.SamAccountName
                Name            = $User.DisplayName
                Enabled         = $User.Enabled
                LastLogon       = if ($LastLogon -gt $LastLogonTimeStamp) { $LastLogon }else { $LastLogonTimeStamp }
                PasswordLastSet = $User.PasswordLastSet
            }
        }
    }

    # Compile a list of accounts that could be considered inactive
    $InactiveAccounts = $Accounts | Where-Object { ($_.LastLogon -eq "Never" -or $_.LastLogon -lt $InactivityCutOff) -and $_.PasswordLastSet -lt $InactivityCutOff }

    # Filter out disabled accounts if we're asked to.
    if ($IncludeDisabled) {
        $InactiveAccounts | ForEach-Object { $Report.Add($_) }
    }
    else {
        $InactiveAccounts | Where-Object { $_.Enabled -notlike $False } | ForEach-Object { $Report.Add($_) }
    }

    # If no inactive accounts exit
    if (-not $Report) {
        Write-Host "No inactive accounts detected!"
        exit 0
    }

    Write-Warning "Inactive accounts detected!"
    $Report | Format-Table -AutoSize -Property Username, PasswordLastSet, LastLogon, Enabled | Out-String | Write-Host
    exit 1
}
end {
    
    
    
}

 

Accédez à plus de 700 scripts dans le Dojo NinjaOne

Obtenir l’accès

Description détaillée

Le script fonctionne en plusieurs étapes :

  • Initialisation des paramètres: Il commence par définir des paramètres, notamment le nombre de jours pendant lesquels un compte est considéré comme inactif et une option permettant d’inclure les comptes désactivés.
  • Contrôles de l’environnement: Le script vérifie si la machine est reliée à un domaine, à un contrôleur de domaine ou à Azure AD. Cela détermine l’étendue des vérifications de comptes – local, Active Directory ou Azure.
  • Récupération de compte: Pour les contrôleurs non-domaines, il récupère les informations sur les comptes à l’aide de net.exe user ou d’instances WMI/CIM, tandis que pour les contrôleurs de domaines, il utilise le module Active Directory PowerShell.
  • Évaluation de l’activité: La fonction principale consiste à évaluer les comptes d’utilisateurs sur la base de leurs dernières dates de connexion et de définition du mot de passe par rapport au seuil d’inactivité.
  • Génération de rapports: Les comptes inactifs sont compilés dans un rapport, avec une option permettant d’exclure les comptes désactivés.
  • Alertes et codes de sortie: Le script se termine en alertant les administrateurs de tout compte inactif et en sortant avec un code indiquant la présence ou l’absence de tels comptes.

Cas d’utilisation potentiels

Prenons l’exemple d’un administrateur informatique d’une grande entreprise qui utilise ce script pour vérifier régulièrement les comptes d’utilisateurs. Ils peuvent programmer l’exécution du script une fois par mois, afin d’être alertés des comptes qui n’ont pas été actifs depuis plus de 90 jours. Cela permet une gestion proactive des comptes d’utilisateurs, réduisant ainsi le risque de failles de sécurité dues à des comptes dormants.

Comparaisons

Il existe d’autres approches, telles que les audits manuels ou l’utilisation d’outils tiers. Toutefois, ce script PowerShell offre une solution plus directe, plus personnalisable et plus économique. Contrairement aux contrôles manuels, il automatise le processus, ce qui permet de gagner du temps et de réduire les erreurs humaines. Par rapport aux outils tiers, il offre transparence et flexibilité, les professionnels de l’informatique pouvant modifier le script en fonction de leurs besoins spécifiques.

FAQ

Q1 : Le script peut-il faire la distinction entre les différents types de comptes d’utilisateurs ?
A1 : Oui, il peut faire la distinction entre les comptes locaux, Active Directory et Azure AD.

Q2 : Est-il possible de programmer l’exécution automatique de ce script ?
A2 : Absolument, cela peut être fait en utilisant le planificateur de tâches de Windows ou des outils d’automatisation similaires.

Q3 : Ce script gère-t-il les comptes dans un environnement en nuage ?
A3 : Il est principalement conçu pour les comptes locaux et Active Directory ; les comptes Azure AD nécessitent des modules et des informations d’identification supplémentaires.

Implications

Les implications de l’utilisation de ce script sont considérables. En identifiant les comptes inactifs, il réduit considérablement la surface d’attaque pour les failles de sécurité potentielles. Toutefois, les professionnels de l’informatique doivent gérer les résultats de manière responsable, en veillant à ce que la désactivation ou la suppression des comptes soit conforme aux politiques de l’organisation et aux besoins des utilisateurs.

Recommandations

  • Audits réguliers: Programmez l’exécution du script à intervalles réguliers.
  • Personnalisation: Adaptez les paramètres du script aux politiques de l’organisation.
  • Actions de suivi: Établissez un protocole pour le traitement des comptes inactifs.

Conclusion :

En conclusion, les scripts de ce type, lorsqu’ils sont utilisés efficacement, contribuent de manière significative à la sécurité et à l’efficacité globales des opérations informatiques. Ils complètent des solutions telles que NinjaOne, qui fournit des outils de gestion informatique complets, aidant les administrateurs à garder le contrôle de leurs environnements informatiques. La capacité de NinjaOne à s’intégrer aux scripts PowerShell renforce son utilité, ce qui en fait un choix idéal pour une gestion informatique proactive.

Pour aller plus loin

Créer une équipe informatique efficace et performante nécessite une solution centralisée qui soit l’outil principal pour fournir vos services. NinjaOne permet aux équipes informatiques de surveiller, gérer, sécuriser et prendre en charge tous les appareils, où qu’ils soient, sans avoir besoin d’une infrastructure complexe sur site.

Pour en savoir plus sur NinjaOne Endpoint Management, participez à une visite guidée ou commencez votre essai gratuit de la plateforme NinjaOne.

Vous pourriez aussi aimer

Voir la démo×
×

Voir NinjaOne en action !

En soumettant ce formulaire, j'accepte la politique de confidentialité de NinjaOne.

Termes et conditions NinjaOne

En cliquant sur le bouton « J’accepte » ci-dessous, vous indiquez que vous acceptez les termes juridiques suivants ainsi que nos conditions d’utilisation:

  • Droits de propriété: NinjaOne possède et continuera de posséder tous les droits, titres et intérêts relatifs au script (y compris les droits d’auteur). NinjaOne vous accorde une licence limitée pour l’utilisation du script conformément à ces conditions légales.
  • Limitation de l’utilisation: Les scripts ne peuvent être utilisés qu’à des fins personnelles ou professionnelles internes légitimes et ne peuvent être partagés avec d’autres entités.
  • Interdiction de publication: Vous n’êtes en aucun cas autorisé à publier le script dans une bibliothèque de scripts appartenant à, ou sous le contrôle d’un autre fournisseur de logiciels.
  • Clause de non-responsabilité: Le texte est fourni « tel quel » et « tel que disponible », sans garantie d’aucune sorte. NinjaOne ne promet ni ne garantit que le script sera exempt de défauts ou qu’il répondra à vos besoins ou attentes particulières.
  • Acceptation des risques: L’utilisation du script est sous votre propre responsabilité. Vous reconnaissez qu’il existe certains risques inhérents à l’utilisation du script, et vous comprenez et assumez chacun de ces risques.
  • Renonciation et exonération de responsabilité: Vous ne tiendrez pas NinjaOne pour responsable des conséquences négatives ou involontaires résultant de votre utilisation du script, et vous renoncez à tout droit ou recours légal ou équitable que vous pourriez avoir contre NinjaOne en rapport avec votre utilisation du script.
  • EULA: Si vous êtes un client de NinjaOne, votre utilisation du script est soumise au contrat de licence d’utilisateur final qui vous est applicable (End User License Agreement (EULA)).