2016-04-02

latest change:

+ Made efficiency changes with file access and fixed an error from the last push



Dark Observer – Windows PowerShell domain scanning tool

It is a culmination of various scripts to be used for scanning windows networks for compliance as well as detecting malicious activity.
Available Options:

conf[c]…….Set scan configuration variables

set………..View current configuration

scan[s]…….Execute Scan

home[h]…….Return to prompt

exit[x]…….Return to powershell



darkobserver

Which scan do you want to perform?

[0] ALL

[1] User Executable Enumeration

[2] USB enumeration

[3] Auto-Run disabled

[4] Start-up Programs

[5] Scheduled tasks

[6] Running Processes

[7] Driver Query

[8] Service Query

[9] Network Connections

[10] Installed Software

[11] Network Shares

[12] Network Shares Permissions

[13] Antivirus Status

[14] Local accounts

[15] Domain accountsr

Script:

#Requires -Version 2.0

############################################
# START Menu Functions
############################################

Function AsciiArt
{
switch($(Get-Random(6)))
{
0{ Write-Host @'

______ __ _______ __
| _ \ .---.-.----.| |--. | _ | |--.-----.-----.----.--.--.-----.----.
|. | \| _ | _|| < |. | | _ |__ --| -__| _| | | -__| _|
|. | \___._|__| |__|__| |. | |_____|_____|_____|__| \___/|_____|__|
|: 1 / |: 1 |
|::.. . / |::.. . |
`------' `-------'

'@}
1{Write-Host @'

_ ()_() _ .-. ___ oo_ wWw()_()wWw wWwwWw()_()
/||_ /) (O o|OO) .' ) c(O_O)c (___)_/ _)-< (O)(O o)(O) (O)(O)(O o)
/o_)(o)(O) |^_\||_/ .' ,'.---.`, (O)(O)\__ `. / __)^_\( \ / )/ __)^_\
/ |(\ //\\ |(_)) / / /|_|_|\ \/ _\ `. |/ ( |(_))\ \ / // ( |(_))
| | ))(__)| | /||\ \ | \_____/ || |_)) _| ( _) | / / \/ ( _) | /
| |///,-. | )|\(/\)\ `. '. `---' .`| |_)),-' |\ \_ )|\\ \ `--' /\ \_ )|\\
\__/-' ''(/ \) `._) `-...-' (.'-'(_..--' \__|/ \) `-..-' \__|/ \)

'@}
2{Write-Host @'

_____ _____
__|__ |__ ____ _____ __ __ __|__ |__ ______ ______ ______ _____ __ _______ _____
| \ | \ | || |/ / / \ | > ___| ___| \ \ // ___| |
| \ | \| \| \ | | | < `-.`-.| ___| \\ \//| ___| \
|______/ __|__|\__\__|\__\__|\__\ \_____/ __|______>______|______|__|\__\\__/ |______|__|\__\
|_____| |_____|

'@}
3{Write-Host @'

\______ \ _____ _______| | __ \_____ \\_ |__ ______ ______________ __ ___________
| | \\__ \\_ __ \ |/ / / | \| __ \ / ___// __ \_ __ \ \/ // __ \_ __ \
| ` \/ __ \| | \/ < / | \ \_\ \\___ \\ ___/| | \/\ /\ ___/| | \/
/_______ (____ /__| |__|_ \ \_______ /___ /____ >\___ >__| \_/ \___ >__|
\/ \/ \/ \/ \/ \/ \/ \/

'@}
4{Write-Host @'

___ ___ _
/ \__ _ _ __| | __ /___\ |__ ___ ___ _ ____ _____ _ __
/ /\ / _` | '__| |/ / // // '_ \/ __|/ _ \ '__\ \ / / _ \ '__|
/ /_// (_| | | | < / \_//| |_) \__ \ __/ | \ V / __/ |
/___,' \__,_|_| |_|\_\ \___/ |_.__/|___/\___|_| \_/ \___|_|

'@}
5{Write-Host @'

____,____,____, __, , ____, ____ ____,____,____,__ _,____,____,
(-| (-/_|(-|__)( |_/ (-/ \(-|__|-(__(-|_,(-|__|-\ /(-|_,(-|__)
_|__// |,_| \,_| \, _\__/,_|__)____)_|__,_| \,_\/ _|__,_| \,
( ( ( ( ( ( ( ( ( ( ( (

'@}
}
}

Function Resize #set console size
{
if ($host.Name -eq 'ConsoleHost')
{
$Width = 120
$height = 45

# buffer size can't be smaller than window size
if ($Width -gt $host.UI.RawUI.BufferSize.Width) {
$host.UI.RawUI.BufferSize = New-Object -TypeName System.Management.Automation.Host.Size -ArgumentList ($Width, $host.UI.RawUI.BufferSize.Height)
}

# if width is too large, set to max allowed size
if ($Width -gt $host.UI.RawUI.MaxPhysicalWindowSize.Width) {
$Width = $host.UI.RawUI.MaxPhysicalWindowSize.Width
}

# if height is too large, set to max allowed size
if ($Height -gt $host.UI.RawUI.MaxPhysicalWindowSize.Height) {
$Height = $host.UI.RawUI.MaxPhysicalWindowSize.Height
}

# set window size
$host.UI.RawUI.WindowSize = New-Object -TypeName System.Management.Automation.Host.Size -ArgumentList ($Width, $Height)
}
}

#Change text color to yellow when prompting a user for input
Function ReadYellow
{
[console]::ForegroundColor = "yellow"
$input = Read-Host
[console]::ForegroundColor = "white"
Return $input
}

#Make temporary directory for scan data before parsing
Function CreateTempDir
{
$ErrorActionPreference = "Stop"
for($i=0; $i -lt 15; $i++)
{
try {
if ((Test-Path $TEMP_DIR -ErrorAction SilentlyContinue) -eq $true)
{
Remove-Item -Recurse -Force "$TEMP_DIR\*"
}
mkdir -Path $TEMP_DIR -Force | Out-Null
break
} catch {
sleep 1
}
}
if($i -eq 30)
{
Write-Host -ForegroundColor Red "Unable to create temporary directory: $TEMP_DIR"
ExitFunction
}
}

#Check for admin rights and psexec
Function CheckDependancies
{
param($PSScriptRoot)

#Check that user is a Domain Admin
try {
$admin=([ADSISEARCHER]"samaccountname=$($env:USERNAME)").Findone().Properties.memberof |
Select-String "Domain Admins"
} Catch {}

if($admin)
{
$Script:AdminPrivs = $true
}
else {$Script:AdminPrivs = $false}

#Add current directory to path
$env:path = $env:path+";.\"

#Check for presence of psexec and store to a variable in $scan hash table
try {
if (test-path .\psexec.exe)
{
$script:scan.psexec = Get-Command ".\psexec.exe" -ErrorAction Stop
Return
}
elseif($script:scan.psexec = Get-Command "psexec.exe" -ErrorAction Stop){Return}

} Catch { #psexec not in path. Check in script directory
if (test-path $PSScriptRoot\psexec.exe)
{
$script:scan.psexec = Get-Command "$PSScriptRoot\psexec.exe"
}
else
{
Write-Warning "Unable to find psexec.exe in your PATH. Payloads will only attempt WMI for remote execution"
Return
}
}
}

#Initial menu presented to start scans
Function DisplayMenu
{
#keep looping until input is valid
while($true){
Write-Host "
Choose scan type:

[1] STANDARD
[2] ADVANCED

Choice: " -NoNewLine
$ScanType = ReadYellow
switch($ScanType)
{
1{Clear-Host; if(-not (DisplayStandardMenu)){Return}}
2{Clear-Host; if(-not (DisplayAdvancedMenu)){Return}}
"h"{Clear-Host; Return}
"home"{Clear-Host; Return}
"x"{ExitFunction}
"exit"{ExitFunction}
default{Write-Host -ForegroundColor Red "Invalid Choice: $ScanType"}
}
}
}

Function DisplayStandardMenu
{
Write-Host "
Which scan do you want to perform?

[0] ALL
[1] User Executable Enumeration
[2] USB enumeration
[3] Auto-Run disabled
[4] Start-up Programs
[5] Scheduled tasks
[6] Running Processes
[7] Driver Query
[8] Service Query
[9] Network Connections
[10] Installed Software
[11] Network Shares
[12] Network Shares Permissions
[13] Antivirus Status
[14] Local accounts
[15] Domain accounts

Choice: " -NoNewLine
$ScanChoice = ReadYellow
Write-Host ""
switch($ScanChoice)
{
"h"{Clear-Host; Return $false}
"home"{Clear-Host; Return $false}
"x"{ExitFunction}
"exit"{ExitFunction}
12{
#If network shares permissions is chosen make sure that network shares data is present.
#If Network shares scan has not been run then run it before network shares permissions.
if(-not ((Get-ChildItem "$OUT_DIR\NetworkShares*.csv") -or (Get-ChildItem "$OUT_DIR\CSV\NetworkShares*.csv" -ErrorAction SilentlyContinue)))
{
$ScanChoice = "11,12"
}
}
$null {Return}
}
ParseMenuChoice $ScanChoice 15 | %{
if($_){
$Script:ScanChoiceArray.add($_)|Out-Null
}
}
}

Function DisplayAdvancedMenu
{
While($true)
{
Write-Host "
Which scan do you want to perform?

[1] File-Type Search
[2] Logged on users
[3] Ping Sweep
[4] Hot-Fix Enumeration
[5] NT/LM password hash dump (Win7+)
[6] File hasher (Win7+)
[7] Virus-Total hash analysis

Choice: " -NoNewLine
$AdvScanChoice = ReadYellow

switch ($AdvScanChoice)
{
1{if(-not (FileTypeSearch)){Return}}
2{if (-not (LoggedOnUsers)){Return}}
3{if (-not (PingSweep)){Return}}
4{
Write-Host
$Script:ScanChoiceArray.add("16")
Return
}
5{
Write-Host
$Script:ScanChoiceArray.add("110")
Return
}
6{
Write-Host
$Script:ScanChoiceArray.add("111")
Return
}
7{if (-not (VTHashAnalysis)){Return}}

"h"{Clear-Host; return $false}
"home"{Clear-Host; return $false}
"x"{ExitFunction}
"exit"{ExitFunction}
default{Write-Host -ForegroundColor Red "Invalid Choice: $ScanType"}
}
}
}

Function ParseMenuChoice
{
param($Choice, $TotalChoices)

#Create a temporary array to store the different comma separated scan choices
$TempChoiceArray = New-Object System.Collections.ArrayList
$Choice = $Choice.split(",") | %{$_.trim()}

#if the array only has 1 item do this
if(-not $Choice.count -or $Choice.count -eq 1)
{
$TempChoiceArray.Add($Choice)|out-null

#choice of 0 means perform all scans.
if($TempChoiceArray[0] -eq "0")
{
$TempChoiceArray.Clear()

#Fill array with values from 1 to total number of choices
for($i=1; $i -le $TotalChoices; $i++){$TempChoiceArray.Add($i)|out-null}
Return $TempChoiceArray
}
}

else
{
#add each comma separated item to the array
for($i=0; $i -lt $Choice.count; $i++)
{
$TempChoiceArray.Add($Choice[$i]) |out-null
}
}

#step through each choice in TempChoiceArray
for($i=0; $i -lt $TempChoiceArray.count; $i++)
{
#Test if choice contains a "-" representing a range of numbers (i.e. 4-8)
if ($TempChoiceArray[$i] | select-string "-")
{
#split the range and test that they are digits
$IntRange = ($TempChoiceArray[$i]).split("-")
for($j=0; $j -le 1; $j++)
{
if ( $IntRange[$j] | select-string "^\d$")
{
$IntRange[$j] = [convert]::ToInt32($IntRange[$j], 10)
}
else
{
$invalid = $true
break
}
}
if(-not $invalid)
{
#fill in the numeric values between the range
$IntRange=($IntRange[0] .. $IntRange[1])
for($j=0; $j -lt $IntRange.count; $j++)
{
#add each item in the integer range to the temp array
$TempChoiceArray.Add($IntRange[$j])|out-null
}
#remove the item that represents the range from the temp array
$TempChoiceArray.Remove($TempChoiceArray[$i])|out-null

#restart the loop until all choice ranges have been expanded
$i = -1
}
else
{
continue
}
}
}

for($i=0; $i -lt $TempChoiceArray.count; $i++)
{
if($TempChoiceArray[$i] -match "[0-9]" -and $TempChoiceArray[$i] -notmatch "[a-zA-Z]")
{
#convert to base 10 integer
$TempChoiceArray[$i] = [convert]::ToInt32($TempChoiceArray[$i], 10)
}
else
{
#value is not a number. remove it
Write-Host -ForegroundColor Red "Invalid Choice: $($TempChoiceArray[$i])"
$TempChoiceArray.Remove($TempChoiceArray[$i])
}
}

#return sorted array
$TempChoiceArray = $TempChoiceArray | sort
Return $TempChoiceArray
}

#Get location to save data
Function SetOutFile
{
param($CurrentChoice)
$input = ReadYellow
if(-not $input) #no user input. use current choice
{
#Current choice is users current directory
if($CurrentChoice -eq $(Get-Location).path)
{
$(Get-Location).path+"\Scans${today}"
$(Get-Location).path+"\Scans${today}_TEMP"
$script:OUT_DIR_root = $CurrentChoice
return
}

#User changed default choice. Make sure choice is full path
else
{
$input = (Get-Item "$CurrentChoice").FullName #full path needed for script to run properly
"${input}Scans${today}"
"${input}Scans${today}_TEMP"
$script:OUT_DIR_root = $CurrentChoice
return
}
}
else #choice changed from currently stored value
{
if(-not (Test-Path $input -PathType Container)) #path must be a directory
{
if(ReturnFunction $input) #User is trying to exit or return to prompt
{
Return $True
}
Else
{
Write-Host -ForegroundColor Red " $input does not exist or is not a directory."
return $false
}
}
else #path is a directory
{
$input = (Get-Item "$input").FullName #full path needed for script to run properly
"${input}Scans${today}"
"${input}Scans${today}_TEMP"
$script:OUT_DIR_root = $input
return
}
}
}

#Set location/create known good files for data parsing
Function SetKnownGood
{
#known good directory not found create and fill with files
if(-not (Test-Path "$PSScriptRoot\KnownGood" -PathType Container))
{
mkdir "$PSScriptRoot\KnownGood" |Out-Null
$null|Add-Content "$PSScriptRoot\KnownGood\UserExeSearch.txt"
$null|Add-Content "$PSScriptRoot\KnownGood\USBs.txt"
$null|Add-Content "$PSScriptRoot\KnownGood\StartUpPrograms.txt"
$null|Add-Content "$PSScriptRoot\KnownGood\ScheduledTasks.txt"
$null|Add-Content "$PSScriptRoot\KnownGood\RunningProcs.txt"
$null|Add-Content "$PSScriptRoot\KnownGood\Drivers.txt"
$null|Add-Content "$PSScriptRoot\KnownGood\Services.txt"
$null|Add-Content "$PSScriptRoot\KnownGood\InstalledSoftware.txt"
$null|Add-Content "$PSScriptRoot\KnownGood\RequiredHotFix.txt"
}

#Directory is present. Make sure each data parsing file exists
if (-not (Test-Path "$PSScriptRoot\KnownGood\UserExeSearch.txt")){
$null|Add-Content "$PSScriptRoot\KnownGood\UserExeSearch.txt"
}
if (-not (Test-Path "$PSScriptRoot\KnownGood\USBs.txt")){
$null|Add-Content "$PSScriptRoot\KnownGood\USBs.txt"
}
if (-not (Test-Path "$PSScriptRoot\KnownGood\StartUpPrograms.txt")){
$null|Add-Content "$PSScriptRoot\KnownGood\StartUpPrograms.txt"
}
if (-not (Test-Path "$PSScriptRoot\KnownGood\ScheduledTasks.txt")){
$null|Add-Content "$PSScriptRoot\KnownGood\ScheduledTasks.txt"
}
if (-not (Test-Path "$PSScriptRoot\KnownGood\RunningProcs.txt")){
$null|Add-Content "$PSScriptRoot\KnownGood\RunningProcs.txt"
}
if (-not (Test-Path "$PSScriptRoot\KnownGood\Drivers.txt")){
$null|Add-Content "$PSScriptRoot\KnownGood\Drivers.txt"
}
if (-not (Test-Path "$PSScriptRoot\KnownGood\Services.txt")){
$null|Add-Content "$PSScriptRoot\KnownGood\Services.txt"
}
if (-not (Test-Path "$PSScriptRoot\KnownGood\InstalledSoftware.txt")){
$null|Add-Content "$PSScriptRoot\KnownGood\InstalledSoftware.txt"
}
if (-not (Test-Path "$PSScriptRoot\KnownGood\RequiredHotFix.txt")){
$null|Add-Content "$PSScriptRoot\KnownGood\RequiredHotFix.txt"
}

#Fill known good hash table with paths to data files
$script:KnownGood = @{
UserExe = "$PSScriptRoot\KnownGood\UserExeSearch.txt"
USB = "$PSScriptRoot\KnownGood\USBs.txt"
StartUpProg = "$PSScriptRoot\KnownGood\StartUpPrograms.txt"
SchedTasks = "$PSScriptRoot\KnownGood\ScheduledTasks.txt"
RunningProcs = "$PSScriptRoot\KnownGood\RunningProcs.txt"
Drivers = "$PSScriptRoot\KnownGood\Drivers.txt"
Services = "$PSScriptRoot\KnownGood\Services.txt"
Software = "$PSScriptRoot\KnownGood\InstalledSoftware.txt"
HotFix = "$PSScriptRoot\KnownGood\RequiredHotFix.txt"}
}

Function help
{
Write-Host "
Available Options:
conf[c].......Set scan configuration variables
set...........View current configuration
scan[s].......Execute Scan
set-creds.....Input credentials to use for scan (default is current user)
get-hosts.....Generate list of active computers
home[h].......Return to prompt
exit[x].......Return to powershell
"

}

#set the hosts that should be scanned
Function ScanHostsFile
{
param($CurrentChoice)
$input = ReadYellow
if(-not $input){$input = $CurrentChoice} #keep current value

#generate list of all active hosts in domain
if($input -eq "ALL")
{
if($script:ScanDomain -eq $null)
{
Write-Warning "Host-File is required for deployable scans when domain is null"
Return $input
}
else
{
$script:FirstRunComps = $True
Return $input
}
}

#User input is not valid. Either does not exist or is not a file
elseif(-not (Test-Path $input -PathType Leaf))
{
if(ReturnFunction $input) #User is trying to exit or return to prompt
{
Return $True
}
Else
{
Write-Host -ForegroundColor Red " $input not found"
}
}

#User input is valid. Return user input
else
{
$script:FirstRunComps = $True
$script:HostFileModTime = (Get-ChildItem $input).LastWriteTime
Return $input
}
}

Function OutputFormat
{
param($CurrentChoice)
$input = ReadYellow
if(-not $input){$CurrentChoice; return}
switch($input)
{
"csv"{$input}
"xls"{$input}
"xlsx"{$input}
"xlsb"{$input}
default{
if(ReturnFunction $input) #User is trying to exit or return to prompt
{
Return $True
}
Else
{
Write-Host -ForegroundColor Red " Choices are: csv, xls, xlsx, xlsb"; return $false
}
}
}
}

Function ThreadCount
{
param($CurrentChoice)
$ProcNum = (gwmi win32_computersystem).NumberofLogicalProcessors #number of processor cores
$min=1 #minimum number of threads is 1
$max=$ProcNum*2
if($max -lt 8){$max = 8} #maximum number of threads is twice the number of processor cores or 8, whichever is more.
$input = ReadYellow
if(-not $input){[convert]::ToInt32($CurrentChoice); return}
try{
$input = [convert]::ToInt32($input)
if($input -ge $min -and $input -le $max){$input; return}
else {Write-Host -ForegroundColor Red " Choose a number from $min to $max"; return $false}
} catch {
if(ReturnFunction $input) #User is trying to exit or return to prompt
{
Return $True
}
Else
{
Write-Host -ForegroundColor Red " Choose a number from $min to $max"; return $false
}
}
}

Function SetScanDomain
{
param($CurrentChoice)
$input = ReadYellow
if(-not $input)
{
if(-not $CurrentChoice){
#Write-Host -ForegroundColor Red " Domain name cannot be null"
#Write-Warning "Hostname/IP list required for null domain"
Return
}
$script:DistinguishedName = "DC=$($CurrentChoice.Replace('.',',DC='))" #convert fqdn into distinguished name
Return $CurrentChoice
}

if ($input.split('.').count -eq 1) #input is not an fqdn
{
if(-not $CurrentChoice)
{
$fqdn = $input
}
else
{
for($i=1; $i -lt $CurrentChoice.split('.').count; $i++)
{
$root = $root+'.'+$CurrentChoice.split('.')[$i] #strip the first field off of the current domain
}
$fqdn = "$input$root" #prepend input to current domain
}
}
else
{
$fqdn = $input
}

$script:DistinguishedName = "DC=$($fqdn.Replace('.',',DC='))"

try {
if([adsi]::Exists("LDAP://$DistinguishedName")){Return $fqdn}
} catch {
if(ReturnFunction $input){Return $True}
else
{
Write-Host -ForegroundColor Red " Domain cannot be reached: $fqdn"
Return $False
}
}
}

Function Config #prompt user for required scan variables
{
Write-Host

#Set default values if variables are not already set
if(-not $ScanHostsFile){$ScanHostsFile="ALL"}
if(-not $OUT_DIR_root){$OUT_DIR_root=$(Get-Location).path}
if(-not $OutputFormat){$OutputFormat="xlsb"}
if(-not $ThreadCount){$ThreadCount = (gwmi win32_computersystem).NumberofLogicalProcessors}
if(-not $ScanDomain){
$ScanDomain = $(([ADSI]"").DistinguishedName)
if($ScanDomain){
$ScanDomain = $ScanDomain.Replace('DC=','').Replace(',','.')
}
}
if(-not $scan.creds)
{
if($env:USERDOMAIN -eq $env:COMPUTERNAME)
{
$UserDomain = '.'
}
else
{
$UserDomain = $env:USERDOMAIN
}

}

while($true) #loop until input is valid
{
Write-Host " Domain [$ScanDomain]: " -NoNewLine #set out file
$ScanDomain_temp = SetScanDomain $ScanDomain
if($ScanDomain_temp -eq $True){Write-Host; Return $False} #Boolen returned. Return to prompt
if($ScanDomain_temp)
{
$script:ScanDomain = $ScanDomain_temp
break
}
elseif($ScanDomain_temp -eq $null)
{
$script:ScanDomain = $null
break
}
}
while($true)
{
Write-Host " Data directory [$OUT_DIR_root]: " -NoNewLine #set out file
$OUT_DIR_temp,$TEMP_DIR_temp = SetOutFile $OUT_DIR_root
if($OUT_DIR_temp -eq $True){Write-Host; Return $False}
if($OUT_DIR_temp) #setOutFile was successful
{
$script:OUT_DIR, $script:TEMP_DIR = $OUT_DIR_temp, $TEMP_DIR_temp
$Script:scan.TEMP_DIR = $TEMP_DIR
$script:SCAN.OUT_DIR = $OUT_DIR
break
}
}
while($true)
{
Write-Host " Hosts to scan [$ScanHostsFile]: " -NoNewLine
$ScanHostsFile_temp = ScanHostsFile $ScanHostsFile
if($ScanHostsFile_temp -eq $True){Write-Host; Return $False}
if($ScanHostsFile_temp)
{
$script:ScanHostsFile = $ScanHostsFile_temp
break
}
}
while($true)
{
Write-Host " Output format [$OutputFormat]: " -NoNewLine
$OutputFormat_temp = OutputFormat $OutputFormat
if($OutputFormat_temp -eq $True){Write-Host; Return $False}
if($OutputFormat_temp)
{
$script:OutputFormat = $OutputFormat_temp
break
}
}
while($true)
{
Write-Host " Thread count [$ThreadCount]: " -NoNewLine
$ThreadCount_temp = ThreadCount $ThreadCount
if($ThreadCount_temp -eq $True){Write-Host; Return $False}
if($ThreadCount_temp)
{
$script:ThreadCount = $ThreadCount_temp
$Script:scan.Throttle = $script:ThreadCount
break
}
}
while($true)
{
Write-Host " Set Credentials [y/N]: " -NoNewLine
$credsChoice = ReadYellow
if(($credsChoice -eq 'Y') -or ($credsChoice -eq 'y'))
{
Set-Creds
}
elseif(ReturnFunction $credsChoice)
{
Write-Host; Return $False
}
else
{
$script:scan.creds = $null
}
break
}
Write-Host
$script:ConfigSuccess = $True
Return $True
}

Function Set-Creds #Get different credential than logged on user. This Functionality is currently not written into this script
{
try{
$script:scan.creds = Get-Credential $null -ErrorAction Stop
} catch {
$script:scan.creds = $null
Write-Host -ForegroundColor Red "Unable to set credentials"
}
}

Function CurrentConfig #display currently set scan variables
{
if(-not $scan.creds)
{
if($env:USERDOMAIN -eq $env:COMPUTERNAME)
{
$dname = '.'
}
else
{
$dname = $env:USERDOMAIN
}
$uname = $env:USERNAME
}
else
{
$dname = $scan.creds.GetNetworkCredential().domain
$uname = $scan.creds.GetNetworkCredential().username
}
if(-not $script:ScanDomain) {$script:ScanDomain=$env:USERDNSDOMAIN}
Write-Host
Write-Host " Domain: $ScanDomain"
Write-Host " Data directory: $OUT_DIR_root"
Write-Host " Hosts to scan: $ScanHostsFile"
Write-Host " Output format: $OutputFormat"
Write-Host " Thread count: $ThreadCount"
Write-Host " User Credentials: $dname\$uname
"
}

Function DarkObserver #darkobserver command prompt
{
[console]::ForegroundColor = "white"
Write-Host -ForegroundColor magenta "DarkObserver> " -NoNewLine
$Input = Read-Host
switch($input)
{
"set"{CurrentConfig}
"conf"{Config|out-null}
"c"{Config|out-null}
"scan"{Execute}
"s"{Execute}
"set-creds"{Set-Creds}
"get-hosts"{
if (-not $script:ConfigSuccess){$script:ConfigSuccess = config} #scan vars have not been configured enter configuration mode
if(-not $script:ConfigSuccess){Return}
CreateTempDir
$Script:ScanTime = $((get-date).tostring("HHmmss"))
Write-Host
$script:ActiveComputers = @(GetActiveComputers $TRUE)
}
"cls"{Clear-Host}
"exit"{Write-Host ""; ExitFunction}
"x"{Write-Host ""; ExitFunction}
default{Help}
}
}

Function ExitFunction
{
#Reset colors, clear screen and exit
[Console]::BackgroundColor = $BackgroundColor
[Console]::ForegroundColor = $ForegroundColor
Clear-Host
exit 0
}

Function ReturnFunction
{
param($UserInput)

switch($UserInput)
{
"x"{exitfunction}
"exit"{exitfunction}
"h"{Return $True}
"home"{Return $True}
}
}

############################################
# END Menu Functions
############################################

############################################
# START Scan Functions
############################################

#Set all variables to to used for each scan
Function SetScanTypeVars
{
param($Selection) #scan choice
(get-Date).ToString()
switch ($Selection)
{
1{
$Script:Deploy = $true #means this is will copy over a script to be executed with psexec
$Script:ScanType="user executable search" #used for printing scan status to screen
$Script:outfile="UserExeSearch$script:ScanTime.csv" #file where data will be parsed into
$Script:scan.RemoteDataFile = "UserExeSearch392125281" #file where data will output to on remote host
$Script:scan.TimeOut = 240 #number of seconds to wait for scan to complete during collection
$Script:scan.PS1Code = $UserExeSearchCode_PS1 #powershell code for windows version 6+
$Script:scan.BATCode = $UserExeSearchCode_BAT} #batch script for windows version < 6
2{
$Script:Deploy = $true
$Script:ScanType="USB enumeration"
$Script:outfile="USB_Enumeration$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "USB_Enumeration392125281"
$Script:scan.TimeOut = 240
$Script:scan.PS1Code = $USB_EnumerationCode_PS1
$Script:scan.BATCode = $USB_EnumerationCode_BAT}
3{
$Script:Deploy = $true
$Script:ScanType="auto-run disable query"
$Script:outfile="AutoRunDisable$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "AutoRunDisable392125281"
$Script:scan.TimeOut = 120
$Script:scan.PS1Code = $AutoRunDisableCode_PS1
$Script:scan.BATCode = $AutoRunDisableCode_BAT}
4{
$Script:Deploy = $true
$Script:ScanType="Start-up program query"
$Script:outfile="StartUpPrograms$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "StartUpPrograms392125281"
$Script:scan.TimeOut = 120
$Script:scan.PS1Code = $StartUpProgramsCode_PS1
$Script:scan.BATCode = $StartUpProgramsCode_BAT}
5{
$Script:Deploy = $true
$Script:ScanType="scheduled tasks query"
$Script:outfile="ScheduledTasks$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "ScheduledTasks392125281"
$Script:scan.TimeOut = 120
$Script:scan.PS1Code = $ScheduledTasksCode_PS1
$Script:scan.BATCode = $ScheduledTasksCode_BAT}
6{
$Script:Deploy = $true
$Script:ScanType="running processes query"
$Script:outfile="RunningProcs$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "RunningProcs392125281"
$Script:scan.TimeOut = 120
$Script:scan.PS1Code = $RunningProcsCode_PS1
$Script:scan.BATCode = $RunningProcsCode_BAT}
7{
$Script:Deploy = $true
$Script:ScanType="driver query"
$Script:outfile="Drivers$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "Drivers392125281"
$Script:scan.TimeOut = 120
$Script:scan.PS1Code = $QueryDriversCode_PS1
$Script:scan.BATCode = $QueryDriversCode_BAT}
8{
$Script:Deploy = $true
$Script:ScanType="service query"
$Script:outfile="Services$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "Services392125281"
$Script:scan.TimeOut = 120
$Script:scan.PS1Code = $QueryServicesCode_PS1
$Script:scan.BATCode = $QueryServicesCode_BAT}

9{
$Script:Deploy = $true
$Script:ScanType="network connections query"
$Script:outfile="NetStat$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "Netstat392125281"
$Script:scan.TimeOut = 600
$Script:scan.PS1Code = $NetstatCode_PS1
$Script:scan.BATCode = $NetstatCode_BAT}
10{
$Script:Deploy = $true
$Script:ScanType="installed software query"
$Script:outfile="Software$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "InstalledSoftware392125281"
$Script:scan.TimeOut = 240
$Script:scan.PS1Code = $InstalledSoftwareCode_PS1
$Script:scan.BATCode = $InstalledSoftwareCode_BAT}
11{
$Script:Deploy = $true
$Script:ScanType="network shares query"
$Script:outfile="NetworkShares$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "NetworkShares392125281"
$Script:scan.TimeOut = 120
$Script:scan.PS1Code = $SharesCode_PS1
$Script:scan.BATCode = $SharesCode_BAT}
12{
$Script:Deploy = $false
$Script:outfile="NetworkSharesPermissions$script:ScanTime.csv"
NetworkSharesPermissions}
13{
#!!!!!!!This check does not work on servers. Check servers manually!!!!!!
$Script:Deploy = $true
$Script:ScanType="antivirus status checks"
$Script:outfile="AntivirusStatus$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "AntivirusStatus392125281"
$Script:scan.TimeOut = 120
$Script:scan.PS1Code = $AntivirusStatusCode_PS1
$Script:scan.BATCode = $AntivirusStatusCode_BAT}
14{
$Script:Deploy = $true
$Script:ScanType="local account enumeration"
$Script:outfile="LocalAccounts$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "LocalAccounts392125281"
$Script:scan.TimeOut = 900
$Script:scan.PS1Code = $LocalAccountsCode_PS1
$Script:scan.BATCode = $LocalAccountsCode_BAT}
15{
$Script:Deploy = $false
$Script:ScanType="user account compliance query"
$Script:outfile="DomainAccounts$script:ScanTime.txt"
$scan.DomainName = $DistinguishedName
if($scan.DomainName)
{
Write-Host $(get-Date)
DomainAccounts
}
else
{
Write-Host -ForegroundColor Red "No domain available"
}}
16{
$Script:Deploy = $true
$Script:ScanType="hot-fix enumeration"
$Script:outfile="HotFixInfo$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "HotFixData392125281"
$Script:scan.TimeOut = 240
$Script:scan.PS1Code = $HotFixCode_PS1
$Script:scan.BATCode = $HotFixCode_BAT}

101{
$Script:Deploy = $true
$Script:ScanType="image file search"
$Script:outfile="ImageFileSearch$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "ImageFileSearch392125281"
$Script:scan.TimeOut = 1800
$Script:scan.PS1Code = $ImageSearchCode_PS1
$Script:scan.BATCode = $ImageSearchCode_BAT}
102{
$Script:Deploy = $true
$Script:ScanType="audio file search"
$Script:outfile="AudioFileSearch$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "AudioFileSearch392125281"
$Script:scan.TimeOut = 1800
$Script:scan.PS1Code = $AudioSearchCode_PS1
$Script:scan.BATCode = $AudioSearchCode_BAT}
103{
$Script:Deploy = $true
$Script:ScanType="video file search"
$Script:outfile="VideoFileSearch$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "VideoFileSearch392125281"
$Script:scan.TimeOut = 1800
$Script:scan.PS1Code = $VideoSearchCode_PS1
$Script:scan.BATCode = $VideoSearchCode_BAT}
104{
$Script:Deploy = $true
$Script:ScanType="script file search"
$Script:outfile="ScriptFileSearch$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "ScriptFileSearch392125281"
$Script:scan.TimeOut = 1800
$Script:scan.PS1Code = $ScriptSearchCode_PS1
$Script:scan.BATCode = $ScriptSearchCode_BAT}
105{
$Script:Deploy = $true
$Script:ScanType="executable file search"
$Script:outfile="ExecutableFileSearch$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "ExecutableFileSearch392125281"
$Script:scan.TimeOut = 1800
$Script:scan.PS1Code = $ExecutableSearchCode_PS1
$Script:scan.BATCode = $ExecutableSearchCode_BAT}
106{
$Script:Deploy = $true
$Script:ScanType="Outlook data file search"
$Script:outfile="DataFileSearch$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "DataFileSearch392125281"
$Script:scan.TimeOut = 1800
$Script:scan.PS1Code = $DataFileSearchCode_PS1
$Script:scan.BATCode = $DataFileSearchCode_BAT}
107{
$Script:Deploy = $true
$Script:ScanType="password file search"
$Script:outfile="PasswordFileSearch$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "PasswordFileSearch392125281"
$Script:scan.TimeOut = 1800
$Script:scan.PS1Code = $PasswordSearchCode_PS1
$Script:scan.BATCode = $PasswordSearchCode_BAT}
110{
$Script:Deploy = $true
$Script:ScanType="password hash dump"
$Script:outfile="HashDump$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "HashDump392125281"
$Script:scan.TimeOut = 180
$Script:scan.PS1Code = $PowerDump}
111{
$Script:Deploy = $true
$Script:ScanType="file hasher"
$Script:outfile="FileHashes$script:ScanTime.csv"
$Script:scan.RemoteDataFile = "hashes392125281"
$Script:scan.TimeOut = 2700
$Script:scan.PS1Code = $FileHasher}

"h"{return}
"home"{return}
"x"{ExitFunction}
"exit"{ExitFunction}

default{
Write-Host -ForegroundColor Red " Invalid Choice: $Selection
"
Return $false
}
}
Return $true
}

#Parse through AD search results and return the logon name
Function GetResults
{
param($results)

Foreach($result in $results)
{
if($result.properties.item("lastLogon") -ne 0)
{
$LastLogon = [datetime]::FromFileTime([int64]::Parse($result.properties.item("lastLogon")))
}
else
{
$LastLogon = $null
}
$Locked = $($result.properties.item("lockouttime"))
$UAC = $($result.properties.item("useraccountcontrol"))
$result.properties.item("memberof")| %{
if(-not $MemberOf)
{
$MemberOf = $_.Split(',')[0].Replace('CN=','')
}
else
{
$MemberOf = $MemberOf + "; " + $_.Split(',')[0].Replace('CN=','')
}
}
if($Locked){$status = 'Locked'}
elseif($UAC -band 0x0002){$status = 'Disabled'}
else{$status = 'Active'}
$Account = $($result.properties.item("SAMAccountName"))
"$Account,$status,$LastLogon,$MemberOf"
$MemberOf = $null
}
}

#Convert Date values into time ticks
Function ConvertDate
{
param($Day)

#Convert to datetime.
$Date = [DateTime]"$Day"

# Correct for daylight savings.
If ($Date.IsDaylightSavingTime)
{
$Date = $Date.AddHours(-1)
}

# Convert the datetime value, in UTC, into the number of ticks since
# 12:00 AM January 1, 1601.
$Value = ($Date.ToUniversalTime()).Ticks - ([DateTime]"January 1, 1601").Ticks
return $Value
}

#get stale and non-compliant accounts
Function DomainAccounts
{
Write-Host -ForegroundColor Yellow "Collecting active directory user account data."

#Variables to hold dates (30 & 45 days ago)
$30Days = (get-date).adddays(-30)
$45Days = (get-date).adddays(-45)

#Create a new object to search Active directory
#[ADSI]"" searches begining in the the root of your current domain
#you can change where your search starts by specifying the AD location
#example: [ADSI]"LDAP://OU=Users and Computers,DC=foo,DC=bar,DC=com"
$Search = New-Object DirectoryServices.DirectorySearcher([ADSI]"")
$Search.PageSize = 1000

#Accounts with no password expiration and no CLO enforced
$Search.filter = "(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=65536)(!(userAccountControl:1.2.840.113556.1.4.803:=262144)))"
"Account Name,Status,Last Logon,Group Membership"|Add-content "$TEMP_DIR\NoCLO.csv"
GetResults $Search.Findall() | sort | Add-content "$TEMP_DIR\NoCLO.csv"

#Active accounts that haven't been accessed in 30 days
$Value = ConvertDate($30Days)
$Search.filter = "(&(objectCategory=person)(objectClass=user)(lastLogon<=$Value)(!(lastLogon=0))(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(lockoutTime>=1)))"
"Account Name,Status,Last Logon,Group Membership"|Add-content "$TEMP_DIR\30DaysStale.csv"
GetResults $Search.Findall() | sort | Add-content "$TEMP_DIR\30DaysStale.csv"

#Accounts not accessed in 45 days
$Value = ConvertDate($45Days)

#UTC date for whencreated comparison
$Value2 = $45Days.ToString("yyhhmmss.0Z")

$Search.filter = "(|(&(objectCategory=person)(objectClass=user)(lastLogon<=$Value)(!(lastLogon=0)))(&(objectCategory=person)(objectClass=user)(whenCreated<=$Value2)(|(!(lastLogon=*))(lastLogon=0))))"
"Account Name,Status,Last Logon,Group Membership"|Add-content "$TEMP_DIR\45DaysStale.csv"
GetResults $Search.Findall() | sort | Add-content "$TEMP_DIR\45DaysStale.csv"

$Convert = "$TEMP_DIR\NoCLO.csv", "$TEMP_DIR\45DaysStale.csv", "$TEMP_DIR\30DaysStale.csv"
ConvertFileFormat $Convert
}

#Return a list of windows machines on the domain
Function GetComputers
{
#Create a new object to search Active directory
#[ADSI]“" searches beginning in the the root of your current domain
#you can change where your search starts by specifying the AD location
#example: [ADSI]“LDAP://OU=Users and Computers,DC=foo,DC=bar,DC=com”

param($HostFile)

if(-not ($HostFile -eq "ALL")) #host names to scan provided by user
{
$Hosts = Get-Content $HostFile -ReadCount 0
RunScriptBlock $GetComputersSB $Hosts $scan | sort -Unique
}
else #grab all computers
{
$Search = New-Object DirectoryServices.DirectorySearcher([ADSI]"LDAP://$DistinguishedName")
$Search.PageSize = 1000 #page size needed to return more than 1000 entries
$Search.filter = "(objectClass=computer)"
Foreach($result in $Search.Findall())
{
$result.GetDirectoryEntry()|%{
$name=$_.name
$os=$_.OperatingSystem
$ver=$_.OperatingSystemVersion
"$name,$os,$ver" | Select-String "Windows" | Select-String -NotMatch $env:COMPUTERNAME
}
}
}
}

Function GetActiveComputers
{
param($menuScan)

(get-Date).ToString() | Write-Host
Write-Host -ForegroundColor Yellow "Generating list of active computers"
$ScannedHosts = "Scanned_Hosts$script:ScanTime.csv"
$Threads = $scan.Throttle #store number of threads
$scan.Throttle = $scan.Throttle * 5 #lots of network delay for absent hosts so increase thread count for runspace
if($scan.Throttle -gt 50){$scan.Throttle = 50}
$scan.DomainName = $DistinguishedName
[string[]] $Computers = GetComputers $ScanHostsFile
"Time Stamp,Host Name, Error" | Add-Content "$TEMP_DIR\ErrorLog.csv"
[string[]] $ActiveComputers = RunScriptBlock $ActiveComputers_SB $Computers $scan
$scan.Throttle = $Threads #re-set throttle

$ActiveComputers = $ActiveComputers | Sort -Unique | Select-String -NotMatch $env:COMPUTERNAME #remove scanning machine and any duplicates
$numActOrig = $ActiveComputers.count #number of active computers returned

#Write list of computers to file starting with column names
"Host Name,IP Address,Operating System,Version"|Add-Content "$TEMP_DIR\$ScannedHosts"
$ActiveComputers |Add-Content "$TEMP_DIR\$ScannedHosts"
$ConvertFiles = "$TEMP_DIR\ErrorLog.csv", "$TEMP_DIR\$ScannedHosts"
$Script:outfile = $ScannedHosts
If($menuScan)
{
ConvertFileFormat $ConvertFiles
}
Else
{
ConvertFileFormat $ConvertFiles $true
}

#list of computers has been generated
$Script:FirstRunComps = $false
$numTot = $Computers.count
$numAct = $ActiveComputers.Count
if(-not ($numAct -ge 0)){$numAct = 0}
$numDif = $numActOrig - $numAct #in case there were duplicate hosts found
$numTot = $numTot - $numDif
Write-Host -ForegroundColor Yellow "$numAct/$numTot active computers found
"
#Store a timestamp for when list of computers was generated to update list after time
$script:CompsDate = Get-Date
return $ActiveComputers
}

Function VerifyIP
{
param($IP, $CIDR)

$Octets = $IP.split(".")
if($Octets.count -ne 4){Return $false}

if($CIDR)
{
$CIDR = [convert]::ToInt32($CIDR, 10)
if(-not (($CIDR -ge 1) -and ($CIDR -le 32)))
{
Return $false
}
}

for($i=0; $i -lt 4; $i++)
{
if($Octets[$i] -match "[0-9]" -and $Octets[$i] -notmatch "[a-zA-Z]")
{
$num = [convert]::ToInt32($Octets[$i], 10)
if(-not (($num -le 255) -and ($num -ge 0)))
{
Return $false
}
}
else
{
Return $false
}
}
Return $true
}

Function Get-IPSubnet
{

Param(
[Parameter(Mandatory = $true)]
[Array] $Subnets
)

foreach($subnet in $Subnets){

#Split IP and subnet
$IP = ($Subnet -split "\/")[0]
$CIDR = ($Subnet -split "\/")[1]

if(-not (VerifyIP $IP $CIDR))
{
Write-Host -ForegroundColor Red "Invalid subnet: $subnet"
Return $false
}
}

foreach($subnet in $Subnets)
{

#Split IP and subnet
$IP = ($Subnet -split "\/")[0]

$SubnetBits = ($Subnet -split "\/")[1]

#Convert IP into binary
#Split IP into different octects and for each one, figure out the binary with leading zeros and add to the total
$Octets = $IP -split "\."
$IPInBinary = @()
foreach($Octet in $Octets)
{
#convert to binary
$OctetInBinary = [convert]::ToString($Octet,2)

#get length of binary string add leading zeros to make octet
$OctetInBinary = ("0" * (8 - ($OctetInBinary).Length) + $OctetInBinary)

$IPInBinary = $IPInBinary + $OctetInBinary
}
$IPInBinary = $IPInBinary -join ""

#Get network ID by subtracting subnet mask
$HostBits = 32-$SubnetBits
$NetworkIDInBinary = $IPInBinary.Substring(0,$SubnetBits)

#Get host ID and get the first host ID by converting all 1s into 0s
$HostIDInBinary = $IPInBinary.Substring($SubnetBits,$HostBits)
$HostIDInBinary = $HostIDInBinary -replace "1","0"

#Work out all the host IDs in that subnet by cycling through $i from 1 up to max $HostIDInBinary (i.e. 1s stringed up to $HostBits)
#Work out max $HostIDInBinary
$imax = [convert]::ToInt32(("1" * $HostBits),2) -1

$IPs = @()

#Next ID is first network ID converted to decimal plus $i then converted to binary
For ($i = 1 ; $i -le $imax ; $i++)
{
#Convert to decimal and add $i
$NextHostIDInDecimal = ([convert]::ToInt32($HostIDInBinary,2) + $i)
#Convert back to binary
$NextHostIDInBinary = [convert]::ToString($NextHostIDInDecimal,2)
#Add leading zeros
#Number of zeros to add
$NoOfZerosToAdd = $HostIDInBinary.Length - $NextHostIDInBinary.Length
$NextHostIDInBinary = ("0" * $NoOfZerosToAdd) + $NextHostIDInBinary

#Work out next IP
#Add networkID to hostID
$NextIPInBinary = $NetworkIDInBinary + $NextHostIDInBinary
#Split into octets and separate by . then join
$IP = @()
For ($x = 1 ; $x -le 4 ; $x++)
{
#Work out start character position
$StartCharNumber = ($x-1)*8
#Get octet in binary
$IPOctetInBinary = $NextIPInBinary.Substring($StartCharNumber,8)
#Convert octet into decimal
$IPOctetInDecimal = [convert]::ToInt32($IPOctetInBinary,2)
#Add octet to IP
$IP += $IPOctetInDecimal
}

#Separate by .
$IP = $IP -join "."
$IPs += $IP
}
$IPs
}
}

Function Get-IPRange
{

Param(
[Parameter(Mandatory = $true)]
[Array] $Ranges
)

foreach($Range in $Ranges){

#Split IP and subnet
$StartIP = $Range.split("-")[0]
$EndIP = $Range.split("-")[1]

if(-not (VerifyIP $StartIP))
{
Write-Host -ForegroundColor Red "Invalid range: $Range"
Return $false
}
if(-not (VerifyIP $EndIP))
{
Write-Host -ForegroundColor Red "Invalid range: $Range"
Return $false
}
}

foreach($Range in $Ranges)
{
$TempIPArray = $Range.split("-")
$TempIPArray = [System.Version[]] ($TempIPArray) | Sort-Object
$StartIP = $TempIPArray[0].ToString()
$EndIP = $TempIPArray[1].ToString()

$StartOct1 = [convert]::ToInt32($StartIP.split(".")[0], 10)
$StartOct2 = [convert]::ToInt32($StartIP.split(".")[1], 10)
$StartOct3 = [convert]::ToInt32($StartIP.split(".")[2], 10)
$StartOct4 = [convert]::ToInt32($StartIP.split(".")[3], 10)

$EndOct1 = [convert]::ToInt32($EndIP.split(".")[0], 10)
$EndOct2 = [convert]::ToInt32($EndIP.split(".")[1], 10)
$EndOct3 = [convert]::ToInt32($EndIP.split(".")[2], 10)
$EndOct4 = [convert]::ToInt32($EndIP.split(".")[3], 10)

for($i=0; $i -lt 4; $i++)
{
$num = [convert]::ToInt32($StartIP.split(".")[$i], 10)
if(-not (($num -le 255) -and ($num -ge 0))){
Write-Host -ForegroundColor Red "Invalid IP range: $Range"
$invalid=$true
}
}
if($invalid){$invalid=$false; continue}

for($i=0; $i -lt 4; $i++)
{
$num = [convert]::ToInt32($EndIP.split(".")[$i], 10)
if(-not (($num -le 255) -and ($num -ge 0))){
Write-Host -ForegroundColor Red "Invalid IP range: $Range"
$invalid=$true
}
}
if($invalid){$invalid=$false; continue}

for($StartOct1; $StartOct1 -le $EndOct1; $StartOct1++){
if(-not ($StartOct1 -eq $EndOct1)){
$TempEnd2 = 255
}
Else {$TempEnd2 = $EndOct2}

for($StartOct2; $StartOct2 -le $TempEnd2; $StartOct2++){
if(-not (($StartOct2 -eq $EndOct2) -and ($StartOct1 -eq $EndOct1))){
$TempEnd3 = 255
}
Else {$TempEnd3 = $EndOct3}

for($StartOct3; $StartOct3 -le $TempEnd3; $StartOct3++){
if(-not (($StartOct3 -eq $EndOct3) -and ($StartOct2 -eq $EndOct2) -and ($StartOct1 -eq $EndOct1))){
$TempEnd4 = 255
}
Else {$TempEnd4 = $EndOct4}
for($StartOct4; $StartOct4 -le $TempEnd4; $StartOct4++){
"$StartOct1.$StartOct2.$StartOct3.$StartOct4"
}
$StartOct4=0
}
$StartOct3=0
}
$StartOct2=0
}
$IPs
}
}

Function Get-IPFile
{

Param(
[Parameter(Mandatory = $true)]
[string] $File
)

[Array]$IParray = $null
$content = Get-Content $File -ReadCount 0

foreach($IP in $content)
{
if($IP|Select-String "-")
{
$tempIP = Get-IPRange -Range $IP
if($tempIP){$IParray = $IParray + $tempIP}
}
elseif($IP|Select-String "/")
{
$tempIP = Get-IPSubnet -Subnets "$IP"
if($tempIP){$IParray = $IParray + $tempIP}
}
else
{
if(VerifyIP $IP)
{
$IParray = $IParray + $IP
}
}
}
$ipsort = [System.Version[]]($IParray) | Sort-Object
Return $ipsort
}

Function PingSweep
{
Write-Host -ForegroundColor Green "
Ping Sweep
-----------"
while($true)
{
Write-Host "Input IPs as Subnets[1], Range[2], or file[3]: " -NoNewLine
$Choice = ReadYellow
switch($Choice)
{
1{
Write-Host "Enter comma separated subnets: " -NoNewLine
$Input= ReadYellow
[Array]$IPArray = $Input.split(",")
$IPList = Get-IPSubnet -Subnets $IPArray
if($IPList){ExecutePingSweep $IPList}
Return}
2{
Write-Host "Enter IP range: " -NoNewLine
$Input = ReadYellow
[Array]$IPArray = $Input.split(",")
$IPList = Get-IPRange -Range $IPArray
if($IPList){ExecutePingSweep $IPList}
Return}
3{
Write-Host "Enter IP file: " -NoNewLine
$Input= ReadYellow
if(-not (Test-Path $Input))
{
Write-Host -ForegroundColor Red "File not found: $Input"
Return
}
$IPList = Get-IPFile -File $Input
if($IPList){ExecutePingSweep $IPList}
Return}
"h"{Return $false}
"home"{Return $false}
"x"{ExitFunction}
"exit"{ExitFunction}
default{Write-Host -ForegroundColor Red "Invalid input"}
}
}
}

Function ExecutePingSweep
{
param($IPList)

Write-Host

$Script:Deploy = $false
$Script:outfile="PingSweep$script:ScanTime.csv"

Write-Host $(get-Date)
Write-Host -ForegroundColor Yellow "Executing ping sweep"
CreateTempDir
$TempThrottle = $scan.Throttle
$scan.Throttle = $scan.Throttle * 5
RunScriptBlock $PingSweepSB $IPList $scan
$scan.Throttle = $TempThrottle
ParseData 109
}

Function ChooseFileTypes
{
Write-Host "
File-types to search.

[0] ALL
[1] Image Files (*.jpg, *.jpeg, *.tif, *.gif, *.bmp)
[2] Audio Files (*.m4a, *.m4p, *.mp3, *.wma)
[3] Video Files (*.asf, *.avi, *.m4v, *.mov, *.mp4, *.mpeg, *.mpg, *.wmv)
[4] Windows Script Files (*.ps1, *.psm1, *.vb, *.vbs, *.bat, *.cmd)
[5] Executable Files (*.exe, *.dll, *.sys)
[6] Outlook data files (*.pst)
[7] Password files (*passw*, *pwd*)

Choice: " -NoNewLine
$ScanChoice = ReadYellow
Write-Host
Return ParseMenuChoice $ScanChoice 7
}

Function FileTypeSearch
{
Write-Host -ForegroundColor Green "
File Search
-----------"
while($true)
{
Write-Host "Search local path[1] or network share[2]: " -NoNewLine
$SearchScope = ReadYellow
switch($SearchScope)
{
1{DeployFileSearch; return}
2{NetShareFileSearch; return}
"h"{Return $false}
"home"{Return $false}
"x"{ExitFunction}
"exit"{ExitFunction}
default{Write-Host -ForegroundColor Red "Invalid input"}
}
}
}

#deploy file search searches a file path on each local host using psexec
Function DeployFileSearch
{
$Script:ScanChoiceArray.clear()

#Array to hold the choices of file-types to search for
$FileTypesArray = New-Object System.Collections.ArrayList
Write-Host "
Enter local path to begin search.
Default is C:\: " -NoNewLine
$Script:PathToSearch = ReadYellow
if (-not $Script:PathToSearch){$Script:PathToSearch="C:\"} #default path is C:\
$FileTypesArray.add($(ChooseFileTypes))|Out-Null

for($i=0; $i -lt $FileTypesArray.count; $i++)
{
#set script variables based on file types
switch($FileTypesArray[$i])
{
1{
$Script:ScanChoiceArray.add(101)|out-null
$Script:ImageSearchCode_BAT = '
@echo off
IF EXIST "C:\ImageFileSearch392125281" DEL "C:\ImageFileSearch392125281"
for /R "'+$PathToSearch+'" %%f in (*.jpg *.jpeg *.tif *.gif *.bmp) do (
echo %COMPUTERNAME%,%%~nxf,%%~dpf
) >> "C:\ImageFileSearch392125281"
(goto) 2>nul & del "%~f0"'

$Script:ImageSearchCode_PS1 = '
if (Test-Path "C:\ImageFileSearch392125281"){Remove-Item -Force "C:\ImageFileSearch392125281"}
$include = "*.jpg", "*.jpeg", "*.tif", "*.gif", "*.bmp"
try{
Get-ChildItem -path "'+$PathToSearch+'*" -Include $include -Recurse -Force -ErrorAction silentlycontinue |
?{$_.FullName -NotMatch "Application Data"}|
foreach {${env:COMPUTERNAME}+","+$_.Name+","+$_.Directoryname}|
Out-file "C:\ImageFileSearch392125281"
} catch {continue}
Remove-Item -Force "C:\PSExecShellCode.ps1"'
}
2{
$Script:ScanChoiceArray.add(102)|out-null
$Script:AudioSearchCode_BAT = '
@echo off
IF EXIST "C:\AudioFileSearch392125281" DEL "C:\AudioFileSearch392125281"
for /R "'+$PathToSearch+'" %%f in (*.m4a *.m4p *.mp3 *.wma) do (
echo %COMPUTERNAME%,%%~nxf,%%~dpf
) >> "C:\AudioFileSearch392125281"
(goto) 2>nul & del "%~f0"'

$Script:AudioSearchCode_PS1 = '
if (Test-Path "C:\AudioFileSearch392125281"){Remove-Item -Force "C:\AudioFileSearch392125281"}
$include = "*.m4a", "*.m4p", "*.mp3", "*.wma"
try{
Get-ChildItem -path "'+$PathToSearch+'*" -Include $include -Recurse -Force -ErrorAction silentlycontinue |
?{$_.FullName -NotMatch "Application Data"}|
foreach {${env:COMPUTERNAME}+","+$_.Name+","+$_.Directoryname}|
Out-file "C:\AudioFileSearch392125281"
} catch {continue}
Remove-Item -Force "C:\PSExecShellCode.ps1"'
}
3{
$Script:ScanChoiceArray.add(103)|out-null
$Script:VideoSearchCode_BAT = '
@echo off
IF EXIST "C:\VideoFileSearch392125281" DEL "C:\VideoFileSearch392125281"
for /R "'+$PathToSearch+'" %%f in (*.asf *.avi *.m4v *.mov *.mp4 *.mpeg *.mpg *.wmv) do (
echo %COMPUTERNAME%,%%~nxf,%%~dpf
) >> "C:\VideoFileSearch392125281"
(goto) 2>nul & del "%~f0"'

$Script:VideoSearchCode_PS1 = '
if (Test-Path "C:\VideoFileSearch392125281"){Remove-Item -Force "C:\VideoFileSearch392125281"}
$include = "*.asf", "*.avi", "*.m4v", "*.mov", "*.mp4", "*.mpeg", "*.mpg", "*.wmv"
try{
Get-ChildItem -path "'+$PathToSearch+'*" -Include $include -Recurse -Force -ErrorAction silentlycontinue |
?{$_.FullName -NotMatch "Application Data"}|
foreach {${env:COMPUTERNAME}+","+$_.Name+","+$_.Directoryname}|
Out-file "C:\VideoFileSearch392125281"
} catch {continue}
Remove-Item -Force "C:\PSExecShellCode.ps1"'
}
4{
$Script:ScanChoiceArray.add(104)|out-null
$Script:ScriptSearchCode_BAT = '
@echo off
IF EXIST "C:\ScriptFileSearch392125281" DEL "C:\ScriptFileSearch392125281"
for /R "'+$PathToSearch+'" %%f in (*.ps1 *.psm1 *.vb *.vbs *.bat *.cmd) do (
echo %COMPUTERNAME%,%%~nxf,%%~dpf
) >> "C:\ScriptFileSearch392125281"
(goto) 2>nul & del "%~f0"'

$Script:ScriptSearchCode_PS1 = '
if (Test-Path "C:\ScriptFileSearch392125281"){Remove-Item -Force "C:\ScriptFileSearch392125281"}
$include = "*.ps1", "*.psm1", "*.vb", "*.vbs", "*.bat", "*.cmd"
try{
Get-ChildItem -path "'+$PathToSearch+'*" -Include $include -Recurse -Force -ErrorAction silentlycontinue |
?{$_.FullName -NotMatch "Application Data"}|
foreach {${env:COMPUTERNAME}+","+$_.Name+","+$_.Directoryname}|
Out-file "C:\ScriptFileSearch392125281"
} catch {continue}
Remove-Item -Force "C:\PSExecShellCode.ps1"'
}
5{
$Script:ScanChoiceArray.add(105)|out-null
$Script:ExecutableSearchCode_BAT = '
@echo off
IF EXIST "C:\ExecutableFileSearch392125281" DEL "C:\ExecutableFileSearch392125281"
for /R "'+$PathToSearch+'" %%f in (*.exe *.dll *.sys) do (
echo %COMPUTERNAME%,%%~nxf,%%~dpf
) >> "C:\ExecutableFileSearch392125281"
(goto) 2>nul & del "%~f0"'

$Script:ExecutableSearchCode_PS1 = '
if (Test-Path "C:\ExecutableFileSearch392125281"){Remove-Item -Force "C:\ExecutableFileSearch392125281"}
$include = "*.exe", "*.dll", "*.sys"
try{
Get-ChildItem -path "'+$PathToSearch+'*" -Include $include -Recurse -Force -ErrorAction silentlycontinue |
?{$_.FullName -NotMatch "Application Data"}|
foreach {${env:COMPUTERNAME}+","+$_.Name+","+$_.Directoryname}|
Out-file "C:\ExecutableFileSearch392125281"
} catch {continue}
Remove-Item -Force "C:\PSExecShellCode.ps1"'
}
6{
$Script:ScanChoiceArray.add(106)|out-null
$Script:DataFileSearchCode_BAT = '
@echo off
IF EXIST "C:\DataFileSearch392125281" DEL "C:\DataFileSearch392125281"
for /R "'+$PathToSearch+'" %%f in (*.pst) do (
echo %COMPUTERNAME%,%%~nxf,%%~dpf
) >> "C:\DataFileSearch392125281"
(goto) 2>nul & del "%~f0"'

$Script:DataFileSearchCode_PS1 = '
if (Test-Path "C:\DataFileSearch392125281"){Remove-Item -Force "C:\DataFileSearch392125281"}
$include = "*.pst"
try{
Get-ChildItem -path "'+$PathToSearch+'*" -Include $include -Recurse -Force -ErrorAction silentlycontinue |
?{$_.FullName -NotMatch "Application Data"}|
foreach {${env:COMPUTERNAME}+","+$_.Name+","+$_.Directoryname}|
Out-file "C:\DataFileSearch392125281"
} catch {continue}
Remove-Item -Force "C:\PSExecShellCode.ps1"'
}
7{
$Script:ScanChoiceArray.add(107)|out-null
$Script:PasswordSearchCode_BAT = '
@echo off
IF EXIST "C:\PasswordFileSearch392125281" DEL "C:\PasswordFileSearch392125281"
for /R "'+$PathToSearch+'" %%f in (*passw* *pwd*) do (
echo %COMPUTERNAME%,%%~nxf,%%~dpf
) >> "C:\PasswordFileSearch392125281"
(goto) 2>nul & del "%~f0"'

$Script:PasswordSearchCode_PS1 = '
if (Test-Path "C:\PasswordFileSearch392125281"){Remove-Item -Force "C:\PasswordFileSearch392125281"}
$include = "*passw*", "*pwd*"
try{
Get-ChildItem -path "'+$PathToSearch+'*" -Include $include -Recurse -Force -ErrorAction silentlycontinue |
?{$_.FullName -NotMatch "Application Data"}|
foreach {${env:COMPUTERNAME}+","+$_.Name+","+$_.Directoryname}|
Out-file "C:\PasswordFileSearch392125281"
} catch {continue}
Remove-Item -Force "C:\PSExecShellCode.ps1"'
}
"h"{return $false}
"home"{return $false}
"x"{ExitFunction}
"exit"{ExitFunction}
}
}
}

#Execute net share file search with progress meter.
Function NetShareFileSearch_Run
{
param($path, $include, $ScanType)

#hash table to store variables for progress meter
$progParam=@{
Activity = "$ScanType"
CurrentOperation = $path
Status="Querying top level folders"
PercentComplete=0
}

Write-Progress @progParam

#Get all subdirectories in path to search
$top = Get-ChildItem -Path $path |Where{$_.PSIsContainer}
#initialize a counter
$i=0
foreach ($folder in $top) {
$folder=$folder.FullName
#calculate percentage based on number of folders in path to search
$i++

#set variables for progress meter
[int]$pct = ($i/$top.count)*100
$progParam.CurrentOperation ="Searching: $folder"
$progParam.Status="Progress"
$progParam.PercentComplete = $pct

#Write the progress
Write-Progress @progParam

#Perform the file search in the subdirectory of the path
Get-ChildItem -path "$folder\*" -Include $include -Recurse -Force -ErrorAction silentlycontinue |
foreach {$_.Name+","+$_.Directoryname}
}
}

Function NetShareFileSearch
{
$FileTypesArray = New-Object System.Collections.ArrayList
While ($true) #Loop until input is valid
{
Write-Host "Enter full path to network share: " -NoNewLine
$SearchNetworkShare = ReadYellow

#Make sure that input is valid.
if ($SearchNetworkShare -and (Test-Path $SearchNetworkShare -ErrorAction SilentlyContinue)) {break}
else
{
Write-Host -ForegroundColor Red "Invalid Path
Use format: \\servername\sharename"
}
}

$FileTypesArray.add($(ChooseFileTypes)) #fill array with file types to search
$Script:Deploy = $false #Search is not executed using psexec

#iterate through file choices and find files
for($i=0; $i -lt $FileTypesArray.count; $i++)
{
CreateTempDir
switch ($FileTypesArray[$i])
{
1{ #image files
$script:outfile = "ImageFiles_Share$script:ScanTime.csv"
Write-Host -ForegroundColor Yellow "Searching for image files."
"File,Directory" | Add-Content "$TEMP_DIR\$outfile"
$include = "*.jpg", "*.jpeg", "*.tif", "*.gif", "*.bmp"
NetShareFileSearch_Run $SearchNetworkShare $include "Image Search:" |Add-Content "$TEMP_DIR\$outfile"
ConvertFileFormat "$TEMP_DIR\$outfile"
}
2{ #Audio Files
$script:outfile = "AudioFiles_Share$script:ScanTime.csv"
Write-Host -ForegroundColor Yellow "Searching for audio files."
"File,Directory" | Add-Content "$TEMP_DIR\$outfile"
$include = "*.m4a", "*.m4p", "*.mp3", "*.wma"
NetShareFileSearch_Run $SearchNetworkShare $include "Audio Search:" |Add-Content "$TEMP_DIR\$outfile"
ConvertFileFormat "$TEMP_DIR\$outfile"
}
3{ #Video Files
$script:outfile = "VideoFiles_Share$script:ScanTime.csv"
Write-Host -ForegroundColor Yellow "Searching for video files."
"File,Directory" | Add-Content "$TEMP_DIR\$outfile"
$include = "*.asf", "*.avi", "*.m4v", "*.mov", "*.mp4", "*.mpeg", "*.mpg", "*.wmv"
NetShareFileSearch_Run $SearchNetworkShare $include "Video Search:" |Add-Content "$TEMP_DIR\$outfile"
ConvertFileFormat "$TEMP_DIR\$outfile"
}
4{ #Script Files
$script:outfile = "ScriptFiles_Share$script:ScanTime.csv"
Write-Host -ForegroundColor Yellow "Searching for windows script files."
"File,Directory" | Add-Content "$TEMP_DIR\$outfile"
$include = "*.ps1", "*.psm1", "*.vb", "*.vbs", "*.bat", "*.cmd"
NetShareFileSearch_Run $SearchNetworkShare $include "Script Search:" |Add-Content "$TEMP_DIR\$outfile"
ConvertFileFormat "$TEMP_DIR\$outfile"
}
5{ #Executable Files
$script:outfile = "ExecutableFiles_Share$script:ScanTime.csv"
Write-Host -ForegroundColor Yellow "Searching for executable files."
"File,Directory" | Add-Content "$TEMP_DIR\$outfile"
$include = "*.exe", "*.dll", "*.sys"
NetShareFileSearch_Run $SearchNetworkShare $include "Executable Search:" |Add-Content "$TEMP_DIR\$outfile"
ConvertFileFormat "$TEMP_DIR\$outfile"
}
6{ #Outlook data files
$script:outfile = "OutlookDataFiles_Share$script:ScanTime.csv"
Write-Host -ForegroundColor Yellow "Searching for Outlook data files."
"File,Directory" | Add-Content "$TEMP_DIR\$outfile"
$include = "*.pst"
NetShareFileSearch_Run $SearchNetworkShare $include "Outlook Data-file Search:" |Add-Content "$TEMP_DIR\$outfile"
ConvertFileFormat "$TEMP_DIR\$outfile"
}
7{ #password files
$script:outfile = "PasswordFiles_Share$script:ScanTime.csv"
Write-Host -ForegroundColor Yellow "Searching for password files."
"File,Directory" | Add-Content "$TEMP_DIR\$outfile"
$include = "*passw*", "*pwd*"
NetShareFileSearch_Run $SearchNetworkShare $include "Password Search:" |Add-Content "$TEMP_DIR\$outfile"
ConvertFileFormat "$TEMP_DIR\$outfile"
}
}
}
}

Function LoggedOnUsers
{
Write-Host
if($script:FirstRunComps) #Test to see if list of active computers exists or not
{
$script:ActiveComputers = GetActiveComputers
}

$Script:Deploy = $false

Show more