This is the fifth post in my “PowerView PowerUsage” series, and follows the same Scenario/Solution/Explanation pattern as the previous entries. The original post contains a constantly updated list of the entire series.
The Scenario
You discovered on an engagement that most user workstations contain the user’s Active Directory samaccount name, e.g. John Smith’s (jsmith@domain.local) machine is named something like jsmith-workstation.domain.local. You want to find all user->workstation mappings, exported as a CSV.
The Solution
https://gist.github.com/HarmJ0y/ae901f21cbba507971b1f2c7eca3b16c
The Explanation
To start off, we enumerate all user samaccountnames in the environment, using the -Properties parameter of Get-DomainUser to again “optimize to the left.” This signals the target domain controller to only return the samaccountname data back to the requestor, reducing the amount of exchange traffic, and causing the entire exchange to be faster than if ALL user data fields were returned (the default.)
We then iterate over each returned result with % (shortcut for ForEach-Object), and query all computers with a wildcard search for the resulting user samaccountname. This is done with Get-DomainComputer, embedding the current samaccountname in a wildcard search with “*$($_.samaccountname)*”, and using -Properties again to just return the dnshostname of the returned systems.
Then we pipe that to select (alias for Select-Object), indicating that we want to expand the given dnshostname field. This returns a flat list/array of one or more string representations of the system dnshostnames, which we then join together to create a pipe-separated string. This is because there may be multiple results (e.g. jsmith-laptop.domain.local and jsmith-workstation.domain.local), so we want to make sure we don’t lose any results. These results are all saved to the variable $a.
The if ($a) {…} check is to ensure that we only process search results that returned non-null values. For each valid result that was returned, we create a custom output object of “UserName” and “ComputerName” fields. Finally, we output everything to a .csv file with Export-CSV, specifying the -NoTypeInformation flag so PS object type information isn’t output to the file. Note that we could also pipe this to ConvertTo-Csv -NoTypeInformation to display the CSV to a screen if we’re executing these actions over some type of RAT.