Get a Report of All (Inactive) Computer Accounts

As an Active Directory domain matures, it tends to accumulate junk. (It’s a lot like me in that way.) This script will scan your domain for computer accounts that haven’t been used in at least 90 days and output the results to an Excel spreadsheet. Since I included the operating system, service packs, manager’s name, and creator SID, you can use this same script for general auditing. Just change two lines.

  • Delete (or comment out) this line:
    $NinetyDays = [DateTime]::Now.Subtract([TimeSpan]::FromDays(90))
  • And remove “| Where-Object {$_.lastLogonTimeStamp -lt $NinetyDays}” from this line:
    $DataFile = Get-QADComputer -sizelimit 0 -IncludedProperties…

I’ve marked both in bold below. That will change this script to report every computer instead of just inactive computers.

In order for this script to work, you have to have Microsoft Excel and Quest ActiveRoles AD Management Snap-In installed on the same computer.

Update 3/22/2013: Added better commenting and refined the code a bit.

# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Filename: Get_InactiveComputers.ps1
# Author: Jay Carper (http://exchangetips.us)
# Version: 13.3.21
# Purpose: Creates an xlsx file of all inactive computer accounts. Requires
# two command line options: domain name and file name. File name must include
# full path and extension.
#
# Example:
# get_inactivecomputers.ps1 my.domain.com “C:\temp\output.xlsx”
#
# Requires Microsoft Excel, Exchange Management Shell, and Quest Active Roles
# AD Management snap-in
#


# Checks for input parameters. If they are present, calls RunReport.
# If they aren’t present, prints syntax info.
Param([string]$Domain,[string]$Output)
if ($Domain -and $Output) {
write-host “Scanning $Domain for inactive computer accounts.”
write-host “Results will be saved to $Output.”
RunReport

# Checks for the E2010 and Quest AD Tools PowerShell
# snapins. If they are not already loaded, it loads them.
if ((get-pssnapin Microsoft.Exchange.Management.PowerShell.E2010 `
-erroraction silentlycontinue) -eq $null) {add-pssnapin `
Microsoft.Exchange.Management.PowerShell.E2010}
if ((get-pssnapin -name quest.activeroles.admanagement `
-erroraction silentlycontinue) -eq $null) {add-pssnapin `
quest.activeroles.admanagement}

# Get a list of computer accounts that have been inactive for at
# least 90 days. Sort the list by ParentContainer and
# lastLogonTimestamp. To get a list of *all* computer accounts
# delete the line that begins with “$NinetyDays =” and remove this
# text from the line that begins “$DataFile = “: “Where-Object
#{$_.lastLogonTimeStamp -lt $NinetyDays} |”
$NinetyDays = [DateTime]::Now.Subtract([TimeSpan]::FromDays(90))
$DataFile = Get-QADComputer -sizelimit 0 -IncludedProperties `
parentcontainer, name, computerrole, lastLogonTimestamp, CreationDate, `
AccountIsDisabled, osname, osversion, osservicepack, managedby, `
description, location, Sid, creatorsid | Where-Object `
{$_.lastLogonTimeStamp -lt $NinetyDays} | select parentcontainer, `
name, computerrole, lastLogonTimestamp, CreationDate, `
AccountIsDisabled,osname, osversion, osservicepack, managedby, `
description, location, Sid, creatorsid | sort-object parentcontainer, `
lastLogonTimestamp

# Create and configure the spreadsheet.
$Excel = New-Object -com Excel.Application
$Excel.visible = $false
$Excel.DisplayAlerts = $false
$Excel.AskToUpdateLinks = $false
$Excel.AlertBeforeOverwriting = $false

# Write the column headers to the spreadsheet.
$Workbook = $excel.workbooks.add()
$Worksheet = $Workbook.worksheets.item(1)
$Worksheet.name = “Inactive Computers Report”
$Worksheet.cells.item(1,1) = “Organizational Unit”
$Worksheet.cells.item(1,2) = “Computer Name”
$Worksheet.cells.item(1,3) = “Computer Role”
$Worksheet.cells.item(1,4) = “Last Logon”
$Worksheet.cells.item(1,5) = “Create Date”
$Worksheet.cells.item(1,6) = “Disabled”
$Worksheet.cells.item(1,7) = “Operating System”
$Worksheet.cells.item(1,8) = “OS Version”
$Worksheet.cells.item(1,9) = “Service Pack”
$Worksheet.cells.item(1,10) = “Managed By”
$Worksheet.cells.item(1,11) = “Description”
$Worksheet.cells.item(1,12) = “Location”
$Worksheet.cells.item(1,13) = “Computer SID”
$Worksheet.cells.item(1,14) = “Creator SID”

# Format header row.
$Range = $Worksheet.usedrange
$Range.font.bold = $true
$Range = $Worksheet.columns
$Range.borders.color = 0

$intRow = 2

# Write the data to the spreadsheet.
foreach ($row in $DataFile) {
# Gets the name of the manager.
$Manager = $row.Managedby
if ($Manager) {
$manager = $manager.trimstart(“CN=”)
$manager = $manager.split(“,”)[0]
}

# Converts the lastLogonTimestamp field to a string.
if ($row.lastLogonTimestamp) {
$LastLogon = $row.lastLogonTimestamp.tostring(“MM/dd/yyyy”)
}
else {$LastLogon = $null}

# Fills in each field of the spreadsheet.
[String]$Role = $row.ComputerRole
$Worksheet.cells.item($intRow,1) = `
$row.ParentContainer.trimstart($Domain + “/”)
$Worksheet.cells.item($intRow,2) = $row.Name
$Worksheet.cells.item($intRow,3) = $Role
$Worksheet.cells.item($intRow,4) = $LastLogon
$Worksheet.cells.item($intRow,5) = $row.CreationDate.tostring(“MM/dd/yyyy”)
$Worksheet.cells.item($intRow,6) = $row.AccountIsDisabled
$Worksheet.cells.item($intRow,7) = $row.OSName
$Worksheet.cells.item($intRow,8) = $row.OSVersion
$Worksheet.cells.item($intRow,9) = $row.OSServicePack
$Worksheet.cells.item($intRow,10) = $manager
$Worksheet.cells.item($intRow,11) = $row.Description
$Worksheet.cells.item($intRow,12) = $row.Location
$Worksheet.cells.item($intRow,13) = $row.SID.Value
$Worksheet.cells.item($intRow,14) = $row.CreatorSID.Value
$intRow = $intRow + 1
}

# Configure column widths and save spreadsheet.
$Range.entirecolumn.autofit()
$Workbook.saveas($Output)

# Close the workbook and the Excel window.
$Workbook.Close()
$Excel.Quit()

# Close the Excel process and the variables.
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel)
Get-Process excel | stop-process -Force
Remove-Variable intRow
Remove-Variable Range
Remove-Variable Workbook
Remove-Variable Worksheet
Remove-Variable DataFile
Remove-Variable row
Remove-Variable Excel
Remove-Variable NinetyDays
Remove-Variable Manager
Remove-Variable Domain
Remove-Variable Output
}

# Syntax info.
else {
write-host “Usage:”
write-host “test [DomainName] [FileName]”
write-host “”
write-host “DomainName = The name of your Active Directory domain.”
write-host “e.g. mydomain.ourdomain.com or ourdomain.com.This will be `
the same domain”
write-host “name shown at the root node of Active Directory Users and `
Computers.”
write-host “”
write-host “FileName = The path and name of the xlsx file you want to `
create.”
write-host “e.g. C:\temp\output.xlsx.”
}

 

I apologize for all the hash marks. This is a lot of code to fit into this narrow column.

If you use this script, let me know how it works for you! If you find any mistakes, let me know that too. I tested it in my own environment, but it’s possible I broke something in attempting to get all the html displayed correctly.

3 responses to “Get a Report of All (Inactive) Computer Accounts”

  1. […] this article, I posted a script that I use for generating a monthly report of inactive computer accounts in […]

  2. Tom says:

    Very Informative article, it describe to find inactive and unused account through dsquery which helps to view inactive user account not logged on within x number of days. I found this active directory cleaner tool(http://www.lepide.com/active-directory-cleaner/). This software helps to find out inactive or disable user or computer account and manage them and get reports on inactive account , never logged on users.

  3. Tom says:

    Thanks for sharing useful PowerShell script which helps to find out inactive computer accounts in active direc tory environment. I tried this active directory cleanup tool ( https://blog.netwrix.com/2018/02/15/the-ten-best-free-active-directory-management-tools/?rid=gDd88kwH ) which generates reports on inactive user accounts who never logged and real last logon information of accounts and manage inactive accounts.

Leave a Reply

Your email address will not be published. Required fields are marked *