Выгрузка сайтов и подсетей Active Directory через Powershell

16.09.2013

Для одного моего веб-приложения, который определяет подсеть, из которой пришел запрос и на каком доменном контроллере нужно выполнить команду, потребовалось знать структуру сайтов в домене. Для того, чтобы дать приложенияю такую информацию, я задумал регулярно выгружать сайты и подсети из Active Directory в XML-файл. Выполнить эту задачу мне помог PowerShell, а именно скрипт, который представлен ниже.

# Получение папки скрипта
$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptFolder = Split-Path $scriptpath

# Получение сайтов из Active Directory
$Sites = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Sites
$SitesX = @()
ForEach ($Site in $Sites) {
$SitesX += New-Object -Type PSObject -Property (
 @
  "SiteName"  = $site.Name
  "DomainController" = $Site.Servers[0].Name
 }
)
}

# Получение подсетей из Active Directory и сопоставление их с доменными контроллерами из таблицы сайтов
$SitesAndSubnets = @()
$Subnets = [ADSI]"LDAP://CN=Subnets,CN=Sites,CN=Configuration,DC=domain,DC=com"
ForEach ($CurrentSubnet in $Subnets.children) {
   $Network = [ADSI]"$($CurrentSubnet.Path)"
   $st = $($Network.siteobject).split(",")
   $SiteName = $st[0].Replace("CN=","")
   ForEach ($CurrentSite in $SitesX) {
     If ($CurrentSite.SiteName -eq $SiteName) {
       $DomainController = $CurrentSite.DomainController
     }
   }
   $SitesAndSubnets += New-Object -Type PSObject -Property (
     @
       "IPAddress" = $($Network.cn)
       "Site"  = $SiteName
       "DomainController" = $DomainController
       "Description" = $($Network.description)
     }
   )
}

# Удаление из таблицы строк без описаний и без доменных контроллеров
$SitesAndSubnetsFinal = @()
ForEach ($CurrentSitesAndSubnet in $SitesAndSubnets) {
   If (($CurrentSitesAndSubnet.DomainController -ne $Nothing) -and `
       ($CurrentSitesAndSubnet.Description -ne $Nothing)) {
        $SitesAndSubnetsFinal += $CurrentSitesAndSubnet
   }
}

# Сортировка таблицы по описаниям
$SitesAndSubnetsFinal = $SitesAndSubnetsFinal | Sort-Object -Property "Description"

# Сохранение таблицы в XML-файл
$OutpupFilePath = $ScriptFolder + "\NetworkStructure.xml"
$XmlWriter = New-Object System.XMl.XmlTextWriter($OutpupFilePath,$Null)
# Установка типа форматирования
$xmlWriter.Formatting = "Indented"
$xmlWriter.Indentation = "4"
# Начало XML-документа
$xmlWriter.WriteStartDocument()
# Установка XSL-стилей, если есть
# $XSLPropText = "type='text/xsl' href='style.xsl'"
# $xmlWriter.WriteProcessingInstruction("xml-stylesheet", $XSLPropText)
# Начало корневого элемента
$xmlWriter.WriteStartElement("NetworkStructure")
# Запись инфоррмационных узлов документа
$xmlWriter.WriteStartElement("Subnet")
$xmlWriter.WriteElementString("IPAddress", "0.0.0.0/0")
$xmlWriter.WriteElementString("Site", "Unknown")
$xmlWriter.WriteElementString("DomainController", "W8SRV701")
$xmlWriter.WriteElementString("Description", "Unknown")
$xmlWriter.WriteEndElement() # <-- Closing Subnets
ForEach ($CurrentSitesAndSubnetsFinal in $SitesAndSubnetsFinal) {
   $xmlWriter.WriteStartElement("Subnet")
   $xmlWriter.WriteElementString("IPAddress", $CurrentSitesAndSubnetsFinal.IPAddress)
   $xmlWriter.WriteElementString("Site", $CurrentSitesAndSubnetsFinal.Site)
   $xmlWriter.WriteElementString("DomainController", $CurrentSitesAndSubnetsFinal.DomainController)
   $xmlWriter.WriteElementString("Description", $CurrentSitesAndSubnetsFinal.Description)
   $xmlWriter.WriteEndElement() # <-- Closing Subnets
}
# Конец корневого элемента
$xmlWriter.WriteEndElement() # <-- Closing RootElement
# Конец XML-документа
$xmlWriter.WriteEndDocument()
# Закрытие XML-файла
$xmlWriter.Finalize
$xmlWriter.Flush()
$xmlWriter.Close()

Результатом работы скрипта является XML-файл, который появляется в той же папке, в которой лежит скрипт. Структура сайтов и подсетей в этом файле быглядит так:

<?xml version="1.0"?>
<NetworkStructure>
   <Subnet>    
       <IPAddress>0.0.0.0/0</IPAddress>
       <Site>Unknown</Site>
       <DomainController>W8SRV701</DomainController>
       <Description>Unknown</Description>
   </Subnet>
   <Subnet>
       <IPAddress>10.107.213.192/26</IPAddress>
       <Site>Site1</Site>
       <DomainController>W8SRV01.domain.com</DomainController>
       <Description>RU - Bataysk (Sovhoznaya str.)</Description>
   </Subnet>
</NetworkStructure>

Чтобы поставить скрипт в расписание сервера, пришлось изменить политику выполнения криптов на сервере - разрешить выполнение локальных неподписанных скриптов командой

set-executionpolicy remotesigned

Далее потребовалось написать CMD-файл для вызова PowerShell и поставить этот файл в расписание сервера, чтобы обновлять XML-файл еженедельно:

powershell.exe "%~DP0NetworkStructure.ps1"

Результатом проделанной работы является еженедельно обновляемый XML-файл NetworkStructure.xml, который используется для идентификации подсетей пользователей в веб-приложении.