At work today I undertook the task of auditing a domain administrator account. Because we don’t want to have many system administrator’s profiles on all of our servers we have a specific domain administrator account which is used for routine maintenance and for anything that needs to be done locally on the server. Over time the account has been used for non-login purposes. For instance, if we needed some scheduled task to run as an administrator, we just set this as the RunAsUser. We also did the same for some specific services that we needed to run.

The problem arises when we need to change the password for this admin account. For instance, if one of our system administrators were to leave, for security reasons we must change the password for this account. If we were to simply change the password the domain administrator account would be changed but none of the saved tasks/services would have their credentials updated. When they try to run they’d login using the old password, be denied, and not run.

So, I had been given the task of auditing approximately 125 physicals servers and over 150 virtual machines running a variety of operating systems. A few weeks earlier I had to update a document which describes all of our serves, virtual machines, their specs, operating systems, and purpose. I was able to use this list of ~275 hostnames to filter out the Windows machines. This list was down to ~200 hosts.

So now I had 200 hosts that I was going to check by hand? No. After some quick googling I was able to find out about the `schtasks` command. The schtasks command allows you to manage all scheduled tasks on your local machine, or a remote machine. I was able to successfully query several remote machines with my domain administrator login and view detailed statistics with the following command:

schtasks /QUERY /S [hostname] /V /FO CSV
/QUERY - Specifies that this command is querying existing tasks as opposed to creating new or deleting old tasks.
/S [hostname] - Specifies that this is the host to query, if omitted it queries the local machine. See also the /U and /P (username and password) switches.
/V - Verbose output, a bunch more information including which user the tasks runs as.
/FO CSV - Format output as a CSV (for my purposes this was for easy parsing and eventual excel import)

I wrote a console application to read a list of hosts from a file and run this query on each. The output was then split apart and parsed, and stored for later.

The next task was querying services. This was a bit more of a challenge. There was no nifty command line tool to do this remotely. I ended up using some WMI queries to connect to each machine and query the list of services. The responses were stored for later.

So in my application’s current run state I had a list of all services and scheduled tasks on about 200 windows hosts. I then checked the appropriate fields for the domain account we wanted to audit, then output this as a .csv file. I imported the file into excel and had a nice neat presentable list of relevant tasks/services, their purpose, use, etc.

All in all what would have taken several boring hours by hand (likely 3+) I was able to automate in about two hours. The run time to audit all of these machines only takes about 5 minutes (mostly due to the occasional time out). The ones which errored ~3% we were able to audit ourselves.

I guess the moral of this story is: Automate if possible! If it takes you 5 hours to do a task by hand, and 5 hours to automate the task, automate it! You never know when you might need to run the audit again. This being said, don’t automate every little thing. Don’t spend an hour making an application/script that you could do by hand in 5 minutes. Then again if this is something that you need to do on a regular basis, automate!