# Active Directory User Logon Statistics Email Report (AD 2003+) # http://www.a2-alpha.co.uk # Requires: dsget, dsquery, lastlogon.vbs (http://www.rlmueller.net/Last%20Logon.htm) # lastlogon.vbs should be in the root of C:\ or update the script! # Uses some import functions from: http://huddledmasses.org/powershell-convert-delimiters-import-tab-delimited-text/ # Version 1.0 - Original Script # Version 1.1 - Added Time Status # Version 1.2 - Added Error Checking # 20100706 # Current Version 1.2 # Feedback to dan@a2-alpha.co.uk would be great! ################################################## # PREREQUISITES # Requires: dsget, dsquery, lastlogon.vbs (http://www.rlmueller.net/Last%20Logon.htm) # lastlogon.vbs should be in the root of C:\ or update the script! # Uses some import functions from: http://huddledmasses.org/powershell-convert-delimiters-import-tab-delimited-text/ ################################################## # DESCRIPTION # Queries Active Directory for all users last logon time using the lastlogon.vbs script. # This is then imported into a PowerShell variable # Each user is queried using dsquery and dsget for their display name # Two emails result, the first a list of users who have never logged in and # a list of all users who have not logged in during the period specified (31 days at the moment) # whos accounts are enabled. # Use this script to check this information and disable any unused user accounts for security of the environment. ################################################## # VARIABLES $recipient = "user@domain.com" $sender = "reporting@domain.com" $smtpserver = "EXCHANGE01" $daystocheck = 31 ################################################## $ErrorActionPreference = "SilentlyContinue" $Error.Clear() dsquery > c:\temp.txt If($Error -like "*dsquery*") { Clear "" "dsquery was not found on this machine, please check you are running this on a domain member server" "" } Else { $Error.Clear() dsget > c:\temp.txt If($Error -like "*dsget*") { Clear "" "dsget was not found on this machine, please check you are running this on a domain member server" "" } Else { $Error.Clear() if(!(test-path -path "C:\LastLogon.vbs")) { Clear "" "The LastLogon.vbs Script was not in the default location, please check (C:\LastLogon.vbs)" "" } Else { Clear $currenttime = get-date -UFormat "%T" "$currenttime ... Prerequisites optimal" ################################################## # FUNCTIONS $currenttime = get-date -UFormat "%T" "$currenttime ... Loading Functions" Function Convert-Delimiter([regex]$from,[string]$to) { process { $_ = $_ -replace "(?:`"((?:(?:[^`"]|`"`"))+)(?:`"$from|`"`$))|(?:((?:.(?!$from))*.)(?:$from|`$))","Þ`$1`$2Þ$to" $_ = $_ -replace "Þ(?:$to|Þ)?`$","Þ" $_ = $_ -replace "`"`"","`"" -replace "`"","`"`"" $_ = $_ -replace "Þ((?:[^Þ`"](?!$to))+)Þ($to|`$)","`$1`$2" $_ = $_ -replace "Þ","`"" -replace "Þ","`"" $_ } } Function Import-Delimited([regex]$delimiter=",", [string]$PsPath="") { begin{ $script:tmp = [IO.Path]::GetTempFileName() write-debug "Using tempfile $($script:tmp)" Function Import-String([string]$inputString){ if($inputString.Length -gt 0 ) { write-debug "Importing $inputString" if(($inputString -as [IO.FileInfo]).Exists) { Get-Content $inputString | Convert-Delimiter $delimiter "," | Add-Content $script:tmp } elseif( ((Join-Path $pwd $inputString) -as [IO.FileInfo]).Exists) { Get-Content (Join-Path $pwd $inputString) | Convert-Delimiter $delimiter "," | Add-Content $script:tmp } else { $inputString | Convert-Delimiter $delimiter "," | Add-Content $script:tmp } } else { write-debug "Nothing to Import" } } Import-String $PsPath } process{ Import-String $_ } end { Import-Csv $script:tmp } } Function Get-CName([string]$DistName) # Convert Distinguished name to CN # http://www.a2-alpha.co.uk # 20100705 { process { $_ = $DistName.Split(",") $_ = $_[0] $_.Substring(3) } } function Get-DC([string]$DistName) # Get Domain from Distinguished Name # http://www.a2-alpha.co.uk # 20100705 { Process { $_ = $DistName.Split(",") $Count = 0 ForEach($line in $_) { If($line -like "*DC*") { $Count++ } } $LineTotal = $_.Count If($Count -gt 3) { "Unable to Determine Domain" } ElseIf($Count -eq 3) { $LastLine = ($_.Count)-1 $LastLine1 = ($_.Count)-2 $LastLine2 = ($_.Count)-3 $D1 = ($_[$LastLine]).Substring(3) $D2 = ($_[$LastLine1]).Substring(3) $D3 = ($_[$LastLine2]).Substring(3) "$D3.$D2.$D1" } ElseIf($Count -eq 2) { $LastLine = ($_.Count)-1 $LastLine1 = ($_.Count)-2 $D1 = ($_[$LastLine]).Substring(3) $D2 = ($_[$LastLine1]).Substring(3) "$D2.$D1" } Else { "Unable to Determine Domain" } } } ################################################## # CREATING THE USER OBJECT AND INTERPRETING DATA $currenttime = get-date -UFormat "%T" "$currenttime ... Importing AD User Data" $userdata = @() echo "Name;LastLogon" > c:\lastlogontemp.csv cscript //nologo c:\LastLogon.vbs >> c:\lastlogontemp.csv Get-content c:\lastlogontemp.csv | convert-delimiter ";" "," | set-content c:\lastlogon.csv $userdata += import-csv c:\lastlogon.csv $never = $userdata | select Name, LastLogon | where {$_.LastLogon -like "Never"} $currenttime = get-date -UFormat "%T" "$currenttime ... Building First User Object" $NeverRep = @() ForEach($usrNev in $never) { $NeverObj = "" | Select Name, LastLogon, DisplayName $NeverObj.Name = $usrNev.Name $NeverObj.LastLogon = $usrNev.LastLogon $NeverObj.DisplayName = Get-CName $usrNev.Name $NeverRep += $NeverObj } $loggedinusers = @() $loggedin = $userdata | select Name, LastLogon | where {$_.LastLogon -notlike "Never"} $DomainbeingChecked = Get-DC (($loggedin[0]).Name) $currenttime = get-date -UFormat "%T" "$currenttime ... Building Second User Object" ForEach($user in $loggedin) { $disabled = dsget user $user.Name -disabled $loggedinObj = "" | select Name, LastLogon, DisplayName, Disabled, "Last $daystocheck Days" $loggedinObj.Name = $user.Name [datetime]$lastlogon = (get-date -UFormat "%m/%d/%Y %T"($user.LastLogon)) $loggedinObj.LastLogon = $lastlogon $loggedinObj.DisplayName = Get-CName $user.Name If($disabled -like "*no*") { $loggedinObj.Disabled = "No" } Else { $loggedinObj.Disabled = "Yes" } $loggedinUsers += $loggedinObj [datetime]$checkdate = (get-date((get-date).AddDays(-$daystocheck))) If($loggedinObj.LastLogon -gt ($checkdate)) { $loggedinObj."Last $daystocheck Days" = "Yes" } Else { $loggedinObj."Last $daystocheck Days" = "No" } } ################################################## # REPORTING $currenttime = get-date -UFormat "%T" "$currenttime ... Creating Report" $loggedinUsers = $loggedinUsers $report = $loggedinUsers | sort LastLogon | select DisplayName, "Last $daystocheck Days", LastLogon, Disabled | where {$_."Last $daystocheck Days" -like "No" -and $_.Disabled -like "No"} ################################################## # EMAILING $body = $report | ft -AutoSize if(!$body) { $body = "No Data to Report" } $body = $body | out-string $currenttime = get-date -UFormat "%T" "$currenttime ... Emailing to $recipient" Send-MailMessage -to "$recipient" -From "$sender" -Subject "$DomainbeingChecked - Inactive Users" -SmtpServer "$smtpserver" -Body $body $Never = $NeverRep | Select DisplayName, LastLogon | Out-String Send-MailMessage -to "$recipient" -From "$sender" -Subject "$DomainbeingChecked - Users Never Logged In" -SmtpServer "$smtpserver" -Body $Never ################################################## # TIDY UP TEMP FILES $currenttime = get-date -UFormat "%T" "$currenttime ... Deleting Temp Files" Remove-Item c:\lastlogontemp.csv Remove-Item c:\lastlogon.csv Remove-Item c:\temp.txt ################################################## # END OF SCRIPT $currenttime = get-date -UFormat "%T" "$currenttime ... Script Ends" ################################################## } } }