Загрузка данных


$ErrorActionPreference = 'SilentlyContinue'

$Results = @()

# klipa1 ... klipa35
$KlipaPattern = '^klipa(?:[1-9]|[12][0-9]|3[0-5])$'

$WshShell = New-Object -ComObject WScript.Shell

# ------------------------------------------------------------
# Функция: получить klipaN из RDP-файла
# ------------------------------------------------------------
function Get-KlipaFromRdp {
    param(
        [Parameter(Mandatory = $true)]
        [string]$RdpPath
    )

    if (-not (Test-Path -LiteralPath $RdpPath -PathType Leaf)) {
        return $null
    }

    try {
        $FullAddressLine = Get-Content `
            -LiteralPath $RdpPath `
            -ErrorAction Stop |
            Where-Object {
                $_ -match '^\s*full\s+address\s*:'
            } |
            Select-Object -First 1

        if (-not $FullAddressLine) {
            return $null
        }

        if ($FullAddressLine -match '^\s*full\s+address\s*:\s*s\s*:\s*(.+?)\s*$') {

            $Address = $Matches[1].Trim()

            # klipa1:3389 -> klipa1
            $TargetHost = ($Address -split ':')[0].Trim()

            # klipa1.domain.local -> klipa1
            $ShortHost = ($TargetHost -split '\.')[0].Trim()

            if ($ShortHost -match $KlipaPattern) {
                return $ShortHost.ToLower()
            }
        }
    }
    catch {
        return $null
    }

    return $null
}

# ------------------------------------------------------------
# Пользовательские профили
# ------------------------------------------------------------
$UserProfiles = Get-ChildItem `
    -LiteralPath 'C:\Users' `
    -Directory `
    -Force `
    -ErrorAction SilentlyContinue |
    Where-Object {
        $_.Name -notin @(
            'Public',
            'Default',
            'Default User',
            'All Users'
        )
    }

foreach ($UserProfile in $UserProfiles) {

    $UserName = $UserProfile.Name

    # Только папки первого уровня пользователя.
    # AppData полностью исключаем.
    $FirstLevelFolders = Get-ChildItem `
        -LiteralPath $UserProfile.FullName `
        -Directory `
        -Force `
        -ErrorAction SilentlyContinue |
        Where-Object {
            $_.Name -ne 'AppData'
        }

    foreach ($Folder in $FirstLevelFolders) {

        # ------------------------------------------------------------
        # Все .RDP и .LNK рекурсивно внутри папки первого уровня
        # ------------------------------------------------------------
        $Files = Get-ChildItem `
            -LiteralPath $Folder.FullName `
            -Recurse `
            -Force `
            -ErrorAction SilentlyContinue |
            Where-Object {
                -not $_.PSIsContainer -and (
                    $_.Extension -ieq '.rdp' -or
                    $_.Extension -ieq '.lnk'
                )
            }

        foreach ($File in $Files) {

            # ========================================================
            # Обычный RDP-файл
            # ========================================================
            if ($File.Extension -ieq '.rdp') {

                $Klipa = Get-KlipaFromRdp -RdpPath $File.FullName

                if ($Klipa) {
                    $Results += [PSCustomObject]@{
                        User = $UserName
                        Host = $Klipa
                        Type = 'RDP'
                        Path = $File.FullName
                    }
                }

                continue
            }

            # ========================================================
            # Windows shortcut .LNK
            # ========================================================
            if ($File.Extension -ieq '.lnk') {

                try {
                    $Shortcut = $WshShell.CreateShortcut($File.FullName)

                    $TargetPath = [Environment]::ExpandEnvironmentVariables(
                        $Shortcut.TargetPath
                    )

                    $Arguments = [Environment]::ExpandEnvironmentVariables(
                        $Shortcut.Arguments
                    )

                    $MatchedHost = $null

                    # ------------------------------------------------
                    # Вариант 1:
                    # ярлык непосредственно указывает на *.rdp
                    # ------------------------------------------------
                    if (
                        $TargetPath -and
                        $TargetPath -match '(?i)\.rdp$'
                    ) {
                        $MatchedHost = Get-KlipaFromRdp -RdpPath $TargetPath
                    }

                    # ------------------------------------------------
                    # Вариант 2:
                    # mstsc.exe /v:klipa1
                    # mstsc.exe /v klipa1
                    # mstsc.exe /v:klipa1:3389
                    # ------------------------------------------------
                    if (
                        -not $MatchedHost -and
                        [System.IO.Path]::GetFileName($TargetPath) -ieq 'mstsc.exe'
                    ) {

                        $VMatch = [regex]::Match(
                            $Arguments,
                            '(?i)(?:^|\s)/v(?::|\s+)\s*(?<address>[^\s"]+)'
                        )

                        if ($VMatch.Success) {

                            $Address = $VMatch.Groups['address'].Value.Trim()

                            $TargetHost = ($Address -split ':')[0].Trim()
                            $ShortHost = ($TargetHost -split '\.')[0].Trim()

                            if ($ShortHost -match $KlipaPattern) {
                                $MatchedHost = $ShortHost.ToLower()
                            }
                        }
                    }

                    # ------------------------------------------------
                    # Вариант 3:
                    #
                    # Target:
                    #   C:\Windows\System32\mstsc.exe
                    #
                    # Arguments:
                    #   "C:\Users\user\workplace\Default.rdp"
                    # ------------------------------------------------
                    if (
                        -not $MatchedHost -and
                        [System.IO.Path]::GetFileName($TargetPath) -ieq 'mstsc.exe' -and
                        $Arguments
                    ) {

                        $RdpArgument = $null

                        # Сначала ищем путь в кавычках
                        $QuotedMatch = [regex]::Match(
                            $Arguments,
                            '(?i)"(?<path>[^"]+\.rdp)"'
                        )

                        if ($QuotedMatch.Success) {
                            $RdpArgument = $QuotedMatch.Groups['path'].Value
                        }
                        else {
                            # Путь без кавычек
                            $PlainMatch = [regex]::Match(
                                $Arguments,
                                '(?i)(?<path>[A-Z]:\\.+?\.rdp)(?:\s|$)'
                            )

                            if ($PlainMatch.Success) {
                                $RdpArgument = $PlainMatch.Groups['path'].Value
                            }
                        }

                        if ($RdpArgument) {

                            $RdpArgument = [Environment]::ExpandEnvironmentVariables(
                                $RdpArgument
                            )

                            $MatchedHost = Get-KlipaFromRdp `
                                -RdpPath $RdpArgument
                        }
                    }

                    if ($MatchedHost) {

                        $Results += [PSCustomObject]@{
                            User = $UserName
                            Host = $MatchedHost
                            Type = 'LNK'
                            Path = $File.FullName
                        }
                    }
                }
                catch {
                    # Битые/недоступные ярлыки пропускаем
                }
            }
        }
    }
}

# ------------------------------------------------------------
# Убираем дубли
# ------------------------------------------------------------
$Results = $Results |
    Sort-Object User, Host, Type, Path -Unique

# ------------------------------------------------------------
# PDQ OUTPUT
# ------------------------------------------------------------
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 'Сканирование завершено.'