Skip to content

Instantly share code, notes, and snippets.

@bevinduplessis
Created January 17, 2017 09:34
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 bevinduplessis/1f5134a9897a6d315dafd49051ed645d to your computer and use it in GitHub Desktop.
Save bevinduplessis/1f5134a9897a6d315dafd49051ed645d to your computer and use it in GitHub Desktop.
Get a list of unique usernames being used to run services on a computer
Function Get-ServiceUsers
{
<#
.Synopsis
Get a list of unique usernames being used to run services on a computer.
.DESCRIPTION
Get a list of unique user's being used to run services on one or more computers.
.PARAMETER ComputerName
A single or list of computer names to perform search against.
.EXAMPLE
PS C:\> Get-ServiceUsers
ComputerName : SERVERDB11
Online : True
Domain :
Username : LocalSystem
ServiceName : ProfSvc
.EXAMPLE
PS C:\> Get-ServiceUsers -ComputerName (Get-ADComputer -Filter { OperatingSystem -like '*Windows Server*'}).Name | Where-Object {$_.Domain -like "DOM*"}
ComputerName : SERVERDB11
Online : True
Domain : DOM.CORP.COM
Username : sqladmin1
ServiceName : ReportServer
#>
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline = $True)]
[ValidateNotNullOrEmpty()]
[Alias('Computers', 'Name')]
[string[]] $ComputerName = $ENV:ComputerName,
[int] $Threads = $env:NUMBER_OF_PROCESSORS,
[switch] $ShowProgress = $True,
[switch] $ShowTime = $false,
[switch] $ShowOnlineOfflineSummary = $false,
[switch]$ShowFullOutput = $True,
[int] $Timeout = 300,
[int]$RetryCount = 5,
[int]$RetryWaitTime = 5,
[switch] $DNSLookup
)
Begin
{
Function Get-Result
{
[CmdletBinding()]
Param(
[switch] $Wait
)
Do
{
$More = $false
foreach ($Runspace in $Runspaces)
{
$StartTime = $RunspaceTimers[$Runspace.ID]
if ($Runspace.Handle.IsCompleted)
{
$Runspace.PowerShell.EndInvoke($Runspace.Handle)
$Runspace.PowerShell.Dispose()
$Runspace.PowerShell = $Null
$Runspace.Handle = $Null
}
elseif ($Runspace.Handle -ne $Null)
{
$More = $True
}
if ($Timeout -and $StartTime)
{
if ((New-TimeSpan -Start $StartTime).TotalSeconds -ge $Timeout -and $Runspace.PowerShell)
{
Write-Warning -Message ('Timeout {0}' -f $Runspace.IObject)
$Runspace.PowerShell.Dispose()
$Runspace.PowerShell = $Null
$Runspace.Handle = $Null
}
}
}
if ($More -and $PSBoundParameters['Wait'])
{
Start-Sleep -Milliseconds 100
}
foreach ($Thread in $Runspaces.Clone())
{
if (-not $Thread.Handle)
{
Write-Verbose -Message ('Removing [{0}] from runspaces' -f $Thread.IObject)
$Runspaces.Remove($Thread)
}
}
if ($ShowProgress)
{
$ProgressSplatting = @{
Activity = 'Checking hosts'
Status = 'Processing: {0} of {1} total hosts' -f ($RunspaceCounter - $Runspaces.Count), $RunspaceCounter
PercentComplete = ($RunspaceCounter - $Runspaces.Count) / $RunspaceCounter * 100
}
Write-Progress @ProgressSplatting
}
}
while ($More -and $PSBoundParameters['Wait'])
}
if($ComputerName.Count -gt 1)
{
Write-Verbose -Message "Processing [$($ComputerName.Count)] hosts"
}
$CachedErrorActionPreference = 'Stop'
$ErrorActionPreference = $CachedErrorActionPreference
$StartTime = Get-Date
$RunspaceTimers = [HashTable]::Synchronized(@{})
$Output = [HashTable]::Synchronized(@{})
$Runspaces = New-Object -TypeName System.Collections.ArrayList
$RunspaceCounter = 0
Write-Verbose -Message 'Creating initial session state'
$ISS = [initialsessionstate]::CreateDefault()
$ISS.Variables.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'RunspaceTimers', $RunspaceTimers, ''))
$ISS.Variables.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'Output', $Output, ''))
Write-Verbose -Message 'Creating runspace factory'
$RunspacePool = [runspacefactory]::CreateRunspacePool(1, $Threads, $ISS, $Host)
$RunspacePool.ApartmentState = 'STA'
$RunspacePool.Open()
$PsExecScriptBlock = {
[CmdletBinding()]
param(
[int] $ID,
[string] $ComputerName,
[int]$RetryCount,
[int]$RetryWaitTime,
[switch] $DNSLookup
)
Begin
{
Function Split-Username
{
[CmdletBinding()]
param
(
[string]$Username
)
if ($Username -like '*\*')
{
$Useroutput = [PSCustomObject]@{
domain = $Username.Split('\')[0].ToUpper()
username = $Username.Split('\')[1]
}
}
elseif ($Username -like '*@*')
{
$Useroutput = [PSCustomObject]@{
domain = $Username.Split('@')[1].ToUpper()
username = $Username.Split('@')[0]
}
}
else
{
$Useroutput = [PSCustomObject]@{
domain = ''
username = $Username
}
}
return $Useroutput
}
}
Process {
$RunspaceTimers.$ID = Get-Date
if (-not $Output.ContainsKey($ComputerName))
{
$Output[$ComputerName] = New-Object -TypeName PSObject -Property @{
ComputerName = $ComputerName
}
}
if ($DNSLookup)
{
Write-Verbose -Message "[$ComputerName] Performing DNS lookup."
$ErrorActionPreference = 'SilentlyContinue'
$HostEntry = [Net.Dns]::GetHostEntry($ComputerName)
$Result = $?
$ErrorActionPreference = $CachedErrorActionPreference
if ($Result)
{
if ($HostEntry.HostName.Split('.')[0] -ieq $ComputerName.Split('.')[0])
{
$IPDns = @($HostEntry |
Select-Object -ExpandProperty AddressList |
Select-Object -ExpandProperty IPAddressToString)
}
else
{
$IPDns = @(@($HostEntry.HostName) + @($HostEntry.Aliases))
}
$Output[$ComputerName] | Add-Member -MemberType NoteProperty -Name 'IP' -Value $IPDns
}
else
{
$Output[$ComputerName] | Add-Member -MemberType NoteProperty -Name 'IP' -Value $Null
}
}
Write-Verbose -Message "Pinging host [$ComputerName]"
$Online = $false
1..$RetryCount | ForEach-Object -Process {
$Param = @{
ComputerName = $ComputerName
BufferSize = 1
Count = 1
Quiet = $True
}
$Online = Test-Connection @Param
if($Online)
{
$Output[$ComputerName] | Add-Member -MemberType NoteProperty -Name Online -Value $True
}
else
{
$Output[$ComputerName] | Add-Member -MemberType NoteProperty -Name Online -Value $false
}
}
if($Online)
{
Write-Verbose -Message 'Attempting to get service users'
try
{
Write-Verbose -Message "Querying WMI on $ComputerName."
$Services = Get-WmiObject -ComputerName $ComputerName -Class win32_service -ErrorAction Stop | Select-Object -Property Name, StartName
}
catch
{
$ErrorText = $Error[0].Exception.Message
$ErrorShortText = $ErrorText.ToString().Split('(')[0]
Write-Verbose -Message "Could not talk to $ComputerName : $ErrorShortText"
Write-Error -Message "Could not talk to $ComputerName : $ErrorText"
}
finally
{
$Error.Clear()
}
$ServicesUsers = $Services |
Select-Object -Property StartName, Name |
Where-Object {
$_.StartName -ne $Null
} |
Sort-Object -Property StartName -Unique
Write-Verbose -Message "Processing a total of $($ServicesUsers.Count) service users for $ComputerName"
foreach ($ServicesUser in $ServicesUsers)
{
$Split = Split-Username -Username $ServicesUser.StartName
$Username = $Split.Username
$Domain = $Split.Domain
$Output[$ComputerName] | Add-Member -MemberType NoteProperty -Name 'Domain' -Value $Domain
$Output[$ComputerName] | Add-Member -MemberType NoteProperty -Name 'Username' -Value $Username
$Output[$ComputerName] | Add-Member -MemberType NoteProperty -Name 'ServiceName' -Value $ServicesUser.Name
}
}
}
}
}
Process
{
foreach ($Computer in $ComputerName)
{
Write-Verbose -Message "Processing [$Computer]"
++$RunspaceCounter
$psCMD = [powershell]::Create().AddScript($PsExecScriptBlock)
$null = $psCMD.AddParameter('ID', $RunspaceCounter)
$null = $psCMD.AddParameter('ComputerName', $Computer)
$null = $psCMD.AddParameter('RetryCount', $RetryCount)
$null = $psCMD.AddParameter('RetryWaitTime', $RetryWaitTime)
$null = $psCMD.AddParameter('DNSLookup', $DNSLookup)
$null = $psCMD.AddParameter('Verbose', $Global:VerbosePreference)
$psCMD.RunspacePool = $RunspacePool
$null = $Runspaces.Add(@{
Handle = $psCMD.BeginInvoke()
PowerShell = $psCMD
IObject = $Computer
ID = $RunspaceCounter
})
Get-Result
}
}
End
{
Get-Result -Wait
if ($ShowProgress)
{
Write-Progress -Activity 'Checking if host is online' -Status 'Done' -Completed
}
Write-Verbose -Message 'Closing runspace pool.'
$RunspacePool.Close()
Write-Verbose -Message 'Disposing runspace pool.'
$RunspacePool.Dispose()
[hashtable[]] $Properties = @{
Name = 'ComputerName'
Expression = {
$_.Name
}
}
if ($DNSLookup)
{
$Properties += @{
Name = 'IP'
Expression = {
$_.Value.'IP'
}
}
}
$Properties += @{
Name = 'Online'
Expression = {
$_.Value.Online
}
}
$Properties += @{
Name = 'Domain'
Expression = {
$_.Value.Domain
}
}
$Properties += @{
Name = 'Username'
Expression = {
$_.Value.Username
}
}
$Properties += @{
Name = 'ServiceName'
Expression = {
$_.Value.ServiceName
}
}
if ($ShowTime)
{
Write-Host ' '
Write-Host "Start time: $StartTime" -ForegroundColor Cyan
Write-Host "End time: $(Get-Date)" -ForegroundColor Cyan
}
if($ShowFullOutput)
{
Write-Host ' '
$Output.GetEnumerator() | Select-Object -Property $Properties | Sort-Object -Property Online
}
if($ShowOnlineOfflineSummary)
{
[int]$TotalOffline = 0
[int]$TotalOnline = 0
Foreach ($OutputObject in ($Output.GetEnumerator() | Select-Object -Property $Properties))
{
if($OutputObject.Online -eq $false)
{
++$TotalOffline
}
if ($OutputObject.Online -eq $True)
{
++$TotalOnline
}
}
Write-Host "Total Offline: " -NoNewLine
Write-Host "[$TotalOffline]" -ForegroundColor Red -BackgroundColor Black
Write-Host "Total Online: " -NoNewLine
Write-Host "[$TotalOnline]" -ForegroundColor Green -BackgroundColor Black
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment