Automatisieren der Erkennung von inaktiven Benutzerkonten mit PowerShell

Die wichtigsten Erkenntnisse

  • Automatisiertes Sicherheitsprotokoll: Das Skript automatisiert die Identifizierung inaktiver Benutzerkonten und erhöht damit die Sicherheit.
  • Individuell einstellbare Grenzwerte: Passen Sie die Inaktivitätsschwelle an die Unternehmensrichtlinien an.
  • Kompatibilität mit verschiedenen Umgebungen: Kann lokale, Active Directory- und Azure AD-Konten verwalten.
  • Zeit- und ressourceneffizient: Automatisiert einen zeitaufwändigen manuellen Prozess.
  • Proaktives Risikomanagement: Hilft bei der Vermeidung von Sicherheitsverstößen durch die Verwaltung potenzieller Schwachstellen.
  • Transparenz und Flexibilität: Da es sich um ein PowerShell-Skript handelt, ist es transparent und kann für bestimmte Anforderungen angepasst werden.
  • Geplante Audits: Kann so eingestellt werden, dass es in regelmäßigen Abständen zur kontinuierlichen Überwachung läuft.
  • Umfassende Berichterstattung: Erzeugt detaillierte Berichte über inaktive Konten, die die Entscheidungsfindung erleichtern.
  • Integration mit Verwaltungstools: Ergänzt und integriert sich mit IT-Management-Lösungen wie NinjaOne.

In der dynamischen Landschaft der IT-Verwaltung haben Sicherheit und Effizienz der Benutzerkontenverwaltung nach wie vor oberste Priorität. Die regelmäßige Überwachung und Beseitigung inaktiver Benutzerkonten ist nicht nur eine bewährte Praxis, sondern eine Notwendigkeit für die Aufrechterhaltung einer sicheren IT-Umgebung. Hier kommen PowerShell-Skripte, wie das, über das wir heute sprechen, für IT-Profis und Managed Service Provider (MSPs), besonders wertvoll zum Einsatz. 

Hintergrund

Das fragliche Skript dient dazu, Administratoren über inaktive oder ungenutzte Konten in einer Windows-Umgebung zu informieren und zu warnen. Inaktive Konten können ein erhebliches Sicherheitsrisiko darstellen, da sie als potenzielle Einstiegspunkte für unbefugten Zugriff dienen, wenn sie kompromittiert werden. Für IT-Profis und MSPs sind solche Skripte entscheidend, um Sicherheitslücken vorzeitig anzugehen und die Einhaltung verschiedener IT-Richtlinien und Vorschriften sicherzustellen.

Das Skript:

<#
.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 {
    
    
    
}

 

Zugriff auf über 300 Skripte im NinjaOne Dojo

Zugang erhalten

Detaillierte Aufschlüsselung

Das Skript arbeitet in einem mehrstufigen Prozess:

  • Initialisierung der Parameter: Sie beginnt mit der Definition von Parametern, einschließlich der Anzahl der Tage, nach denen ein Konto als inaktiv gilt, und einer Option zur Einbeziehung deaktivierter Konten.
  • Umgebungsüberprüfungen: Das Skript überprüft, ob die Maschine einer Domäne beigetreten ist, ein Domänencontroller ist oder mit Azure AD verbunden ist. Dies bestimmt den Umfang der Kontrollen für Konten – lokal, Active Directory oder Azure.
  • Accountabruf: Für Nicht-Domänencontroller werden Kontoinformationen mithilfe von „net.exe user“ oder WMI/CIM-Instanzen abgerufen, während für Domänencontroller das Active Directory PowerShell-Modul verwendet wird.
  • Bewertung der Aktivität: Die Kernfunktion besteht darin, die Benutzerkonten anhand des Datums der letzten Anmeldung und des Passworts im Vergleich zur Inaktivitätsschwelle zu bewerten.
  • Erstellung von Berichten: Inaktive Konten werden in einem Bericht zusammengefasst, mit der Option, deaktivierte Konten auszuschließen.
  • Warnmeldungen und Exit-Codes: Das Skript schließt damit ab, dass es Administratoren über inaktive Konten informiert und mit einem Code beendet, der das Vorhandensein oder Nichtvorhandensein solcher Konten anzeigt.

Mögliche Anwendungsfälle

Stellen Sie sich ein Szenario vor, in dem ein IT-Administrator in einem großen Unternehmen dieses Skript verwendet, um routinemäßig Benutzerkonten zu überprüfen. Sie könnten das Skript so planen, dass es monatlich ausgeführt wird und sie auf Konten aufmerksam macht, die seit mehr als 90 Tagen nicht mehr aktiv waren. Dies ermöglicht eine proaktive Verwaltung der Benutzerkonten und verringert das Risiko von Sicherheitsverletzungen durch inaktive Konten.

Vergleiche

Es gibt alternative Ansätze, wie manuelle Audits oder die Verwendung von Tools von Drittanbietern. Allerdings bietet dieses PowerShell-Skript eine direktere, anpassbare und kostengünstige Lösung. Im Gegensatz zu manuellen Kontrollen automatisiert es den Prozess, spart Zeit und reduziert menschliche Fehler. Im Vergleich zu Tools von Drittanbietern bietet es Transparenz und Flexibilität, da IT-Experten das Skript an ihre spezifischen Bedürfnisse anpassen können.

FAQs

Q1: Kann das Skript zwischen verschiedenen Arten von Benutzerkonten unterscheiden?
A1: Ja, es kann zwischen lokalen, Active Directory- und Azure AD-Konten unterscheiden.

Q2: Ist es möglich, dieses Skript automatisch ablaufen zu lassen?
A2: Absolut, dies kann mithilfe des Windows Taskplaners oder ähnlicher Automatisierungstools durchgeführt werden.

Q3: Kann dieses Skript Konten in einer Cloud-Umgebung verwalten?
A3: Es ist in erster Linie für lokale und Active Directory-Konten konzipiert; für Azure AD-Konten sind zusätzliche Module und Anmeldedaten erforderlich.

Auswirkungen

Die Auswirkungen der Verwendung dieses Skripts sind weitreichend. Durch die Identifizierung inaktiver Konten wird die Angriffsfläche für potenzielle Sicherheitsverstöße erheblich reduziert. IT-Fachleute müssen jedoch verantwortungsvoll mit dem Output umgehen und sicherstellen, dass die Deaktivierung oder Löschung von Konten mit den Unternehmensrichtlinien und den Bedürfnissen der Benutzer:innen übereinstimmt.

Empfehlungen

  • Regelmäßige Audits: Planen Sie das Skript so, dass es in regelmäßigen Abständen ausgeführt wird.
  • Anpassungen: Passen Sie die Skriptparameter an die Unternehmensrichtlinien an.
  • Folgemaßnahmen: Erstellung eines Protokolls für den Umgang mit inaktiven Konten.

Abschließende Überlegungen

Zusammenfassend lässt sich sagen, dass Skripte wie diese, wenn sie effektiv eingesetzt werden, erheblich zur allgemeinen Sicherheit und Effizienz des IT-Betriebsbeitragen. Sie ergänzen Lösungen wie NinjaOne, die umfassende IT-Management-Tools bereitstellen und Administratoren helfen, die Kontrolle über ihre IT-Umgebungen zu behalten. Die Fähigkeit von NinjaOne, sich in PowerShell-Skripte zu integrieren, erhöht seinen Nutzen und macht es zu einer idealen Wahl für proaktives IT-Management.

Nächste Schritte

Der Aufbau eines effizienten und effektiven IT-Teams erfordert eine zentralisierte Lösung, die als vereintes Tool für die Bereitstellung von Dienstleistungen fungiert. NinjaOne ermöglicht es IT-Teams, all ihre Geräte zu überwachen, verwalten, sichern und zu unterstützen, unabhängig von ihrem Ort und komplexer Infrastruktur vor Ort.

Erfahren Sie mehr über NinjaOne Endpoint Management schauen Sie sich eine Live-Tour an oder starten Sie Ihre kostenlose Testversion der NinjaOne Plattform.

Kategorien:

Das könnte Sie auch interessieren

Demo ansehen×
×

Sehen Sie NinjaOne in Aktion!

Mit dem Absenden dieses Formulars akzeptiere ich die Datenschutzerklärung von NinjaOne.

NinjaOne Terms & Conditions

By clicking the “I Accept” button below, you indicate your acceptance of the following legal terms as well as our 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 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).