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
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.