Всем привет.
Время от времени администратору необходимо проводить аудит логов RDP подключений в Windows. Как правило, это может пригодиться при расследовании различных инцидентов на терминальных / RDS серверах Windows, когда от системного администратора требуется предоставить информацию: какие пользователи входили на RDS сервер, когда авторизовался и завершил сеанс конкретный пользователь, с какого устройства (имя или IP адрес) подключался RDP-пользователь, и т.п.
Используем Powershell. Самый простой запрос:
Get-EventLog security -after (Get-date -hour 0 -minute 0 -second 0) | ?{$_.eventid -eq 4624 -and $_.Message -match 'Тип входа:\s+(10)\s'} | select -First 5 | Select $_.Message
И более развернутый вариант. Обращаю ваше внимание на различие запросов по языку интерфейса.
# English версия
Get-EventLog -LogName Security -after (Get-date -hour 0 -minute 0 -second 0)| ?{(4624,4778) -contains $_.EventID -and $_.Message -match 'Тип входа:\s+(10)\s'}| %{
(new-object -Type PSObject -Property @{
TimeGenerated = $_.TimeGenerated
ClientIP = $_.Message -replace '(?smi).*Source Network Address:\s+([^\s]+)\s+.*','$1'
UserName = $_.Message -replace '(?smi).*Account Name:\s+([^\s]+)\s+.*','$1'
UserDomain = $_.Message -replace '(?smi).*Account Domain:\s+([^\s]+)\s+.*','$1'
LogonType = $_.Message -replace '(?smi).*Logon Type:\s+([^\s]+)\s+.*','$1'
})
} | sort TimeGenerated -Descending | Select TimeGenerated, ClientIP `
, @{N='Username';E={'{0}\{1}' -f $_.UserDomain,$_.UserName}} `
, @{N='LogType';E={
switch ($_.LogonType) {
2 {'Interactive - local logon'}
3 {'Network conection to shared folder)'}
4 {'Batch'}
5 {'Service'}
7 {'Unlock (after screensaver)'}
8 {'NetworkCleartext'}
9 {'NewCredentials (local impersonation process under existing connection)'}
10 {'RDP'}
11 {'CachedInteractive'}
default {"LogType Not Recognised: $($_.LogonType)"}
}
}} | Export-Csv RDP-eng.txt -Encoding UTF8
# Russian версия
Get-EventLog -LogName Security -after (Get-date -hour 0 -minute 0 -second 0)| ?{(4624,4778) -contains $_.EventID -and $_.Message -match ‘Тип входа:\s+(10)\s’}| %{
(new-object -Type PSObject -Property @{
TimeGenerated = $_.TimeGenerated
ClientIP = $_.Message -replace ‘(?smi).*Сетевой адрес источника:\s+([^\s]+)\s+.*’,’$1'
UserName = $_.Message -replace ‘(?smi).*Имя учетной записи:\s+([^\s]+)\s+.*’,’$1'
UserDomain = $_.Message -replace ‘(?smi).*Домен учетной записи:\s+([^\s]+)\s+.*’,’$1'
LogonType = $_.Message -replace ‘(?smi).*Тип входа:\s+([^\s]+)\s+.*’,’$1'
})
} | sort TimeGenerated | Select TimeGenerated, ClientIP `
, @{N=’Username’;E={‘{0}\{1}’ -f $_.UserDomain,$_.UserName}} `
, @{N=’LogType’;E={
switch ($_.LogonType) {
2 {‘Interactive — local logon’}
3 {‘Network conection to shared folder)’}
4 {‘Batch’}
5 {‘Service’}
7 {‘Unlock (after screensaver)’}
8 {‘NetworkCleartext’}
9 {‘NewCredentials (local impersonation process under existing connection)’}
10 {‘RDP’}
11 {‘CachedInteractive’}
default {«LogType Not Recognised: $($_.LogonType)»}
}
}} | Export-Csv RDP-rus.txt -Encoding UTF8
Если вас не интересует сама авторизация RDP-подключения то не обязательно анализировать журнал Security. Есть более простой способ. Открываем журнал Diagnostics -> Event Viewer -> Applications and Services Logs -> Microsoft -> Windows -> TerminalServices-RemoteConnectionManager->Operational и смотрим события с номером Event Id 1149. Для удобства можно отфильтровать журнал по событию с этим номером.
#------- Connection by RDP ------------------
Так по имени сервера и логину пользователя найдем все состоявшиеся RDP подключения, которые есть в журнале событий.
$servername = "sccm01.forza.com"
$username = "Cooladmin"
[xml]$equery = @"
<QueryList>
<Query Id="0" Path="Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational">
<Select Path="Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational">*[System[(EventID=1149)]] and *[UserData[EventXML[(Param1='$username')]]]</Select>
</Query>
</QueryList>
"@
Get-WinEvent -ComputerName $servername -FilterXML $equery |
Select-Object TimeCreated, @{Name="User";Expression={$_.Properties[0].Value}},
@{Name="Domain";Expression={$_.Properties[1].Value}},
@{Name="Source Network Address";Expression={$_.Properties[2].Value}},MachineName | Out-GridView
#--------- Connections thru RD Gateway 1 ----------------
Выводим состоявшиеся подключения через RD Gateway. Обратите внимание на то, что логин должен быть задан в полной форме.
$servername = "sccm01.forza.com"
$username = "forza.com\Cooladmin"
[xml]$equery = @"
<QueryList>
<Query Id="0" Path="Microsoft-Windows-TerminalServices-Gateway/Operational">
<Select Path="Microsoft-Windows-TerminalServices-Gateway/Operational">*[System[(EventID=302)]] and *[UserData[EventInfo[(Username='$username')]]]</Select>
</Query>
</QueryList>
"@
Get-WinEvent -ComputerName $servername -FilterXML $equery |
Select-Object TimeCreated, @{Name="User";Expression={$_.Properties[0].Value}},
@{Name="Source Network Address";Expression={$_.Properties[1].Value}},
@{Name="Resource";Expression={$_.Properties[3].Value}},MachineName | Out-GridView
#--------- Connections thru RD Gateway 2 ----------------
Тоже самое только имя пользователя задается в формате RegEx для поиска по шаблону. Этот вариант будет работать очень медленно! К сожалению, Windows не поддерживает поиск по шаблону в XPath для значений.
$servername = "sccm01.forza.com"
$username = "Cooladmin"
[xml]$equery = @"
<QueryList>
<Query Id="0" Path="Microsoft-Windows-TerminalServices-Gateway/Operational">
<Select Path="Microsoft-Windows-TerminalServices-Gateway/Operational">*[System[(EventID=302)]]</Select>
</Query>
</QueryList>
"@
Get-WinEvent -ComputerName $servername -FilterXML $equery |
Select-Object TimeCreated, @{Name="User";Expression={$_.Properties[0].Value}},
@{Name="Source Network Address";Expression={$_.Properties[1].Value}},
@{Name="Resource";Expression={$_.Properties[3].Value}},MachineName |
Where-Object {$_.User -match $username} | Out-GridView
Еще такой вариант - возможно вам понадобиться провести аудит активных RDP-сессий на ваших серверах. В этом случае вам поможет следующий скрипт, список исследуемых серверов помещаете в файл servers.txt, либо получаете прямым запросом из AD.
$Today = Get-Date
$SessionLis t = "`n`nRDP Session List - " + $Today + "`n`n"
$CurrentSN = 0
#$Servers = Get-ADComputer -filter {OperatingSystem -like "*server*"}
#$Servers = Import-Csv -Encoding UTF8 -path "D:\PS\servers.txt" -Delimiter ","
$Servers = Get-ADComputer -filter * -searchbase "OU=Infrastructure Servers,DC=forza,DC=com"
$NumberOfServers = $Servers.Count
ForEach ($Server in $Servers) {
$ServerName = $Server.Name
Write-progress -activity "Checking RDP Sessions" -status "Querying $ServerName" -percentcomplete (($CurrentSN/$NumberOfServers)*100)
try
{
$queryResults = (qwinsta /server:$ServerName | foreach { (($_.trim() -replace "\s+",","))} | convertfrom-csv)
# Обращаю ваше внимание на различие запросa по языку интерфейса.
ForEach($QueryResult in $QueryResults) {
# $RDPUser=$QueryResult.USERNAME
# $SessionType=$QueryResult.SESSIONNAME
# $SessionID=$QueryResult.ID
# $ReturnedCurrentState=$QueryResult.State
$RDPUser = $QueryResult.ПОЛЬЗОВАТЕЛЬ
$SessionType = $QueryResult.СЕАНС
$SessionID = $QueryResult.ID
$ReturnedCurrentState = $QueryResult.СТАТУС
If($ReturnedCurrentState -eq $null){ $CurrentState="Disconnected" } Else { $CurrentState="Active" }
If (($RDPUser -ne $NULL) -and ($SessionType -ne "console") -and ($SessionType -ne "services") -and ($SessionType -ne "rdp-tcp") -and ($RDPUser -ne "65536")) {
$SessionList=$SessionList + "`n" + $ServerName + " logged in by " + $RDPUser + " as " + $SessionType + ", session id "+ $SessionID + " is " + $CurrentState
}
}
}
catch
{
$SessionList=$SessionList + "`n Unable to query " + $ServerName
write-host "Unable to query $ServerName!" -foregroundcolor Red
}
$CurrentSN++
}
$SessionList + "`n`n"
На этом все.
No comments:
Post a Comment
А что вы думаете по этому поводу?