198 lines
9.4 KiB
PowerShell
198 lines
9.4 KiB
PowerShell
function Get-AllServices {
|
|
<#
|
|
.SYNOPSIS
|
|
Used to find all services on a system but with all the details that we might use
|
|
Queries the registry to find all services that have at least an ImagePath, but filters out a majority of Windows Services (not all)
|
|
|
|
.PARAMETER All
|
|
Returns everything that wasn't filtered out for other reasons
|
|
|
|
.PARAMETER Name
|
|
Used to match names
|
|
|
|
.PARAMETER Path
|
|
Used to match paths
|
|
|
|
.PARAMETER Fragment
|
|
Used to search for any occurrence on path or name
|
|
|
|
.PARAMETER Exact
|
|
Used to specify matching an exact path or name
|
|
#>
|
|
[CmdletBinding(DefaultParameterSetName = 'All')]
|
|
param (
|
|
[Parameter(ParameterSetName = 'All')]
|
|
[switch]$All,
|
|
[Parameter(Mandatory = $true, ParameterSetName = 'Name')]
|
|
[Alias('NameLike')]
|
|
[Alias('NamePartial')]
|
|
[Alias('NameFragment')]
|
|
[string]$Name,
|
|
[Parameter(Mandatory = $true, ParameterSetName = 'Path')]
|
|
[Alias('PathLike')]
|
|
[Alias('PathPartial')]
|
|
[Alias('PathFragment')]
|
|
[string]$Path,
|
|
[Parameter(Mandatory = $true, ParameterSetName = 'Fragment')]
|
|
[Alias('Query')]
|
|
[string]$Fragment,
|
|
[Parameter(Mandatory = $false, ParameterSetName = 'Name')]
|
|
[Parameter(Mandatory = $false, ParameterSetName = 'Path')]
|
|
[switch]$Exact,
|
|
[switch]$RefreshCache
|
|
)
|
|
begin {
|
|
$logLead = (Get-LogLeadName)
|
|
|
|
# Define the defaults for the ServiceController response to add some custom display information
|
|
$defaultTypeName = 'ServiceObject'
|
|
$defaultKeys = @('Name')
|
|
$defaultDisplaySet = @('Name', 'RunAs', 'StartMode', 'ExePath')
|
|
$defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$defaultDisplaySet)
|
|
$defaultKeyPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultKeyPropertySet',[string[]]$defaultKeys)
|
|
$PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet,$defaultKeyPropertySet)
|
|
}
|
|
process {
|
|
$contains = $Name.IndexOf('*') -or $Path.IndexOf('*') -or $Fragment.IndexOf('*')
|
|
if ($contains -and $Exact) {
|
|
throw "$logLead : Can not search for an Exact match AND use wildcards"
|
|
}
|
|
$checkPath = ![string]::IsNullOrWhiteSpace($Path)
|
|
$checkName = ![string]::IsNullOrWhiteSpace($Name)
|
|
if (![string]::IsNullOrWhiteSpace($Fragment)) {
|
|
$checkPath = $true
|
|
$checkName = $true
|
|
$Name = $Fragment
|
|
$Path = $Fragment
|
|
}
|
|
|
|
$Name = $Name -Replace '\*',''
|
|
$Path = $Path -Replace '\*',''
|
|
|
|
if ($RefreshCache) {
|
|
$global:get_allservices_servicesWithPaths = $null
|
|
}
|
|
|
|
if ($null -ne $global:get_allservices_servicesWithPaths) {
|
|
$servicesWithPaths = $global:get_allservices_servicesWithPaths
|
|
} else {
|
|
$allServices = Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services\
|
|
|
|
# If there is no path property, we really don't care for the purposes of this function
|
|
$servicesWithAnyPath = $allServices.Where({$_.Property -Contains 'ImagePath'})
|
|
$servicesWithPaths = $servicesWithAnyPath.Where({!$_.GetValue('ImagePath').StartsWith("\SystemRoot")})
|
|
$global:get_allservices_servicesWithPaths = $servicesWithPaths
|
|
}
|
|
|
|
# https://docs.microsoft.com/en-us/windows/win32/msi/serviceinstall-table
|
|
$serviceType = @{0x1 = 'KernelDriver';0x2 = 'FileSystemDriver';0x4 = 'Adapter';0x8 = 'RecognizerDriver';0x10 = 'Win32OwnProcess';0x20 = 'Win32ShareProcess';0x100 = 'InteractiveProcess';}
|
|
$startMode = ('Boot','System','Automatic','Manual','Disabled')
|
|
$errorControl = ('Ignore','Normal','Severe','Critical')
|
|
|
|
$services = @()
|
|
foreach ($regService in $servicesWithPaths) {
|
|
$serviceName = (Split-Path -Path $regService -Leaf)
|
|
|
|
if ($checkName) {
|
|
$checkMatch = $checkName -and ($serviceName.IndexOf($Name, [StringComparison]::OrdinalIgnoreCase) -gt -1)
|
|
if ($checkName) {
|
|
# Write-Host "$logLead : $checkMatch | $serviceName | $Name"
|
|
}
|
|
$exactMatch = $Exact -and ($serviceName -eq $Name)
|
|
if ($Exact) {
|
|
# Write-Host "$logLead : $exactMatch | $serviceName | $Name"
|
|
}
|
|
|
|
if ($checkMatch -or $exactMatch) {
|
|
# We can continue, we found a matching name
|
|
# Write-Host "$logLead : Found $serviceName matched"
|
|
} else {
|
|
continue
|
|
}
|
|
}
|
|
|
|
$displayName = $regService.GetValue("DisplayName")
|
|
if (![string]::IsNullOrWhiteSpace($displayName)) { if ($displayName.IndexOf('@') -eq 0) {
|
|
if ($displayName.IndexOf(';') -gt -1) {
|
|
$displayName = $displayName.Substring($displayName.LastIndexOf(';'))
|
|
}
|
|
}} else {
|
|
$displayName = $serviceName
|
|
}
|
|
if ($displayName.IndexOf('@') -eq 0) {
|
|
# Neat trick: Alkami doesn't care about these services _at all_
|
|
continue
|
|
}
|
|
|
|
$description = $regService.GetValue("Description")
|
|
if (![string]::IsNullOrWhiteSpace($description)) { if ($description.IndexOf('@') -eq 0) {
|
|
# Neat trick: Alkami _also_ doesn't care about these services _at all_
|
|
continue
|
|
}}
|
|
|
|
$imagePath = $regService.GetValue("ImagePath")
|
|
$exePath = $imagePath
|
|
if (![string]::IsNullOrWhiteSpace($imagePath)) { if ($imagePath.IndexOf('"') -gt -1) {
|
|
$exePath = ($imagePath.Remove($imagePath.LastIndexOf(".exe",[StringComparison]::OrdinalIgnoreCase)) + ".exe").Replace('"','')
|
|
}}
|
|
$loginName = ($regService.GetValue("ObjectName"),'LocalSystem' -ne $null)[0]
|
|
|
|
if ($checkPath) {
|
|
$checkMatch = $checkPath -and ($exePath.IndexOf($Path, [StringComparison]::OrdinalIgnoreCase) -gt -1)
|
|
if ($checkPath) {
|
|
# Write-Host "$logLead : $checkMatch | $exePath | $Path"
|
|
}
|
|
$exactMatch = $Exact -and ($exePath -eq $Path)
|
|
if ($Exact) {
|
|
# Write-Host "$logLead : $exactMatch | $exePath | $Path"
|
|
}
|
|
|
|
if ($checkMatch -or $exactMatch) {
|
|
# We can continue, we found a matching path
|
|
# Write-Host "$logLead : Found $exePath matched"
|
|
} else {
|
|
continue
|
|
}
|
|
}
|
|
|
|
$startModeValue = $regService.GetValue("Start")
|
|
|
|
$obj = @{
|
|
Name = $serviceName
|
|
StartMode = $startMode[$startModeValue]
|
|
StartType = <#[System.ServiceProcess.ServiceStartMode]#>$startModeValue
|
|
ErrorControl = $errorControl[$regService.GetValue("ErrorControl")]
|
|
ImagePath = $imagePath
|
|
ExePath = $exePath
|
|
RunAs = $loginName
|
|
DisplayName = $displayName
|
|
Description = $description
|
|
Dependencies = $regService.GetValue("Dependencies")
|
|
ManagedServiceAccount = [System.BitConverter]::ToInt32(($regService.GetValue("ServiceAccountManaged"),@(0,0,0,0) -ne $null)[0],0) -eq 1
|
|
FailureActions = ConvertFrom-FailureActions -FailureActions $regService.GetValue("FailureActions")
|
|
# FailureActionsOnNonCrashFailures https://docs.microsoft.com/en-us/windows/win32/api/winsvc/ns-winsvc-service_failure_actions_flag
|
|
# If this member is TRUE and the service has configured failure actions, the failure actions are queued if the service process terminates without reporting a status of SERVICE_STOPPED or if it enters the SERVICE_STOPPED state but the dwWin32ExitCode member of the SERVICE_STATUS structure is not ERROR_SUCCESS (0).
|
|
# If this member is FALSE and the service has configured failure actions, the failure actions are queued only if the service terminates without reporting a status of SERVICE_STOPPED.
|
|
FailureActionsOnNonCrashFailures = $regService.GetValue("FailureActionsOnNonCrashFailures") -eq 1
|
|
FailureCommand = $regService.GetValue("FailureCommand")
|
|
DelayedAutostart = $regService.GetValue("DelayedAutostart")
|
|
AutoRun = $regService.GetValue("AutoRun")
|
|
AutoRunAlwaysDisable = $regService.GetValue("AutoRunAlwaysDisable")
|
|
AutorunsDisabled = $regService.GetValue("AutorunsDisabled")
|
|
StateFlags = $regService.GetValue("StateFlags")
|
|
Type = $serviceType[$regService.GetValue("Type")]
|
|
# Where we find this key
|
|
# Key = $regService
|
|
# The properties this object has so we can get the data later for confirming we got everything we want
|
|
# Property = $regService.Property
|
|
}
|
|
|
|
$serviceController = New-Object PSCustomObject -Property $obj
|
|
$serviceController.PSObject.TypeNames.Insert(0,$defaultTypeName)
|
|
$serviceController | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers
|
|
|
|
$services += $serviceController
|
|
}
|
|
return $services
|
|
}
|
|
} |