Introducing StealthAUDIT 11.5! Complete your cloud security puzzle. LEARN MORE

Cleaning Up Unused Service Accounts – Part 2: Detecting Common Locations Where Service Accounts Are Used

Blog >Cleaning Up Unused Service Accounts – Part 2: Detecting Common Locations Where Service Accounts Are Used
Cleaning Up Unused Service Accounts – Part 2: Detecting Common Locations Where Service Accounts Are Used

In this post (a continuation from part 1), I will continue the series for how to do a service account clean up in Active Directory by going into details of common locations in a Windows OS that can be used to configure service accounts as well as then showing how to collect these using PowerShell to enable an easy collection of data for later collation as well as being able to help your company documentation for service accounts.

Windows Services

One of the most common places to find Service Accounts being utilised is obviously in Windows Services (Services.msc). To find out whether a Windows System has services configured to run as a service account using the GUI it is as simple as following the steps below:

Now to do the same in PowerShell is straight forward using WMI. Below are 3 different ways you may want to use PowerShell and WMI to retrieve this information and store it in a CSV for later processing:

# WMI Query To Retrieve All Services, Get the startname (Log on As) and Export It to Excel on Local Computer
$CSV_File_Path  = "" #Path to excel file to export information to
$Services = Get-WmiObject Win32_Service
$Services_Info = $Services | Select-Object Name, Caption, StartName, StartMode
$Services_Info | Export-Csv $CSV_File_Path

# WMI Query to a Remote Computer to retireve Service Information
$CSV_File_Path = "" #Path to excel file to export information to
$Computer_Name = "" #Name or IP Address of the computer to query
$Services = Get-WmiObject Win32_Service -ComputerName $Computer_Name
$Services_Info = $Services | Select-Object PSComputerName, Name, Caption, StartName, StartMode
$Services_Info | Export-Csv $CSV_File_Path

# Query Multiple Computers Using a CSV List
$CSV_Input_File = "" # Path to CSV File where A1 is a header called ComputerName and A2 and below are Computer Names
$CSV_File_Path = "" #Path to excel file to export information to
$Computer_Names_Import = Import-Csv $CSV_Input_File
foreach ($Computer_Name in $Computer_Names_Import)
	$Computer_Name = $Computer_Name.ComputerName
	$Services = Get-WmiObject Win32_Service -ComputerName $Computer_Name
	$Services_Info = $Services | Select-Object PSComputerName, Name, Caption, StartName, StartMode
	$Services_Info | Export-Csv $CSV_File_Path -Append

Once the file has been exported you can then just enable filters in Excel and then remove the Default Windows Stuff like LocalSystem and you’ll be left with the configured Windows Service Accounts as shown below:

Once this has been run across all servers you should have a good idea of all service accounts that are in place and running Windows Services. Now we have Windows Services sorted let’s look at getting Scheduled Tasks.

Scheduled Tasks

Service Accounts are often used to run scheduled tasks so permissions can be specifically set up for the task to keep a least privileged permissions model in place. To look at scheduled tasks using the GUI you will need to check each task for the account it runs as due to it not being available in a column like it is for Windows Services.

When Scheduled Tasks in more recent versions of windows create tasks for all users who login, this means that tasks like the one above (User_Feed_Syncronization) can be safely ignored but all others should be checked for Service Accounts. To inventory Scheduled Tasks it can be a slight pain due to different handling between PS and OS Versions so one of the easiest ways to get the basic information we need for this which I previously found was to use the Scheduled Tasks files found in C:WindowsSystem32Tasks and then extract the data from the configuration XML Files that I required. Of course, there is now the ScheduledTasks PowerShell module which also helps with this but I don’t believe it can query older systems so ill show both methods of how to get Scheduled Task Information

Using ScheduledTasks Cmdlets

Using the ScheduledTasks CMDLETs are fine and the simplest if they can work across all of the servers you need to query for this. Below is a PowerShell snippet for getting tasks with username and logon type information exported to an excel file for later looking at:

# Getting Scheduled Tasks Using Get-ScheduledTask
$CSV_File_Path = "" #Path to excel file to export information to
$All_Scheduled_Tasks = Get-ScheduledTask #This will also include the default microsoft ones
$Scheduled_Tasks_ExMicrosoft = $All_Scheduled_Tasks | Where-Object { $_.TaskPath -notlike "Microsoft*" } # Exclude the Microsoft Tasks
$Scheduled_Tasks_Info = $Scheduled_Tasks_ExMicrosoft | Select-Object TaskPath, TaskName, @{ Name = "Username"; Expression = { $_.Principal.UserID } }, @{ Name = "LogonType";  Expression = { $_.Principal.LogonType } }
$Scheduled_Tasks_Info | Export-Csv $CSV_File_Path

Using the Task XML Data

Using the Task Files to get the data seems to work well across all OS’s, it is a bit sloppier, but still yields the results required which is tasks with the logon type and usernames of the accounts running them.

Below is the snippet which uses this method to output tasks to a CSV file:

# Getting Scheduled Tasks Using XML Files in C:WindowsSystem32Tasks
$CSV_File_Path = "" #Path to excel file to export information to
$Task_Folder_Location = "C:WindowsSystem32Tasks" # Path to the Scheduled Tasks folder
$Task_XML_Files_All = Get-ChildItem $Task_XML_Files -Recurse
$Task_XML_Files_Filtered = $Task_XML_Files_All | Where-Object { $_.FullName -notlike "$Task_Folder_LocationMicrosoft*" }
foreach ($Task_XML_File in $Task_XML_Files_Filtered)
	$Task_XML_File_Path = $Task_XML_File.FullName
	#Getting the Principal and Logon Type
	[XML]$XML_Content = Get-Content $Task_XML_File_Path
	$Task_Principal = $XML_Content.Task.Principals.Principal.UserID
	$Task_LogonType = $XML_Content.Task.Principals.Principal.LogonType
	$Output = $Task_XML_File | Select-Object Name, FullName, @{ Name = "Task_Principal"; Expression = { $Task_Principal } }, @{ Name = "Task_LogonType"; Expression = { $Task_LogonType } }
	$Output | Export-Csv $CSV_File_Path -Append

So now after using this, you should have an output of all Windows Services as well as Scheduled Tasks which will allow you to track a get portion of service accounts. The next area is to look at IIS Application Pools (if you’re a company that uses IIS).

IIS Application Pools

IIS Application Pools are very common still, especially for running internal websites. To limit the scope of access of each application pool it is possible to give them service accounts to enable the least privileged permissions model for processes.

Application Pools are simple to find through the GUI on a server but slightly harder using PowerShell. To find application pools using the GUI follow the instructions below:

As stated earlier it can be quite tricky getting Application Pools through PowerShell.

First and foremost, for these to work you’ll need to ensure that the system has the IIS Management Scripts and Tools feature installed on the server you want to interrogate. This can be checked and installed using the below snippet of PowerShell. This will enable the use of the WebAdministration Module:

# Check to see if the IIS Management Scripts and Tools Feature is Installed and if not install it
$Feature_Name = "Web-Scripting-Tools"
$Feature = Get-WindowsFeature -Name $Feature_Name
If (-not ($Feature.Installed))
	Install-WindowsFeature -Name $Feature_Name

Once this is installed it is possible for you to use the WebAdministration Module which, when imported, creates the IIS PS Drive in PowerShell to be used to get the Service Account information for the systems:

# Get Application Pools using WebAdministration Module on Single Machine
$CSV_File_Path = "" #Path to excel file to export information to
$Application_Pools = Get-ChildItem "IIS:AppPools"
$Application_Pools_WithUsername = $Application_Pools | Select-Object Name, State, @{ Name = "Username"; Expression = { $_.ProcessModel.Username } }
$Application_Pools_WithUsername | Export-Csv $CSV_File_Path

# Get Application Pools Using WebAdministration on Multiple Machines
$CSV_Input_File = "" # Path to CSV File with A1 set to ComputerName and then A2 and below being the actual computer names
$CSV_File_Path = "" # Path to excel file to export information to
$Output_Folder = "" # Path to a folder to import all the export files to
$CSV_Computers = Import-Csv $CSV_Input_File
$Computers = $CSV_Computers.ComputerName
Invoke-Command -ComputerName $Computers -ArgumentList $CSV_File_Path -ScriptBlock {
	$Application_Pools = Get-ChildItem "IIS:AppPools"
	$Application_Pools_WithUsername = $Application_Pools | Select-Object Name, State, @{ Name = "Username"; Expression = { $_.ProcessModel.Username } }
	$Application_Pools_WithUsername | Export-Csv $CSV_File_Path

# Collecting the output files by using Admin Shares and modifying the $CSV_File_Path Parameter to get the location on target machine
foreach ($Computer in $Computers)
	$UNC_File_Path = "\$Computer$($CSV_File_Path -replace ':', '$')"
	Move-Item -Path $UNC_File_Path -Destination "$Output_Folder$Computer.csv"

# Merging the files into a single CSV File called Merge.csv
$All_CSV_To_Merge = Get-ChildItem -Path $Output_Folder
foreach ($CSV in $All_CSV_To_Merge)
	$CSV_Import = Import-Csv $CSV.FullName
	$CSV_Import_Update = $CSV_Import | Select-Object Name, State, Username, @{ Name = "ComputerName"; Expression = { $CSV.Name } }
	$CSV_Import_Update | Export-Csv "$Output_FolderMerge.csv" -Append

Now I totally understand that the output and collection of files from remote machines are far from ideal, but this may help get this done without a lot of red tape of enabling credential delegation to drop them in a remote share or stopping Computer Accounts authenticating to a share, or having a completely open share, etc. I am very sure there are better ways to do it, but this is the way I thought of it. Please do leave a comment if you have a better way to get the information!!

Now I just want to add a quick note here that I am very much aware that there are other locations inside IIS where Service Accounts can be used: Virtual Directories, Authentication Settings, etc. Whilst I will not cover these here I will look to add them to the STEALTHbits GitHub along with much nicer snippets, functions for anyone to use in the next few months.

Next Steps

There are plenty of other locations inside Windows where you can use Service Accounts but for now, let’s focus on the 3 CSV Files we have generated here:

  1. Windows Services
  2. Scheduled Tasks
  3. IIS Application Pools

Each of these files, except the Active Directory output from Part 1, will have a ComputerName ( or PSComputerName ) field which can be used to get a better view of what is configured on a server. They will all also have a username field which can be used to easily see how many servers a single account may be used on. Depending on the size of the company you work in and your own preferences you could use Excel VLOOKUP formulas to organise this data in Excel or you could use a database to ingest the CSV Files into and then set up relationships between the fields and query the data to get back the critical information you need.


This data gathering and sorting can be quite cumbersome to do but it is well worth it if you don’t have the data anywhere else to hand. Our StealthAUDIT application can provide reports for these commonly used accounts as well as provide you with the raw data if you wished to use it. As we now have the data for, what I believe to be, the three most common places where service accounts are used the next step is to get your Domain Controller Security Event Logs (Kerberos and NTLM) to then be able to track Service Accounts to servers for further investigation.

Featured Asset

Comments (0)

Leave a Reply

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




© 2022 Stealthbits Technologies, Inc.

Start a Free Stealthbits Trial!

No risk. No obligation.