Skip to content

Instantly share code, notes, and snippets.

@ion-storm
Forked from automationhaus/Get-ServiceAccounts.ps1
Created January 21, 2017 02:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ion-storm/1f0b348cab881e789e89a8d9c203cbc7 to your computer and use it in GitHub Desktop.
Save ion-storm/1f0b348cab881e789e89a8d9c203cbc7 to your computer and use it in GitHub Desktop.
Checks each server in the list of given computers for non-System accounts used in services and non-Microsoft scheduled tasks
function Get-ServiceAccounts
{
<#
.SYNOPSIS
Reaches out to the given servers to get service accounts used in services and scheduled tasks
.DESCRIPTION
Checks each server in the list of given computers for non-System accounts used in services and non-Microsoft scheduled tasks
.EXAMPLE
Get-ServiceAccounts -ComputerName "SERVER1","SERVER2" -CSV
.NOTES
Britt Thompson
bthompson@automation.haus
.LINK
https://gist.github.com/automationhaus/063700ed973fc9ab8a560172994f56f8
#>
[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"
if($ForegroundColor -eq "") { $ForegroundColor = "White" }
$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" } }
default { $ForegroundColor = "White" }
}
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
$ErrorActionPreference = "Stop"
$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
# Establish script path for log output
$LogPath = "$ScriptPath\Logs"
$LogFile = "$LogPath\ServiceAccounts_$DateFormat.txt"
$CSVFile = "$LogPath\ServiceAccounts_$DateFormat.csv"
$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"
# Check the availability of the server and continue
if(Test-Connection -ComputerName $C -Count 1 -ErrorAction 0)
{
# Check all services
$Lang = "service accounts"
Write-Tee "[i] Checking for $Lang"
# Attempt a WMI connection and collect the services data
try
{
$Services = Get-WmiObject Win32_Service -ComputerName $C |
?{ $_.StartName -ne "LocalSystem" -and $_.StartName -notlike "NT *" -and $_.StartName.Length -gt 1 } |
Select @{Name="Server"; Expression = {$_.SystemName}},
Name, StartName, StartMode, State,
@{Name="TaskPath"; Expression = {"N\A"}},
@{Name="Type"; Expression = {"Service"}}
} catch { Get-Catch }
# If WMI didn't work and the version of PowerShell is at least 3 use CIM
if(!$Services -and $PSVersionTable.PSVersion.Major -ge 3)
{
try
{
$Services = Get-CIMInstance Win32_Service -ComputerName $C |
?{ $_.StartName -ne "LocalSystem" -and $_.StartName -notlike "NT *" -and $_.StartName.Length -gt 1 } |
Select @{Name="Server"; Expression = {$_.SystemName}},
Name, StartName, StartMode, State,
@{Name="TaskPath"; Expression = {"N\A"}},
@{Name="Type"; Expression = {"Service"}}
} catch { Get-Catch }
}
# Generate the output and results based on the status of services collected
if(!$Services)
{
Write-Tee "[i] No $Lang found for $C"
}
else
{
Write-Tee "[r] $($Services.Count) $Lang found for $C"
$Services | %{ Write-Tee "[+] [$($_.StartName)] $($_.Name)" }
$Results += $Services
}
# Check all scheduled tasks
$Lang = "scheduled tasks"
Write-Tee "[i] Checking for $Lang"
# If at least Server 2012 use Get-ScheduledTask to get task data otherwise use schtasks
if($OSVersion -ge 6.2)
{
try
{
# Establish a CIMSession with the computer for use with the Get-Scheduled task cmdlet
$Cim = New-CimSession $C
$Tasks = Get-ScheduledTask -CimSession $Cim |
?{
$_.TaskPath -notmatch "Microsoft" -and
$_.TaskName -notmatch "Optimize Start Menu Cache" -and
$_.TaskName -notmatch "User_Feed_Synchronization" -and
$_.Principal.UserId.Length -gt 1
} | Select @{Name="Server"; Expression = {$C}},
@{Name="Name"; Expression = {$_.TaskName}},
@{Name="StartName"; Expression = {$_.Principal.UserId}},
@{Name="StartMode"; Expression = {$_.Principal.RunLevel}},
State, TaskPath, @{Name="Type"; Expression = {"Task"}}
} catch { Get-Catch }
}
else
{
try
{
# Use schtasks to collect the task data on 2008 R2 and earlier
$Tasks = schtasks /query /s $C /V /FO CSV | ConvertFrom-Csv |
?{
$_.TaskName -notmatch "TaskName" -and
$_.TaskName -notmatch "\\Microsoft\\" -and
$_."Run As User" -ne "SYSTEM" -and
($_."Run As User").Length -gt 1 -and
$_.TaskName -notmatch "User_Feed_Synchronization*" -and
$_.TaskName -notlike "GoogleUpdate"
} | Select @{Name="Server"; Expression = {$_.HostName}},
@{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"}}
} catch { Get-Catch }
}
# Generate the output and results based on the status of tasks collected
if(!$Tasks)
{
Write-Tee "[i] No $Lang found for $C"
}
else
{
Write-Tee "[r] $($Tasks.Count) $Lang found for $C"
$Tasks | %{ Write-Tee "[+] [$($_.StartName)] $($_.Name)" }
$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