PowerShell AD Enumeration Script

by Vince
in Blog
Hits: 2564

With each new tool that pops up on the Internet, there's a/v signature written within the very near future of its birth to detect and remove it.  For example, PowerSploit's PowerView which is described as:  "a PowerShell tool to gain network situational awareness on Windows domains."  Technically, there's nothing malicious about this tool as far as I can tell other than its purpose is primarily used for hacking.  When downloaded to a system with endpoint protection, the PowerView script is immediately removed.

Not that I've looked under the PowerView hood but I can imagine it's making calls to existing commands and presenting the output to us.  I'm a huge proponent of living off the land because we're using the system against itself and as far as endpoint protection, we'll go unnoticed.  That's not to say that alerts aren't written for PowerShell execution but that's a separate issue. 

When thinking about situational awareness, what do we want to know?  I might want a list of users, a list of admins, a list of computers, a list of servers, and maybe I'd want to hunt through data in which case, I'd want to know about open shares.  Before I get to the script, it's worth mentioning that this script assumes the ActiveDirectory module exists and is imported.  If you're on a domain controller, it exists.  If we're uncertain, we can run:

Get-Module -ListAvailable -Name ActiveDirectory

If we're on a Windows 10 workstation, for example, we could run the following:

Add-WindowsCapability -online -Name "Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0"; Import-Module ActiveDirectory

The above will install the module and import it for us.

You can obviously run all of these commands individually without the menu system -- and that might actually be better than dropping a script on the filesystem.  But the purpose here is to give you some ideas with this skeleton. 

Clear-Host
function Show-Menu
{
    param (
        [string]$Title = 'Domain Enum'
    )
    Clear-Host
    Write-Host "================ $Title ================"
    Write-Host " "
    Write-Host "1: Press '1' to get Domain Users"
    Write-Host "2: Press '2' to get Domain Admins"
    Write-Host "3: Press '3' to get Enterprise Admins"
    Write-Host "4: Press '4' to get Domain Computers"
    Write-Host "5: Press '5' to get Domain Servers"
    Write-Host "6: Press '6' to get Local Shares"
    Write-Host "7: Press '7' to get ALL Network Shares"
    Write-Host "Q: Press 'Q' to quit."
}
 
do
{
    Show-Menu –Title 'Domain Enum'
    Write-Host " "
    $input = Read-Host "What would you like to do?"
    switch ($input)
    {
        '1' {               
                Get-ADUser -Filter * | select UserPrincipalName
            }
        '2' {               
                Get-ADGroupMember -Identity "Domain Admins" -Recursive | select name
            }
        '3' {               
                Get-ADGroupMember -Identity "Enterprise Admins" -Recursive | select name
            }
        '4' {               
                Get-ADComputer -Filter * | select DNSHostName
            }
        '5' {               
                Get-ADComputer -Filter 'OperatingSystem -like "*Server*"' -Properties OperatingSystem | select DNSHostName,OperatingSystem
            }

        '6' {               
                Get-SmbShare -Special $false
            }
        '7' {               
                $ErrorActionPreference = "SilentlyContinue"; Get-ADComputer -Filter * | select DNSHostName | ForEach-Object{ Invoke-Command -ComputerName $_.DNSHostName -ScriptBlock {Get-SmbShare -Special $false -EA SilentlyContinue} }
            }
        'q' {
                 return
            }
    }
    Write-Host " "
    pause
}
until ($input -eq 'q')

A final point before I wrap this up, the last entry which hunts for shares -- this will attempt to enumerate shares on systems it discovers in the directory.  We don't know if these systems are up or down.  Nor do we know if these systems exist in the domain which is to say that it's not uncommon for systems to die and there name still lives on in the directory because someone forgot to remove it.  One more point, the $false flag hides hidden shares.  For my purpose, I want to know about all other shares, I'll assume the hidden shares are there because that's the default.