Created
December 16, 2016 17:21
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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