Skip to content

Instantly share code, notes, and snippets.

@automationhaus
Created December 16, 2016 17:21
Show Gist options
  • Save automationhaus/f29d75bc2f7bbf72eec3e5199d2672a1 to your computer and use it in GitHub Desktop.
Save automationhaus/f29d75bc2f7bbf72eec3e5199d2672a1 to your computer and use it in GitHub Desktop.
Remotely collect a CSV and log of all accounts associated with scheduled tasks and services on servers. Useful for when you plan to make changes to old admin passowrds.
function Get-ServiceAccounts
{
<#
.SYNOPSIS
Collect logins for services and scheduled tasks that are likely to be service accounts
.DESCRIPTION
Remotely collect a CSV and log of all accounts associated with scheduled tasks and services on servers. Useful for when you plan to make changes to old admin passowrds.
.PARAMETER ComputerName
String array of computer names to check for service accounts
.PARAMETER CSV
Switch to enable the creation of a CSV containing the data collected from all computers
.NOTES
Britt Thompson
[email protected]
.LINK
https://gist.github.com/automationhaus/f29d75bc2f7bbf72eec3e5199d2672a1
#>
[CmdletBinding()]
param
(
[Parameter(ValueFromPipelineByPropertyName=$true,Position=0)]
[Alias("CN","Computers","Servers")]
[string[]]$ComputerName = $env:COMPUTERNAME,
[switch]$CSV
)
Begin
{
#region FUNCTIONS
function Write-Tee
{
<#
.SYNOPSIS
Write output to the screen and to file simultaneously
.DESCRIPTION
Simply write your screen output to a file with automatic coloring based with special sytax between square brackets. Enable debugging and produce debugging only ouptut.
.EXAMPLE
Write-Tee "[=] This is the first task in my loop"
.EXAMPLE
Write-Tee @"
Write a long message without a prefix and overwrite your log file
"@ -NoPrefix -Overwrite
.EXAMPLE
Write-Tee "[?] Collect info without a line break" -NoNewLine; Read-Host
#>
[cmdletbinding()]
param
(
[Parameter(Position=0,ValueFromPipeline=$true)]
[string]$msg,
[string]$ForegroundColor = "White",
[string]$OutFile=$LogFile,
[switch]$Overwrite,
[switch]$NoNewLine,
[string]$Prefix=" - ",
[switch]$NoPrefix
)
$Info = "i"; $Task = "="; $Errors = "!"; $Inquiry = "?"; $Debugging = "d"; $Response = "r"
$DBG = $False
switch -regex ($msg)
{
"\[$Info\]" { $ForegroundColor = "Yellow" }
"\[$Task\]" { $ForegroundColor = "Cyan"; $Prefix = " " }
"\[$Errors\]" { $ForegroundColor = "Red" }
"\[\$Inquiry\]" { $ForegroundColor = "Magenta" }
"\[$Debugging\]" { $ForegroundColor = "Magenta"; $DBG = $True }
"\[$Response\]" { if($ForegroundColor -eq "White"){ $ForegroundColor = "Green" } }
}
if(($DBG -eq $False) -or ($DBG -and $Debug)){ $Write = $True }
if(!$NoPrefix)
{
if($Write){ Write-Host $Prefix -NoNewline }
}
if($NoNewLine)
{
if($Write){ Write-Host -ForegroundColor $ForegroundColor $msg -NoNewline }
}
else
{
if($Write){ Write-Host -ForegroundColor $ForegroundColor $msg }
}
if(!$NoPrefix -and $msg -ne ""){ $msg = $Prefix + $msg }
if($OutFile -ne "")
{
if(!$Overwrite)
{
if($NoNewLine)
{
if($Write){ [System.IO.File]::AppendAllText($OutFile, $msg, [System.Text.Encoding]::Unicode) }
}
else
{
if($Write){ $msg | Out-File $OutFile -Append }
}
}
else
{
if($Write){ $msg | Out-File $OutFile -Force }
}
}
}
function Get-Catch { Write-Tee "[!] $($_.Exception.Message)" }
#endregion
#region VARS
# Establish script path for log output
$OSVersion = [decimal]([environment]::OSVersion.Version.Major,[environment]::OSVersion.Version.Minor -join ".")
# Define the script path based on the PowerShell version
if($PSVersionTable.PSVersion.Major -lt 3)
{
$ScriptPath = Split-Path $Script:MyInvocation.MyCommand.Path -Parent
} else { $ScriptPath = $PSScriptRoot }
[string]$DateFormat = Get-Date -Format yyyy-MM-dd
$LogPath = "$ScriptPath\Logs"
$LogFile = "$LogPath\ServiceAccounts_$DateFormat.txt"
$CSVFile = "$LogPath\ServiceAccounts_$DateFormat.csv"
$ExcludeTasks = @("Adobe Acrobat Update Task","G2MUpdateTask","G2MUploadTask","Optimize Start Menu Cache","User_Feed_Synchronization","GoogleUpdate","TaskName")
$Results = @()
#endregion
}
Process
{
# Create the logs directory if it doesn't exist
if(-not (Test-Path "$ScriptPath\Logs"))
{
$LogsDir = New-Item -Path "$ScriptPath\Logs" -ItemType Directory
}
# Loop through all computers
foreach($C in $ComputerName)
{
Write-Tee "[=] Server: $C"
# Test the availability of the server to be checked
$Avail = Test-Connection -ComputerName $C -Count 1 -ErrorAction 0
if($Avail)
{
$Lang = "service accounts"
Write-Tee "[i] Checking for $Lang"
# Check for services using WMI
try
{
$Services = Get-WmiObject Win32_Service -ComputerName $C |
?{ $_.StartName -ne "LocalSystem" -and $_.StartName -notlike "NT *" -and $_.StartName.Length -gt 1 } |
Select Name, StartName, StartMode, State,
@{Name="TaskPath"; Expression = {"N\A"}},
@{Name="Type"; Expression = {"Service"}}
} catch { Get-Catch }
# If WMI found nothing and this machine is at least 2012 try using CIM
if(!$Services -and $OSVersion -ge 6.2)
{
try
{
$Services = Get-CIMInstance Win32_Service -ComputerName $C |
?{ $_.StartName -ne "LocalSystem" -and $_.StartName -notlike "NT *" -and $_.StartName.Length -gt 1 } |
Select Name, StartName, StartMode, State,
@{Name="TaskPath"; Expression = {"N\A"}},
@{Name="Type"; Expression = {"Service"}}
} catch { Get-Catch }
}
# If services are collected output to screen, log and results for CSV output
if(!$Services)
{
Write-Tee "[i] No $Lang found for $C"
}
else
{
Write-Tee "[r] $($Services.Count) $Lang found for $C"
$Services | %{
Write-Tee "[+] [ " -NoNewLine
Write-Tee "$($_.StartName)" -NoPrefix -NoNewLine -ForegroundColor Magenta
Write-Tee " ] $($_.Name)" -NoPrefix
}
$Results += $Services
}
$Lang = "scheduled tasks"
Write-Tee "[i] Checking for $Lang"
# If this OS is at least 2012 and the remote machine has PowerShell 3+ use Get-ScheduledTask and CIM
if($OSVersion -ge 6.2)
{
try
{
$W = Test-WSMan $C -ErrorAction SilentlyContinue
if($W.ProductVersion -match "3.0")
{
$Cim = New-CimSession $C
$Tasks = Get-ScheduledTask -CimSession $Cim -ErrorAction Stop |
?{
$_.TaskPath -notmatch "Microsoft" -and
$_.Principal.UserId -ne "SYSTEM" -and
$_.Principal.UserId -ne "NETWORK SERVICE" -and
$_.Principal.UserId.Length -gt 1
} | Select @{Name="Name"; Expression = {$_.TaskName}},
@{Name="StartName"; Expression = {$_.Principal.UserId}},
@{Name="StartMode"; Expression = {$_.Principal.RunLevel}},
State, TaskPath, @{Name="Type"; Expression = {"Task"}}
if($Tasks)
{
foreach($E in $ExcludeTasks)
{
$Tasks = $Tasks | ?{ $_.Name -notmatch $E }
}
}
}
} catch { Get-Catch }
}
# If no tasks are collected above use the old schtasks method
if(!$Tasks)
{
try
{
$Tasks = schtasks /query /s $C /V /FO CSV | ConvertFrom-Csv |
?{
$_.TaskName -notmatch "\\Microsoft\\" -and
$_."Run As User" -ne "SYSTEM" -and
$_."Run As User" -ne "NETWORK SERVICE" -and
($_."Run As User").Length -gt 1
} | Select @{Name="Name"; Expression = {Split-Path $_.TaskName -Leaf}},
@{Name="StartName"; Expression = {$_."Run As User"}},
@{Name="StartMode"; Expression = {$_."Scheduled Task State"}},
@{Name="State"; Expression = {$_.Status}},
@{Name="TaskPath"; Expression = {$_.TaskName}},
@{Name="Type"; Expression = {"Task"}}
if($Tasks)
{
foreach($E in $ExcludeTasks)
{
$Tasks = $Tasks | ?{ $_.Name -notmatch $E }
}
}
} catch { Get-Catch }
}
# If tasks are collected output to screen, log and results for CSV output
if(!$Tasks)
{
Write-Tee "[i] No $Lang found for $C"
}
else
{
Write-Tee "[r] $($Tasks.Count) $Lang found for $C"
$Tasks | %{
Write-Tee "[+] [ " -NoNewLine
Write-Tee "$($_.StartName)" -NoPrefix -NoNewLine -ForegroundColor Magenta
Write-Tee " ] $($_.Name)" -NoPrefix
}
$Results += $Tasks
}
} else { Write-Tee "[!] Unable to connect to $C" }
} #foreach($C in $ComputerName)
# Export to CSV if enabled and ?{$_} to support older versions of PowerShell
if($CSV -and $Results){ $Results | ?{$_} | Export-Csv -Path $CSVFile -NoTypeInformation }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment