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


Import-Module ActiveDirectory

$GatewayNodes = @(
    'sgo-ts045-1.go.rshbank.ru'
    # остальные ноды
)

$Days = 30
$StartDate = (Get-Date).AddDays(-$Days)

Write-Host "Запуск сбора с нод RDGW..." -ForegroundColor Cyan

$RemoteScript = {
    param($Since)
    $Filter = @{
        LogName   = 'Microsoft-Windows-TerminalServices-Gateway/Operational'
        Id        = @(300, 301)
        StartTime = $Since
    }

    try {
        $events = Get-WinEvent -FilterHashtable $Filter -ErrorAction Stop
        foreach ($e in $events) {
            $xml = [xml]$e.ToXml()
            $info = $xml.Event.UserData.EventInfo
            
            $user = if ($info.Username) { $info.Username } else { $info.UsrName }
            $target = if ($info.Resource) { $info.Resource } else { $info.ResourceName }
            $ip = if ($info.IpAddress) { $info.IpAddress } else { $info.ClientIp }

            if ($user -and $target) {
                [PSCustomObject]@{
                    GatewayHost = $env:COMPUTERNAME
                    Timestamp   = $e.TimeCreated
                    UserName    = $user
                    TargetHost  = $target
                    ClientIP    = $ip
                }
            }
        }
    }
    catch {
        Write-Warning "Ошибка на $($env:COMPUTERNAME): $_"
    }
}

$AllConnections = Invoke-Command -ComputerName $GatewayNodes -ScriptBlock $RemoteScript -ArgumentList $StartDate -ThrottleLimit 4

if (-not $AllConnections) {
    Write-Warning "События не получены."
    return
}

Write-Host "Собрано сырых записей: $($AllConnections.Count). Начинаем обработку и проверку в AD/DNS..." -ForegroundColor Cyan

# Кэши для снижения нагрузки на AD и DNS
$UserStatusCache = @{}
$DnsCache = @{}

# Вспомогательная функция проверки пользователя в AD
function Test-UserIsActive ($rawUserName) {
    # Отрезаем домен (DOMAIN\user -> user)
    $samAccount = ($rawUserName -split '\\')[-1].Trim().ToLower()
    
    if ($UserStatusCache.ContainsKey($samAccount)) {
        return $UserStatusCache[$samAccount]
    }
    
    try {
        $adUser = Get-ADUser -Identity $samAccount -ErrorAction Stop
        # Проверяем, что найден и включен (Enabled: True)
        $isActive = ($adUser -ne $null) -and ($adUser.Enabled -eq $true)
        $UserStatusCache[$samAccount] = $isActive
        return $isActive
    }
    catch {
        # Пользователь не найден или удалён
        $UserStatusCache[$samAccount] = $false
        return $false
    }
}

# Вспомогательная функция резолва IP (10.x.x.x -> FQDN)
function Resolve-HostTarget ($target) {
    $target = $target.Trim().ToLower()
    
    # Проверяем, начинается ли с 10. (IP-адрес)
    if ($target -match '^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$') {
        if ($DnsCache.ContainsKey($target)) {
            return $DnsCache[$target]
        }
        
        try {
            # Быстрый reverse DNS (PTR)
            $resolved = [System.Net.Dns]::GetHostEntry($target).HostName.ToLower()
            $DnsCache[$target] = $resolved
            return $resolved
        }
        catch {
            # Если в PTR зоне нет записи, оставляем исходный IP
            $DnsCache[$target] = $target
            return $target
        }
    }
    
    return $target
}

# 1. Фильтруем и преобразуем хосты
$ProcessedConnections = foreach ($item in $AllConnections) {
    if (-not (Test-UserIsActive $item.UserName)) {
        continue
    }
    
    [PSCustomObject]@{
        GatewayHost = $item.GatewayHost
        Timestamp   = $item.Timestamp
        UserName    = ($item.UserName -split '\\')[-1].ToLower()
        TargetHost  = Resolve-HostTarget $item.TargetHost
        ClientIP    = $item.ClientIP
    }
}

# 2. Группируем по уникальным связкам уже с обновленными именами ПК
$Mapping = $ProcessedConnections | 
    Group-Object -Property UserName, TargetHost | 
    ForEach-Object {
        $Latest = $_.Group | Sort-Object Timestamp -Descending | Select-Object -First 1
        [PSCustomObject]@{
            UserName       = $Latest.UserName
            TargetHost     = $Latest.TargetHost
            LastConnection = $Latest.Timestamp
            LastGateway    = $Latest.GatewayHost
            LastClientIP   = $Latest.ClientIP
            TotalHits      = $_.Count
        }
    } | 
    Sort-Object UserName, TargetHost

# 3. Экспорт в CSV без кавычек
$OutPath = "C:\Temp\rdgw_cluster_mapping_clean.csv"
$Mapping | ConvertTo-Csv -NoTypeInformation | ForEach-Object { $_ -replace '"', '' } | Set-Content -Path $OutPath -Encoding UTF8

Write-Host "Готово! Сохранено активных связок: $($Mapping.Count) в $OutPath" -ForegroundColor Green