Загрузка данных
<#
.SYNOPSIS
GUI-скрипт для сбора информации о пользователе RDS и управления сессиями/дисками профилей.
.DESCRIPTION
Запрашивает имя пользователя, ищет в AD, собирает сведения об учётной записи,
текущих и предыдущих сессиях (с брокера), дисках UPD.
Имя брокера и список коллекций с путями UPD хранятся в settings.ini рядом со скриптом.
Кнопка "Обновить коллекции" перезапрашивает данные с брокера и обновляет INI.
.NOTES
Требуется PowerShell 3.0+, модули ActiveDirectory и RemoteDesktop.
Запускать от имени администратора домена.
#>
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
Import-Module RemoteDesktop -ErrorAction SilentlyContinue
Import-Module ActiveDirectory -ErrorAction SilentlyContinue
# ============================================================================
# 1. ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
# ============================================================================
function Write-Diag {
param([string]$Message, [string]$Level = "Info")
$ts = Get-Date -Format "HH:mm:ss"
switch ($Level) {
"Warn" { Write-Warning "[$ts] $Message" }
"Err" { Write-Host "[$ts] [ОШИБКА] $Message" -ForegroundColor Red }
default { Write-Host "[$ts] $Message" -ForegroundColor Cyan }
}
}
# --- INI ---
function Get-IniPath {
return (Join-Path $PSScriptRoot "settings.ini")
}
function Read-IniFile {
param([string]$Path)
$ini = @{}
if (-not (Test-Path $Path)) { return $ini }
$section = "Global"
$ini[$section] = @{}
try {
foreach ($line in Get-Content -Path $Path -Encoding UTF8) {
$trimmed = $line.Trim()
if ($trimmed -eq "" -or $trimmed.StartsWith(";") -or $trimmed.StartsWith("#")) { continue }
if ($trimmed -match '^\[(.+?)\]$') {
$section = $Matches[1].Trim()
if (-not $ini.ContainsKey($section)) { $ini[$section] = @{} }
continue
}
if ($trimmed -match '^(.+?)=(.*)$') {
$key = $Matches[1].Trim()
$value = $Matches[2].Trim()
$ini[$section][$key] = $value
}
}
} catch {
Write-Diag "Не удалось прочитать $Path : $($_.Exception.Message)" "Warn"
}
return $ini
}
function Write-IniFile {
param([string]$Path, [hashtable]$Ini)
$lines = New-Object System.Collections.Generic.List[string]
$lines.Add("; Настройки RDS User Info")
$lines.Add("; Автоматически созданный файл. Можно править вручную.")
$lines.Add("")
# Порядок секций: Settings, затем Collections
$orderedSections = @()
if ($Ini.ContainsKey("Settings")) { $orderedSections += "Settings" }
if ($Ini.ContainsKey("Collections")) { $orderedSections += "Collections" }
foreach ($s in $Ini.Keys) {
if ($s -notin $orderedSections) { $orderedSections += $s }
}
foreach ($section in $orderedSections) {
$lines.Add("[$section]")
foreach ($key in $Ini[$section].Keys) {
$lines.Add("$key=$($Ini[$section][$key])")
}
$lines.Add("")
}
Set-Content -Path $Path -Value $lines -Encoding UTF8
}
function Read-Settings {
$ini = Read-IniFile -Path (Get-IniPath)
$broker = $null
$collections = @{}
if ($ini.ContainsKey("Settings") -and $ini.Settings.ContainsKey("Broker")) {
$broker = $ini.Settings.Broker
}
if ($ini.ContainsKey("Collections")) {
foreach ($k in $ini.Collections.Keys) {
$collections[$k] = $ini.Collections[$k]
}
}
return [PSCustomObject]@{
Broker = $broker
Collections = $collections
}
}
function Save-Settings {
param([string]$Broker, [hashtable]$Collections)
$ini = @{
Settings = @{ Broker = $Broker }
Collections = @{}
}
foreach ($k in ($Collections.Keys | Sort-Object)) {
$ini.Collections[$k] = $Collections[$k]
}
Write-IniFile -Path (Get-IniPath) -Ini $ini
Write-Diag "Настройки сохранены: брокер=$Broker, коллекций=$($Collections.Count)"
}
# --- Диалоги ---
function Show-InputBox {
param(
[string]$Title = "Поиск пользователя",
[string]$Prompt = "Введите Logon Name или Фамилию:"
)
$form = New-Object System.Windows.Forms.Form
$form.Text = $Title
$form.Size = New-Object System.Drawing.Size(420, 180)
$form.StartPosition = "CenterScreen"
$form.FormBorderStyle = "FixedDialog"
$form.MaximizeBox = $false
$form.MinimizeBox = $false
$label = New-Object System.Windows.Forms.Label
$label.Text = $Prompt
$label.Location = New-Object System.Drawing.Point(10, 15)
$label.Size = New-Object System.Drawing.Size(380, 20)
$form.Controls.Add($label)
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(10, 40)
$textBox.Size = New-Object System.Drawing.Size(380, 20)
$form.Controls.Add($textBox)
$btnOk = New-Object System.Windows.Forms.Button
$btnOk.Text = "ОК"
$btnOk.Location = New-Object System.Drawing.Point(100, 80)
$btnOk.Size = New-Object System.Drawing.Size(100, 30)
$btnOk.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.Controls.Add($btnOk)
$btnCancel = New-Object System.Windows.Forms.Button
$btnCancel.Text = "Отмена"
$btnCancel.Location = New-Object System.Drawing.Point(220, 80)
$btnCancel.Size = New-Object System.Drawing.Size(100, 30)
$btnCancel.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.Controls.Add($btnCancel)
$form.AcceptButton = $btnOk
$form.CancelButton = $btnCancel
$form.Topmost = $true
$result = $form.ShowDialog()
if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
return $textBox.Text.Trim()
}
return $null
}
function Show-BrokerDialog {
param(
[string]$CurrentBroker = "",
[string]$Title = "Настройка брокера",
[string]$Prompt = "Введите FQDN брокера подключений:"
)
$form = New-Object System.Windows.Forms.Form
$form.Text = $Title
$form.Size = New-Object System.Drawing.Size(440, 180)
$form.StartPosition = "CenterScreen"
$form.FormBorderStyle = "FixedDialog"
$form.MaximizeBox = $false
$form.MinimizeBox = $false
$label = New-Object System.Windows.Forms.Label
$label.Text = $Prompt
$label.Location = New-Object System.Drawing.Point(10, 15)
$label.Size = New-Object System.Drawing.Size(400, 20)
$form.Controls.Add($label)
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(10, 40)
$textBox.Size = New-Object System.Drawing.Size(400, 20)
$textBox.Text = $CurrentBroker
$form.Controls.Add($textBox)
$btnOk = New-Object System.Windows.Forms.Button
$btnOk.Text = "Сохранить"
$btnOk.Location = New-Object System.Drawing.Point(110, 80)
$btnOk.Size = New-Object System.Drawing.Size(100, 30)
$btnOk.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.Controls.Add($btnOk)
$btnCancel = New-Object System.Windows.Forms.Button
$btnCancel.Text = "Отмена"
$btnCancel.Location = New-Object System.Drawing.Point(230, 80)
$btnCancel.Size = New-Object System.Drawing.Size(100, 30)
$btnCancel.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.Controls.Add($btnCancel)
$form.AcceptButton = $btnOk
$form.CancelButton = $btnCancel
$form.Topmost = $true
$result = $form.ShowDialog()
if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
$v = $textBox.Text.Trim()
if ($v.Length -gt 0) { return $v }
}
return $null
}
function Show-UserSelection {
param([array]$Users)
$form = New-Object System.Windows.Forms.Form
$form.Text = "Выбор пользователя"
$form.Size = New-Object System.Drawing.Size(600, 400)
$form.StartPosition = "CenterScreen"
$form.FormBorderStyle = "FixedDialog"
$form.MaximizeBox = $false
$form.MinimizeBox = $false
$label = New-Object System.Windows.Forms.Label
$label.Text = "Найдено несколько пользователей. Выберите нужного:"
$label.Location = New-Object System.Drawing.Point(10, 10)
$label.Size = New-Object System.Drawing.Size(560, 20)
$form.Controls.Add($label)
$checkedListBox = New-Object System.Windows.Forms.CheckedListBox
$checkedListBox.Location = New-Object System.Drawing.Point(10, 35)
$checkedListBox.Size = New-Object System.Drawing.Size(560, 280)
$checkedListBox.CheckOnClick = $true
$checkedListBox.SelectionMode = 'One'
foreach ($u in $Users) {
$display = "$($u.Name) | $($u.SamAccountName) | $($u.DistinguishedName)"
[void]$checkedListBox.Items.Add($display)
}
$form.Controls.Add($checkedListBox)
$btnOk = New-Object System.Windows.Forms.Button
$btnOk.Text = "Выбрать"
$btnOk.Location = New-Object System.Drawing.Point(200, 325)
$btnOk.Size = New-Object System.Drawing.Size(100, 30)
$btnOk.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.Controls.Add($btnOk)
$btnCancel = New-Object System.Windows.Forms.Button
$btnCancel.Text = "Отмена"
$btnCancel.Location = New-Object System.Drawing.Point(320, 325)
$btnCancel.Size = New-Object System.Drawing.Size(100, 30)
$btnCancel.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.Controls.Add($btnCancel)
$form.AcceptButton = $btnOk
$form.CancelButton = $btnCancel
$form.Topmost = $true
$result = $form.ShowDialog()
if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
$selectedIndex = $checkedListBox.CheckedIndices | Select-Object -First 1
if ($selectedIndex -ne $null) {
return $Users[$selectedIndex]
}
}
return $null
}
# ============================================================================
# 2. СБОР ДАННЫХ
# ============================================================================
function Get-UserInfo {
param([string]$SamAccountName)
return Get-ADUser -Identity $SamAccountName -Properties `
DisplayName, LockedOut, Enabled, AccountExpirationDate, `
PasswordExpired, PasswordNeverExpires, CannotChangePassword, `
pwdLastSet, msDS-UserPasswordExpiryTimeComputed, `
Surname, GivenName, SamAccountName, DistinguishedName, SID
}
function Get-CurrentSessions {
param([string]$SamAccountName, [string]$ConnectionBroker)
return @(Get-RDUserSession -ConnectionBroker $ConnectionBroker -ErrorAction SilentlyContinue |
Where-Object { $_.UserName -like "*$SamAccountName" })
}
function Test-UserMatch {
param([string]$EventUser, [string]$SamAccountName)
if ([string]::IsNullOrWhiteSpace($EventUser)) { return $false }
$normalized = $EventUser
if ($normalized -like "*\*") { $normalized = $normalized.Split('\')[-1] }
return ($normalized -ieq $SamAccountName)
}
function Get-PreviousSessions {
param(
[string]$SamAccountName,
[string]$ConnectionBroker,
[int]$MaxEvents = 500,
[int]$DaysBack = 30
)
$results = @()
$dnsCache = @{}
$RDPAuths = @()
try {
$RDPAuths = Get-WinEvent -ComputerName $ConnectionBroker `
-LogName 'Microsoft-Windows-TerminalServices-SessionBroker/Operational' `
-FilterXPath '<QueryList><Query Id="0"><Select>*[System[EventID=801]]</Select></Query></QueryList>' `
-MaxEvents $MaxEvents -ErrorAction Stop
} catch {
Write-Diag "Не удалось прочитать журнал SessionBroker на $ConnectionBroker : $($_.Exception.Message)" "Err"
return $results
}
if (-not $RDPAuths -or $RDPAuths.Count -eq 0) {
Write-Diag "SessionBroker/801: события не найдены" "Warn"
return $results
}
Write-Diag "SessionBroker/801: получено событий с брокера — $($RDPAuths.Count)"
[xml[]]$xml = $RDPAuths | ForEach-Object { $_.ToXml() }
$EventData = foreach ($event in $xml.Event) {
New-Object PSObject -Property @{
TimeCreated = (Get-Date ($event.System.TimeCreated.SystemTime) -Format 'yyyy-MM-dd HH:mm:ss')
User = $event.UserData.EventXML.Param1
Domain = $event.UserData.EventXML.Param2
Client = $event.UserData.EventXML.Param3
}
}
$filtered = @($EventData | Where-Object { Test-UserMatch -EventUser $_.User -SamAccountName $SamAccountName })
Write-Diag "SessionBroker/801: событий для '$SamAccountName' — $($filtered.Count)"
foreach ($item in $filtered) {
$clientIP = $item.Client
$hostName = "N/A"
if ($clientIP -and $clientIP -ne "LOCAL") {
if ($dnsCache.ContainsKey($clientIP)) {
$hostName = $dnsCache[$clientIP]
} else {
try {
$hostName = [System.Net.Dns]::GetHostEntry($clientIP).HostName
$dnsCache[$clientIP] = $hostName
} catch { $hostName = "N/A" }
}
}
$results += [PSCustomObject]@{
Time = [datetime]::Parse($item.TimeCreated)
Host = $hostName
IP = if ($clientIP) { $clientIP } else { "N/A" }
}
}
return @($results | Sort-Object Time -Descending)
}
# --- Запрос коллекций и путей UPD с брокера ---
function Get-CollectionsFromBroker {
param([string]$ConnectionBroker)
$mapping = @{}
$collections = @()
try {
$collections = @(Get-RDSessionCollection -ConnectionBroker $ConnectionBroker -ErrorAction Stop)
} catch {
Write-Diag "Не удалось получить коллекции с брокера $ConnectionBroker : $($_.Exception.Message)" "Err"
return $null
}
Write-Diag "С брокера получено коллекций: $($collections.Count)"
foreach ($coll in $collections) {
$collName = $coll.CollectionName
try {
$config = Get-RDSessionCollectionConfiguration -ConnectionBroker $ConnectionBroker `
-CollectionName $collName -UserProfileDisk -ErrorAction Stop
$updPath = $null
foreach ($propName in @('DiskPath','UserProfileDiskPath','UserProfileDisk','ProfileDiskPath')) {
if ($config.PSObject.Properties[$propName]) {
$val = $config.$propName
if ($val -and $val -is [string] -and $val.Trim().Length -gt 0) {
$updPath = $val.Trim()
break
}
}
}
if ($updPath) {
$updPath = $updPath.TrimEnd('\')
$mapping[$collName] = $updPath
Write-Diag "Коллекция '$collName' -> UPD: $updPath"
} else {
Write-Diag "Коллекция '$collName' — UPD не настроен" "Warn"
}
} catch {
Write-Diag "Не удалось получить конфигурацию UPD коллекции '$collName': $($_.Exception.Message)" "Warn"
}
}
return $mapping
}
# --- Поиск дисков профиля (UPD) пользователя ---
function Get-ProfileDiskInfo {
param(
[string]$SamAccountName,
[hashtable]$CollectionUPDMapping
)
$user = Get-ADUser -Identity $SamAccountName -Properties SID
$sid = $user.SID.Value
Write-Diag "SID пользователя: $sid"
$disks = @()
if ($CollectionUPDMapping.Count -eq 0) {
Write-Diag "Нет коллекций с настроенным UPD — поиск дисков пропущен" "Warn"
return $disks
}
foreach ($collName in $CollectionUPDMapping.Keys) {
$updPath = $CollectionUPDMapping[$collName]
if (-not (Test-Path -Path $updPath -ErrorAction SilentlyContinue)) {
Write-Diag "Путь UPD недоступен: $updPath (коллекция '$collName')" "Warn"
continue
}
$fileName = "UVHD-$sid.vhdx"
$files = @(Get-ChildItem -Path $updPath -Filter $fileName -ErrorAction SilentlyContinue)
if ($files.Count -eq 0) {
$files = @(Get-ChildItem -Path $updPath -Filter "*$sid*.vhdx" -ErrorAction SilentlyContinue)
}
foreach ($file in $files) {
if ($file.Name -like "*template*") { continue }
$disks += [PSCustomObject]@{
FileName = $file.Name
Collection = $collName
SizeGB = [math]::Round($file.Length / 1GB, 2)
LastModified = $file.LastWriteTime
FullPath = $file.FullName
}
Write-Diag "Найден диск: $($file.Name) в коллекции '$collName'"
}
if ($files.Count -eq 0) {
Write-Diag "Файл '$fileName' не найден в $updPath" "Warn"
}
}
return $disks
}
# ============================================================================
# 3. ФОРМА С РЕЗУЛЬТАТАМИ
# ============================================================================
function Show-ResultsForm {
param(
[object]$UserInfo,
[array]$CurrentSessions,
[array]$PreviousSessions,
[array]$ProfileDisks,
[string]$Broker,
[string]$DomainNetBIOS
)
$script:FormBroker = $Broker
$script:FormUserInfo = $UserInfo
$script:FormDomain = $DomainNetBIOS
$script:FormResult = "Close"
$form = New-Object System.Windows.Forms.Form
$form.Text = "Информация о пользователе: $($UserInfo.DisplayName) | Брокер: $Broker"
$form.Size = New-Object System.Drawing.Size(920, 780)
$form.StartPosition = "CenterScreen"
$form.FormBorderStyle = "Sizable"
$form.MaximizeBox = $true
$script:FormWindow = $form
# --- Учётная запись ---
$groupBoxUser = New-Object System.Windows.Forms.GroupBox
$groupBoxUser.Text = "Учётная запись"
$groupBoxUser.Location = New-Object System.Drawing.Point(10, 10)
$groupBoxUser.Size = New-Object System.Drawing.Size(880, 120)
$form.Controls.Add($groupBoxUser)
$labelUser = New-Object System.Windows.Forms.Label
$labelUser.Location = New-Object System.Drawing.Point(10, 20)
$labelUser.Size = New-Object System.Drawing.Size(860, 90)
$labelUser.Font = New-Object System.Drawing.Font("Consolas", 9)
$locked = if ($UserInfo.LockedOut) { "Да" } else { "Нет" }
$disabled = if (-not $UserInfo.Enabled) { "Да" } else { "Нет" }
$pwdExpired = if ($UserInfo.PasswordExpired) { "Да" } else { "Нет" }
$accExpires = if ($UserInfo.AccountExpirationDate) { $UserInfo.AccountExpirationDate } else { "Не установлен" }
$labelUser.Text = @"
ФИО: $($UserInfo.DisplayName)
Logon Name: $($UserInfo.SamAccountName)
Заблокирована: $locked
Отключена: $disabled
Account expires: $accExpires
Требуется смена пароля: $pwdExpired
"@
$groupBoxUser.Controls.Add($labelUser)
# --- Текущие подключения ---
$groupBoxCurrent = New-Object System.Windows.Forms.GroupBox
$groupBoxCurrent.Text = "Текущие подключения к брокеру"
$groupBoxCurrent.Location = New-Object System.Drawing.Point(10, 140)
$groupBoxCurrent.Size = New-Object System.Drawing.Size(880, 150)
$form.Controls.Add($groupBoxCurrent)
$listViewCurrent = New-Object System.Windows.Forms.ListView
$listViewCurrent.Location = New-Object System.Drawing.Point(10, 20)
$listViewCurrent.Size = New-Object System.Drawing.Size(860, 95)
$listViewCurrent.View = "Details"
$listViewCurrent.FullRowSelect = $true
$listViewCurrent.GridLines = $true
$listViewCurrent.Columns.Add("Коллекция", 200) | Out-Null
$listViewCurrent.Columns.Add("Хост", 200) | Out-Null
$listViewCurrent.Columns.Add("IP-адрес", 150) | Out-Null
$listViewCurrent.Columns.Add("Session ID", 100) | Out-Null
$listViewCurrent.Columns.Add("Состояние", 100) | Out-Null
foreach ($s in $CurrentSessions) {
$item = New-Object System.Windows.Forms.ListViewItem($s.CollectionName)
$item.SubItems.Add($s.HostServer) | Out-Null
$item.SubItems.Add($s.ServerIPAddress) | Out-Null
$item.SubItems.Add($s.UnifiedSessionId) | Out-Null
$item.SubItems.Add($s.SessionState) | Out-Null
$listViewCurrent.Items.Add($item) | Out-Null
}
$groupBoxCurrent.Controls.Add($listViewCurrent)
$script:FormLvCurrent = $listViewCurrent
$btnLogoff = New-Object System.Windows.Forms.Button
$btnLogoff.Text = "Разорвать выбранную сессию"
$btnLogoff.Location = New-Object System.Drawing.Point(10, 122)
$btnLogoff.Size = New-Object System.Drawing.Size(220, 25)
$btnLogoff.Add_Click({
if ($script:FormLvCurrent.SelectedItems.Count -eq 0) {
[System.Windows.Forms.MessageBox]::Show("Выберите сессию для разрыва.", "Внимание", "OK", "Warning")
return
}
$sel = $script:FormLvCurrent.SelectedItems[0]
$collection = $sel.Text
$scriptPath = Join-Path $PSScriptRoot "Logoff-RDSUser.ps1"
if (Test-Path $scriptPath) {
$userArg = "$script:FormDomain\$($script:FormUserInfo.SamAccountName)"
& $scriptPath -BrokerName $script:FormBroker -CollectionName $collection -UserName $userArg
} else {
[System.Windows.Forms.MessageBox]::Show("Скрипт Logoff-RDSUser.ps1 не найден в папке скрипта.", "Ошибка", "OK", "Error")
}
})
$groupBoxCurrent.Controls.Add($btnLogoff)
# --- Предыдущие подключения ---
$groupBoxPrevious = New-Object System.Windows.Forms.GroupBox
$groupBoxPrevious.Text = "Предыдущие подключения (журнал брокера SessionBroker/Operational, EventID 801)"
$groupBoxPrevious.Location = New-Object System.Drawing.Point(10, 300)
$groupBoxPrevious.Size = New-Object System.Drawing.Size(880, 150)
$form.Controls.Add($groupBoxPrevious)
$listViewPrevious = New-Object System.Windows.Forms.ListView
$listViewPrevious.Location = New-Object System.Drawing.Point(10, 20)
$listViewPrevious.Size = New-Object System.Drawing.Size(860, 120)
$listViewPrevious.View = "Details"
$listViewPrevious.FullRowSelect = $true
$listViewPrevious.GridLines = $true
$listViewPrevious.Columns.Add("Время", 180) | Out-Null
$listViewPrevious.Columns.Add("Хост", 380) | Out-Null
$listViewPrevious.Columns.Add("IP-адрес", 280) | Out-Null
foreach ($p in $PreviousSessions) {
$item = New-Object System.Windows.Forms.ListViewItem($p.Time.ToString("yyyy-MM-dd HH:mm:ss"))
$item.SubItems.Add($p.Host) | Out-Null
$item.SubItems.Add($p.IP) | Out-Null
$listViewPrevious.Items.Add($item) | Out-Null
}
$groupBoxPrevious.Controls.Add($listViewPrevious)
# --- Диски профиля ---
$groupBoxDisk = New-Object System.Windows.Forms.GroupBox
$groupBoxDisk.Text = "Диски профиля пользователя (UPD)"
$groupBoxDisk.Location = New-Object System.Drawing.Point(10, 460)
$groupBoxDisk.Size = New-Object System.Drawing.Size(880, 150)
$form.Controls.Add($groupBoxDisk)
$listViewDisk = New-Object System.Windows.Forms.ListView
$listViewDisk.Location = New-Object System.Drawing.Point(10, 20)
$listViewDisk.Size = New-Object System.Drawing.Size(860, 95)
$listViewDisk.View = "Details"
$listViewDisk.FullRowSelect = $true
$listViewDisk.GridLines = $true
$listViewDisk.Columns.Add("Имя файла", 300) | Out-Null
$listViewDisk.Columns.Add("Коллекция", 200) | Out-Null
$listViewDisk.Columns.Add("Размер (GB)", 110) | Out-Null
$listViewDisk.Columns.Add("Дата изменения", 220) | Out-Null
foreach ($disk in $ProfileDisks) {
$item = New-Object System.Windows.Forms.ListViewItem($disk.FileName)
$item.SubItems.Add($disk.Collection) | Out-Null
$item.SubItems.Add($disk.SizeGB) | Out-Null
$item.SubItems.Add($disk.LastModified.ToString("yyyy-MM-dd HH:mm:ss")) | Out-Null
$listViewDisk.Items.Add($item) | Out-Null
}
$groupBoxDisk.Controls.Add($listViewDisk)
$script:FormLvDisk = $listViewDisk
$btnRemoveDisk = New-Object System.Windows.Forms.Button
$btnRemoveDisk.Text = "Удалить выбранный диск профиля"
$btnRemoveDisk.Location = New-Object System.Drawing.Point(10, 122)
$btnRemoveDisk.Size = New-Object System.Drawing.Size(240, 25)
$btnRemoveDisk.Add_Click({
if ($script:FormLvDisk.SelectedItems.Count -eq 0) {
[System.Windows.Forms.MessageBox]::Show("Выберите диск профиля для удаления.", "Внимание", "OK", "Warning")
return
}
$sel = $script:FormLvDisk.SelectedItems[0]
$collection = $sel.SubItems[1].Text
$scriptPath = Join-Path $PSScriptRoot "Remove-UPD.ps1"
if (Test-Path $scriptPath) {
$userArg = "$script:FormDomain\$($script:FormUserInfo.SamAccountName)"
& $scriptPath -ConnectionBroker $script:FormBroker -CollectionName $collection -UserName $userArg
} else {
[System.Windows.Forms.MessageBox]::Show("Скрипт Remove-UPD.ps1 не найден в папке скрипта.", "Ошибка", "OK", "Error")
}
})
$groupBoxDisk.Controls.Add($btnRemoveDisk)
# --- Нижняя панель кнопок ---
$btnEditBroker = New-Object System.Windows.Forms.Button
$btnEditBroker.Text = "Изменить брокера"
$btnEditBroker.Location = New-Object System.Drawing.Point(10, 630)
$btnEditBroker.Size = New-Object System.Drawing.Size(160, 32)
$btnEditBroker.Add_Click({
$script:FormResult = "EditBroker"
$script:FormWindow.Close()
})
$form.Controls.Add($btnEditBroker)
$btnRefresh = New-Object System.Windows.Forms.Button
$btnRefresh.Text = "Обновить"
$btnRefresh.Location = New-Object System.Drawing.Point(180, 630)
$btnRefresh.Size = New-Object System.Drawing.Size(110, 32)
$btnRefresh.Add_Click({
$script:FormResult = "Refresh"
$script:FormWindow.Close()
})
$form.Controls.Add($btnRefresh)
$btnRefreshCollections = New-Object System.Windows.Forms.Button
$btnRefreshCollections.Text = "Обновить коллекции"
$btnRefreshCollections.Location = New-Object System.Drawing.Point(300, 630)
$btnRefreshCollections.Size = New-Object System.Drawing.Size(170, 32)
$btnRefreshCollections.Add_Click({
$script:FormResult = "RefreshCollections"
$script:FormWindow.Close()
})
$form.Controls.Add($btnRefreshCollections)
$btnNewQuery = New-Object System.Windows.Forms.Button
$btnNewQuery.Text = "Новый запрос"
$btnNewQuery.Location = New-Object System.Drawing.Point(480, 630)
$btnNewQuery.Size = New-Object System.Drawing.Size(140, 32)
$btnNewQuery.Add_Click({
$script:FormResult = "NewQuery"
$script:FormWindow.Close()
})
$form.Controls.Add($btnNewQuery)
$btnClose = New-Object System.Windows.Forms.Button
$btnClose.Text = "Закрыть"
$btnClose.Location = New-Object System.Drawing.Point(760, 630)
$btnClose.Size = New-Object System.Drawing.Size(130, 32)
$btnClose.Add_Click({
$script:FormResult = "Close"
$script:FormWindow.Close()
})
$form.Controls.Add($btnClose)
$form.Topmost = $true
$form.ShowDialog() | Out-Null
return $script:FormResult
}
# ============================================================================
# 4. ОСНОВНАЯ ЛОГИКА
# ============================================================================
$settings = Read-Settings
$script:CurrentBroker = $settings.Broker
$script:Collections = $settings.Collections
# Первичная настройка брокера
if (-not $script:CurrentBroker) {
Write-Diag "Имя брокера не найдено в settings.ini — запрашиваем у пользователя"
$script:CurrentBroker = Show-BrokerDialog -CurrentBroker "rdcb.contoso.com" `
-Title "Первичная настройка" -Prompt "Введите FQDN брокера подключений:"
if (-not $script:CurrentBroker) { exit }
Save-Settings -Broker $script:CurrentBroker -Collections @{}
}
# Если коллекции в INI пусты — запрашиваем их с брокера и сохраняем
if ($script:Collections.Count -eq 0) {
Write-Diag "Коллекции не найдены в settings.ini — запрашиваем с брокера"
$fresh = Get-CollectionsFromBroker -ConnectionBroker $script:CurrentBroker
if ($null -ne $fresh) {
$script:Collections = $fresh
Save-Settings -Broker $script:CurrentBroker -Collections $script:Collections
}
} else {
Write-Diag "Загружено коллекций из settings.ini: $($script:Collections.Count)"
}
# NetBIOS-имя домена
$script:DomainNetBIOS = ""
try {
$script:DomainNetBIOS = (Get-ADDomain).NetBIOSName
} catch {
Write-Diag "Не удалось получить NetBIOS-имя домена: $($_.Exception.Message)" "Warn"
}
$action = "NewQuery"
$currentUser = $null
while ($true) {
# --- Обработка действия ---
if ($action -eq "NewQuery") {
$query = Show-InputBox
if ([string]::IsNullOrWhiteSpace($query)) { exit }
$users = @()
try {
$users = @(Get-ADUser -Filter "SamAccountName -like '$query*'" `
-Properties DisplayName, Surname, GivenName -ErrorAction SilentlyContinue)
if ($users.Count -eq 0) {
$users = @(Get-ADUser -Filter "Surname -like '$query*'" `
-Properties DisplayName, Surname, GivenName -ErrorAction SilentlyContinue)
}
} catch {
[System.Windows.Forms.MessageBox]::Show("Ошибка поиска в AD: $_", "Ошибка", "OK", "Error")
exit
}
if ($users.Count -eq 0) {
[System.Windows.Forms.MessageBox]::Show("Пользователь не найден.", "Результат", "OK", "Information")
$action = "NewQuery"
continue
}
if ($users.Count -eq 1) {
$currentUser = $users[0]
Write-Diag "Найден один пользователь — выбран автоматически: $($currentUser.SamAccountName)"
} else {
$currentUser = Show-UserSelection -Users $users
}
if ($null -eq $currentUser) {
$action = "NewQuery"
continue
}
}
elseif ($action -eq "EditBroker") {
$newBroker = Show-BrokerDialog -CurrentBroker $script:CurrentBroker `
-Title "Изменение брокера" -Prompt "Введите FQDN брокера подключений:"
if ($newBroker) {
$script:CurrentBroker = $newBroker
Write-Diag "Брокер изменён на $newBroker — обновляем список коллекций"
$fresh = Get-CollectionsFromBroker -ConnectionBroker $script:CurrentBroker
if ($null -ne $fresh) {
$script:Collections = $fresh
}
Save-Settings -Broker $script:CurrentBroker -Collections $script:Collections
}
# после смены брокера просто пересобираем данные по текущему пользователю
}
elseif ($action -eq "RefreshCollections") {
Write-Diag "Обновление списка коллекций с брокера $script:CurrentBroker"
$fresh = Get-CollectionsFromBroker -ConnectionBroker $script:CurrentBroker
if ($null -ne $fresh) {
$script:Collections = $fresh
Save-Settings -Broker $script:CurrentBroker -Collections $script:Collections
[System.Windows.Forms.MessageBox]::Show(
"Информация о коллекциях обновлена. Всего: $($fresh.Count).",
"Обновление коллекций", "OK", "Information")
} else {
[System.Windows.Forms.MessageBox]::Show(
"Не удалось получить данные о коллекциях с брокера. INI-файл оставлен без изменений.",
"Ошибка", "OK", "Error")
}
}
if ($null -eq $currentUser) { exit }
# --- Сбор данных ---
try {
$userInfo = Get-UserInfo -SamAccountName $currentUser.SamAccountName
} catch {
[System.Windows.Forms.MessageBox]::Show("Не удалось получить данные из AD: $_", "Ошибка", "OK", "Error")
$action = "NewQuery"
continue
}
$currentSessions = Get-CurrentSessions -SamAccountName $currentUser.SamAccountName -ConnectionBroker $script:CurrentBroker
$previousSessions = Get-PreviousSessions -SamAccountName $currentUser.SamAccountName -ConnectionBroker $script:CurrentBroker
# Пути UPD берём из INI ($script:Collections), без обращения к брокеру
$profileDisks = Get-ProfileDiskInfo -SamAccountName $currentUser.SamAccountName -CollectionUPDMapping $script:Collections
Write-Diag "Текущих сессий: $($currentSessions.Count); предыдущих: $($previousSessions.Count); дисков: $($profileDisks.Count)"
# --- Отображение формы ---
$action = Show-ResultsForm -UserInfo $userInfo `
-CurrentSessions $currentSessions `
-PreviousSessions $previousSessions `
-ProfileDisks $profileDisks `
-Broker $script:CurrentBroker `
-DomainNetBIOS $script:DomainNetBIOS
if ($action -eq "Close") { break }
# Для "Refresh" цикл повторится и просто пересоберёт данные того же пользователя
}