93 lines
3.7 KiB
PowerShell
93 lines
3.7 KiB
PowerShell
Set-StrictMode -Version Latest
|
|
|
|
function Get-CampaignLaSessionProcessCorrelations {
|
|
[CmdletBinding()]
|
|
param()
|
|
|
|
$matches = [Collections.Generic.List[object]]::new()
|
|
if ($IsWindows) {
|
|
$pattern = '(?i)(?:^|\s)(?:--config|--session-config)\s+(?:"([^"]+)"|(\S+))'
|
|
foreach ($candidate in @(Get-CimInstance Win32_Process -ErrorAction Stop)) {
|
|
$commandLine = [string]$candidate.CommandLine
|
|
if ([string]::IsNullOrWhiteSpace($commandLine)) { continue }
|
|
foreach ($match in [Text.RegularExpressions.Regex]::Matches(
|
|
$commandLine,
|
|
$pattern)) {
|
|
$value = if ($match.Groups[1].Success) {
|
|
$match.Groups[1].Value
|
|
} else { $match.Groups[2].Value }
|
|
if ([IO.Path]::IsPathFullyQualified($value)) {
|
|
$matches.Add([pscustomobject]@{
|
|
ProcessId = [int]$candidate.ProcessId
|
|
SessionConfigPath = [IO.Path]::GetFullPath($value)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
elseif ($IsLinux) {
|
|
foreach ($directory in [IO.Directory]::EnumerateDirectories('/proc')) {
|
|
$leaf = [IO.Path]::GetFileName($directory)
|
|
$processId = 0
|
|
if (-not [int]::TryParse(
|
|
$leaf,
|
|
[Globalization.NumberStyles]::None,
|
|
[Globalization.CultureInfo]::InvariantCulture,
|
|
[ref]$processId)) {
|
|
continue
|
|
}
|
|
try {
|
|
$bytes = [IO.File]::ReadAllBytes((Join-Path $directory 'cmdline'))
|
|
if ($bytes.Length -eq 0) { continue }
|
|
$arguments = @([Text.Encoding]::UTF8.GetString($bytes).Split(
|
|
[char]0,
|
|
[StringSplitOptions]::RemoveEmptyEntries))
|
|
for ($index = 0; $index + 1 -lt $arguments.Count; $index++) {
|
|
if ($arguments[$index] -cin @('--config', '--session-config') -and
|
|
[IO.Path]::IsPathFullyQualified($arguments[$index + 1])) {
|
|
$matches.Add([pscustomobject]@{
|
|
ProcessId = $processId
|
|
SessionConfigPath = [IO.Path]::GetFullPath(
|
|
$arguments[$index + 1])
|
|
})
|
|
}
|
|
}
|
|
}
|
|
catch [IO.IOException] {
|
|
# A process may exit between /proc enumeration and cmdline read.
|
|
}
|
|
catch [UnauthorizedAccessException] {
|
|
# Other-user processes cannot be the owner-readable gate child.
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
throw 'Campaign LA process correlation supports Windows and Linux only.'
|
|
}
|
|
|
|
return @($matches)
|
|
}
|
|
|
|
function Get-CampaignLaCorrelatedProcessIds {
|
|
[CmdletBinding()]
|
|
param([Parameter(Mandatory = $true)][string]$SessionConfigPath)
|
|
|
|
if (-not [IO.Path]::IsPathFullyQualified($SessionConfigPath)) {
|
|
throw 'Session-config correlation requires an absolute path.'
|
|
}
|
|
$SessionConfigPath = [IO.Path]::GetFullPath($SessionConfigPath)
|
|
$comparison = if ($IsWindows) {
|
|
[StringComparison]::OrdinalIgnoreCase
|
|
} else { [StringComparison]::Ordinal }
|
|
$matches = [Collections.Generic.HashSet[int]]::new()
|
|
foreach ($candidate in @(Get-CampaignLaSessionProcessCorrelations)) {
|
|
if ([string]::Equals(
|
|
$candidate.SessionConfigPath,
|
|
$SessionConfigPath,
|
|
$comparison)) {
|
|
$null = $matches.Add([int]$candidate.ProcessId)
|
|
}
|
|
}
|
|
|
|
return @($matches | Sort-Object)
|
|
}
|