Загрузка данных
$ErrorActionPreference = 'SilentlyContinue'
# Допустимые имена хостов: klipa1 ... klipa35
$KlipaRegex = '(?i)\bklipa(?:[1-9]|[12][0-9]|3[0-5])\b'
$Results = New-Object System.Collections.Generic.List[object]
# WScript.Shell нужен для чтения .lnk
$WshShell = New-Object -ComObject WScript.Shell
# Берем реальные папки профилей из C:\Users
$UserProfiles = Get-ChildItem -Path 'C:\Users' -Directory -Force |
Where-Object {
$_.Name -notin @(
'Public',
'Default',
'Default User',
'All Users'
)
}
foreach ($UserProfile in $UserProfiles) {
$UserName = $UserProfile.Name
# Только папки первого уровня профиля, кроме AppData.
# После этого внутри каждой такой папки поиск идет рекурсивно.
$FirstLevelFolders = Get-ChildItem -Path $UserProfile.FullName -Directory -Force |
Where-Object {
$_.Name -ne 'AppData'
}
foreach ($Folder in $FirstLevelFolders) {
# Ищем только RDP-файлы и Windows-ярлыки
$Files = Get-ChildItem `
-Path $Folder.FullName `
-File `
-Recurse `
-Force `
-Include '*.rdp', '*.lnk' `
-ErrorAction SilentlyContinue
foreach ($File in $Files) {
# ------------------------------------------------------------
# .RDP
# ------------------------------------------------------------
if ($File.Extension -ieq '.rdp') {
$Content = Get-Content -LiteralPath $File.FullName -Raw -ErrorAction SilentlyContinue
if (-not $Content) {
continue
}
# Стандартная строка в RDP:
# full address:s:klipa12
$AddressMatch = [regex]::Match(
$Content,
'(?im)^\s*full address\s*:\s*s\s*:\s*(?<host>[^\r\n:]+)'
)
if ($AddressMatch.Success) {
$HostName = $AddressMatch.Groups['host'].Value.Trim()
if ($HostName -match "^$KlipaRegex$") {
$Results.Add([PSCustomObject]@{
User = $UserName
Host = $HostName
Type = 'RDP'
Path = $File.FullName
})
}
}
}
# ------------------------------------------------------------
# .LNK
# ------------------------------------------------------------
elseif ($File.Extension -ieq '.lnk') {
try {
$Shortcut = $WshShell.CreateShortcut($File.FullName)
$TargetPath = $Shortcut.TargetPath
$Arguments = $Shortcut.Arguments
$MatchedHost = $null
# Вариант 1:
# ярлык запускает mstsc.exe /v:klipa12
if (
$TargetPath -match '(?i)\\mstsc\.exe$' -or
[System.IO.Path]::GetFileName($TargetPath) -ieq 'mstsc.exe'
) {
$ArgMatch = [regex]::Match(
$Arguments,
'(?i)(?:/v:|/v\s+)(?<host>klipa(?:[1-9]|[12][0-9]|3[0-5]))(?:\b|:)'
)
if ($ArgMatch.Success) {
$MatchedHost = $ArgMatch.Groups['host'].Value
}
}
# Вариант 2:
# ярлык напрямую указывает на .rdp-файл
if (
-not $MatchedHost -and
$TargetPath -and
$TargetPath.EndsWith('.rdp', [System.StringComparison]::OrdinalIgnoreCase) -and
(Test-Path -LiteralPath $TargetPath)
) {
$RdpContent = Get-Content -LiteralPath $TargetPath -Raw -ErrorAction SilentlyContinue
if ($RdpContent) {
$AddressMatch = [regex]::Match(
$RdpContent,
'(?im)^\s*full address\s*:\s*s\s*:\s*(?<host>[^\r\n:]+)'
)
if ($AddressMatch.Success) {
$HostName = $AddressMatch.Groups['host'].Value.Trim()
if ($HostName -match "^$KlipaRegex$") {
$MatchedHost = $HostName
}
}
}
}
if ($MatchedHost) {
$Results.Add([PSCustomObject]@{
User = $UserName
Host = $MatchedHost
Type = 'LNK'
Path = $File.FullName
})
}
}
catch {
# Битые/недоступные ярлыки просто пропускаем
}
}
}
}
}
# Убираем возможные дубли
$Results = $Results |
Sort-Object User, Host, Type, Path -Unique
Write-Output '============================================================'
Write-Output 'RDP KLIPA SCAN'
Write-Output "Computer: $env:COMPUTERNAME"
Write-Output '============================================================'
if (-not $Results -or $Results.Count -eq 0) {
Write-Output 'Совпадений не найдено.'
}
else {
Write-Output "Найдено совпадений: $($Results.Count)"
Write-Output ''
foreach ($Result in $Results) {
Write-Output "Пользователь : $($Result.User)"
Write-Output "Клипа : $($Result.Host)"
Write-Output "Тип : $($Result.Type)"
Write-Output "Файл : $($Result.Path)"
Write-Output '------------------------------------------------------------'
}
}
Write-Output 'Сканирование завершено.'