function Get-DFSServers {
<#
.SYNOPSIS
Перечисляет все серверы, используемые в качестве целей в DFS-пространствах домена.
.DESCRIPTION
Функция подключается к Active Directory, находит все объекты msDFS-Namespacev2 и msDFS-Linkv2,
извлекает атрибут msDFS-TargetListv2 (XML с целевыми UNC-путями) и возвращает уникальные имена серверов.
.PARAMETER DFSRootPath
Корневой UNC-путь DFS, например \\domain.corporate.ru\ или \\domain.corporate.ru\Namespace.
.EXAMPLE
Get-DFSServers -DFSRootPath "\\mydep.corporate.ru\"
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$DFSRootPath
)
# Нормализуем путь: убираем завершающие слеши
$DFSRootPath = $DFSRootPath.TrimEnd('\')
if ($DFSRootPath -match '^\\\\') {
$DFSRootPath = $DFSRootPath.Substring(2)
}
# Извлекаем домен (первый компонент пути)
$parts = $DFSRootPath -split '\\'
$domain = $parts[0]
# Строим DN для контейнера Dfs-Configuration
$domainParts = $domain -split '\.'
$dn = ($domainParts | ForEach-Object { "DC=$_" }) -join ','
$dfsConfigDN = "CN=Dfs-Configuration,CN=System,$dn"
Write-Verbose "Подключение к AD: LDAP://$dfsConfigDN"
try {
$root = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$dfsConfigDN")
$searcher = New-Object System.DirectoryServices.DirectorySearcher($root)
# Ищем и пространства имён, и папки (ссылки)
$searcher.Filter = "(|(objectClass=msDFS-Namespacev2)(objectClass=msDFS-Linkv2))"
$searcher.PageSize = 1000
$searcher.PropertiesToLoad.Add("msDFS-TargetListv2") | Out-Null
$searcher.PropertiesToLoad.Add("name") | Out-Null
}
catch {
Write-Error "Не удалось подключиться к Active Directory. Проверьте путь и права доступа."
return
}
$servers = @{} # Хэш-таблица для уникальных имён
foreach ($result in $searcher.FindAll()) {
$targetList = $result.Properties["msdfs-targetlistv2"]
if (-not $targetList -or $targetList.Count -eq 0) { continue }
$bytes = $targetList[0]
if (-not $bytes) { continue }
# Атрибут хранится в кодировке UTF-16 LE (Unicode)
$xmlString = [System.Text.Encoding]::Unicode.GetString($bytes)
# Удаляем нулевые символы, которые могут появиться при декодировании
$xmlString = $xmlString -replace "`0", ""
try {
[xml]$xml = $xmlString
# Ищем все элементы <target> в любом пространстве имён XML
$targetNodes = $xml.SelectNodes("//target")
foreach ($node in $targetNodes) {
$unc = $node.InnerText
if ($unc -match '^\\\\([^\\]+)') {
$serverName = $matches[1]
$servers[$serverName] = $true
}
}
}
catch {
Write-Warning "Не удалось разобрать XML для объекта '$($result.Properties['name'])'"
}
}
# Возвращаем отсортированный список уникальных серверов
return $servers.Keys | Sort-Object
}