function GetDnsNameByAddress($IPv4Adress)
{
	$DnsEntry = Resolve-DnsName -Name $IPv4Adress -ErrorAction Stop;
	return $DnsEntry.NameHost;
}

function GetAddressByDnsName($DNSName)
{
	$idn = New-Object System.Globalization.IdnMapping;
	$DNSName = $idn.GetAscii($DNSName);
	$DnsEntry = Resolve-DnsName -Name $DNSName -ErrorAction Stop;
	return $DnsEntry.IP4Address;
}

function CreateDNSForwardZone($dnsServers, $domainName)
{
<#
.SYNOPSIS
Создает DNS-зону прямого просмотра с указанным именем на указанных DNS-серверах

.DESCRIPTION

.PARAMETER dnsServers 
Массив DNS-имен DNS-серверов

.PARAMETER domainName 
Имя зоны DNS

.EXAMPLE 
CreateDNSForwardZone -dnsServers "dns1.server.local","dns2.server.local" -domainName "company.local"

.NOTES
#>
	$idn = New-Object System.Globalization.IdnMapping;
	$domainName = $idn.GetAscii($domainName);
	
	# Добавляем зону прямого просмотра с указанным именем на указанные DNS-сервера
	foreach ($item in $dnsServers) {
		Write-Host ($MSG_DNS_FORWARD_ZONE_CREATING -f $item,$domainName);
		$zone = Get-DnsServerZone -ComputerName $item | Where-Object { $_.ZoneName -eq $domainName };
		if($zone -ne $null)
		{
			# throw [System.Exception]($MSG_DNS_ZONE_ALREADY_EXISTS -f $domainName,$item);
		}
		else
		{
			$NewZone = ([WMIClass]"\\$item\root\MicrosoftDNS:MicrosoftDNS_Zone").CreateZone($domainName, 0, $false, $null, $null, $null);
			Write-Host ($MSG_DNS_FORWARD_ZONE_CREATED -f $item,$domainName) -ForegroundColor Yellow;
		}
	}
}

function DeleteDNSZone($dnsServers, $domainName)
{
<#
.SYNOPSIS
Удаляет DNS-зону с указанным именем со всех указанных DNS-серверов

.DESCRIPTION

.PARAMETER dnsServers 
Массив DNS-имен DNS-серверов

.PARAMETER domainName 
Имя зоны DNS

.EXAMPLE 
DeleteDNSZone -dnsServers "dns1.server.local","dns2.server.local" -domainName "company.local"

.NOTES
#>

	$idn = New-Object System.Globalization.IdnMapping;
	$domainName = $idn.GetAscii($domainName);
# Удаляем DNS-зону с указанным именем с указанного DNS-сервера
	foreach ($item in $dnsServers) {
		Try 
		{
			Write-Host ($MSG_DNS_FORWARD_ZONE_DELETING -f $item,$domainName);
			Remove-DnsServerZone -Name $domainName -ComputerName $item -Force -ErrorAction Stop;
			Write-Host ($MSG_DNS_FORWARD_ZONE_DELETED -f $item,$domainName) -ForegroundColor Yellow;
		}
		Catch [Microsoft.Management.Infrastructure.CimException]
		{
			$category = $_.CategoryInfo.Category;
			if($category -ne [System.Management.Automation.ErrorCategory]::ObjectNotFound)
			{
				throw $_;
			}
		}
	}
}

function LockDNSZone($dnsServers, $domainName)
{
<#
.SYNOPSIS
Блокирует DNS-зону с указанным именем на всех указанных DNS-серверах

.DESCRIPTION

.PARAMETER dnsServers 
Массив DNS-имен DNS-серверов

.PARAMETER domainName 
Имя зоны DNS

.EXAMPLE 
LockDNSZone -dnsServers "dns1.server.local","dns2.server.local" -domainName "company.local"

.NOTES
#>
	$idn = New-Object System.Globalization.IdnMapping;
	$domainName = $idn.GetAscii($domainName);
# Блокируем DNS-зону с указанным именем на указанных DNS-серверах
	foreach ($item in $dnsServers) {
		Write-Host ($MSG_DNS_FORWARD_ZONE_LOCKING -f $item,$domainName);
		Suspend-DnsServerZone -Name $domainName -ComputerName $item -Force -ErrorAction Stop;
		Write-Host ($MSG_DNS_FORWARD_ZONE_LOCKED -f $item,$domainName) -ForegroundColor Yellow;
	}
}

function UnLockDNSZone($dnsServers, $domainName)
{
<#
.SYNOPSIS
Разблокирует DNS-зону с указанным именем на всех указанных DNS-серверах

.DESCRIPTION

.PARAMETER dnsServers 
Массив DNS-имен DNS-серверов

.PARAMETER domainName 
Имя зоны DNS

.EXAMPLE 
UnLockDNSZone -dnsServers "dns1.server.local","dns2.server.local" -domainName "company.local"

.NOTES
#>
	$idn = New-Object System.Globalization.IdnMapping;
	$domainName = $idn.GetAscii($domainName);
# Разблокируем DNS-зону с указанным именем на указанных DNS-серверах
	foreach ($item in $dnsServers) {
		Write-Host ($MSG_DNS_FORWARD_ZONE_UNLOCKING -f $item,$domainName);
		Resume-DnsServerZone -Name $domainName -ComputerName $item -Force -ErrorAction Stop;
		Write-Host ($MSG_DNS_FORWARD_ZONE_UNLOCKED -f $item,$domainName) -ForegroundColor Yellow;
	}
}

function AddARecordToZone($dnsServers, $computerName, $zoneName, $IPv4Address)
{
<#
.SYNOPSIS
Добавляет запись типа A в DNS-зону с указанным именем на всех указанных DNS-серверах

.DESCRIPTION

.PARAMETER dnsServers 
Массив DNS-имен DNS-серверов

.PARAMETER zoneName 
Имя зоны DNS

.PARAMETER computerName 
Имя записи типа A (Имя устройства)

.PARAMETER IPv4Address 
IP-адрес устройства

.EXAMPLE 
AddARecordToZone -dnsServers "dns1.server.local","dns2.server.local" -zoneName "company.local" -computerName "host" -IPv4Address "10.10.10.10"

.NOTES
#>
	$idn = New-Object System.Globalization.IdnMapping;
	$zoneName = $idn.GetAscii($zoneName);
	
	$computerName = $idn.GetAscii($computerName);
# Добавляем запись типа A в DNS-зону с указанным именем на указанных DNS-серверах
	foreach ($item in $dnsServers) {
		Write-Host ($MSG_DNS_RECORD_CREATING -f $item,$domainName, "A");
		Add-DnsServerResourceRecordA -Name $computerName -ZoneName $zoneName -IPv4Address $IPv4Address -ComputerName $item -ErrorAction Stop;
		Write-Host ($MSG_DNS_RECORD_CREATED -f $item,$domainName, "A") -ForegroundColor Yellow;
	}
}

function AddNSRecordToZone($dnsServers, $computerName, $zoneName)
{
<#
.SYNOPSIS
Добавляет запись типа NS в DNS-зону с указанным именем на всех указанных DNS-серверах

.DESCRIPTION

.PARAMETER dnsServers 
Массив DNS-имен DNS-серверов

.PARAMETER zoneName 
Имя зоны DNS

.PARAMETER computerName 
Имя записи типа NS (Имя устройства)

.PARAMETER IPv4Address 
IP-адрес устройства

.EXAMPLE 
AddNSRecordToZone -dnsServers "dns1.server.local","dns2.server.local" -zoneName "company.local" -computerName "host" -IPv4Address "10.10.10.10"

.NOTES
#>
	$idn = New-Object System.Globalization.IdnMapping;
	$zoneName = $idn.GetAscii($zoneName);
	$computerName = $idn.GetAscii($computerName);
# Добавляем запись типа NS в DNS-зону с указанным именем на указанных DNS-серверах
	foreach ($item in $dnsServers) {
		Write-Host ($MSG_DNS_RECORD_CREATING -f $item,$domainName, "NS");
		Add-DnsServerResourceRecord -Name $domainName -ZoneName $zoneName -NS -NameServer $computerName -ComputerName $item -ErrorAction Stop;
		Write-Host ($MSG_DNS_RECORD_CREATED -f $item,$domainName, "NS") -ForegroundColor Yellow;
	}
}

function AddMXRecordToZone($dnsServers, $zoneName, $name, $mailExchange, $priority)
{
<#
.SYNOPSIS
Добавляет запись типа MX в DNS-зону с указанным именем на всех указанных DNS-серверах

.DESCRIPTION

.PARAMETER dnsServers 
Массив DNS-имен DNS-серверов

.PARAMETER zoneName 
Имя зоны DNS

.PARAMETER name 
Родительская DNS-зона, используйте "." для текущего домена

.PARAMETER mailExchange 
DNS-имя exchange-сервера

.PARAMETER priority 
Приоритет использования почтового сервера в списке контактных серверов, значение от 0 to 65535

.EXAMPLE 
AddMXRecordToZone -dnsServers "dns1.server.local","dns2.server.local" -zoneName "company.local" -name "."  -mailExchange "mailserver.company.local" -priority 10

.NOTES
#>
if([string]::IsNullOrEmpty($name) -eq $true)
{
	$name = ".";
}
	$idn = New-Object System.Globalization.IdnMapping;
	$zoneName = $idn.GetAscii($zoneName);
	$name = $idn.GetAscii($name);
# Добавляем запись типа MX в DNS-зону с указанным именем на указанных DNS-серверах
	foreach ($item in $dnsServers) {
		Write-Host ($MSG_DNS_RECORD_CREATING -f $item,$domainName, "MX");
		Add-DnsServerResourceRecordMX -Preference $priority  -Name $name -MailExchange $mailExchange -ZoneName $zoneName -ComputerName $item -ErrorAction Stop;
		Write-Host ($MSG_DNS_RECORD_CREATED -f $item,$domainName, "MX") -ForegroundColor Yellow;
	}
}

function AddCNameRecordToZone($dnsServers, $computerName, $zoneName, $alias)
{
<#
.SYNOPSIS
Добавляет запись типа CNAME в DNS-зону с указанным именем на всех указанных DNS-серверах

.DESCRIPTION

.PARAMETER dnsServers 
Массив DNS-имен DNS-серверов

.PARAMETER zoneName 
Имя зоны DNS

.PARAMETER computerName 
Имя записи типа СName

.PARAMETER alias 
Псевдоним для записи типа A

.EXAMPLE 
AddCNameRecordToZone -dnsServers "dns1.server.local","dns2.server.local" -zoneName "company.local" -computerName "host" -alias "www"

.NOTES
#>
	$idn = New-Object System.Globalization.IdnMapping;
	$zoneName = $idn.GetAscii($zoneName);
	$alias = $idn.GetAscii($alias);
# Добавляем запись типа CNAME в DNS-зону с указанным именем на указанных DNS-серверах
	foreach ($item in $dnsServers) {
		Write-Host ($MSG_DNS_RECORD_CREATING -f $item,$domainName, "CName");
		Add-DnsServerResourceRecordCName -Name $alias -HostNameAlias $computerName -ZoneName $zoneName -ComputerName $item -ErrorAction Stop;
		Write-Host ($MSG_DNS_RECORD_CREATED -f $item,$domainName, "CName") -ForegroundColor Yellow;
	}
}

function AddTXTRecordToZone($dnsServers, $zoneName, $txt, $recordName)
{
<#
.SYNOPSIS
Добавляет запись типа TXT в DNS-зону с указанным именем на всех указанных DNS-серверах

.DESCRIPTION

.PARAMETER dnsServers 
Массив DNS-имен DNS-серверов

.PARAMETER zoneName 
Имя зоны DNS

.PARAMETER txt 
Текстовая строка

.EXAMPLE 
AddTXTRecordToZone -dnsServers "dns1.server.local","dns2.server.local" -zoneName "company.local" -txt "string data"

.NOTES
#>
	$idn = New-Object System.Globalization.IdnMapping;
	$zoneName = $idn.GetAscii($zoneName);
	$recordName = $idn.GetAscii($recordName);
# Добавляем запись типа TXT в DNS-зону с указанным именем на указанных DNS-серверах
	foreach ($item in $dnsServers) {
		Write-Host ($MSG_DNS_RECORD_CREATING -f $item,$domainName, "TXT");
		Add-DnsServerResourceRecord -Txt -DescriptiveText $txt -Name $recordName -ZoneName $zoneName -ComputerName $item -ErrorAction Stop;
		Write-Host ($MSG_DNS_RECORD_CREATED -f $item,$domainName, "TXT") -ForegroundColor Yellow;
	}
}

function DeleteRecordFromZone($dnsServers, $zoneName, $recordType, $recordName, $recordData)
{
<#
.SYNOPSIS
Удаляет запись указанного типа с DNS-зоны с указанным именем на всех указанных DNS-серверах

.DESCRIPTION

.PARAMETER dnsServers 
Массив DNS-имен DNS-серверов

.PARAMETER zoneName 
Имя зоны DNS

.PARAMETER recordType 
Тип DNS-записи

.PARAMETER recordData 
Данные DNS-записи

.EXAMPLE 
DeleteRecordFromZone -dnsServers "dns1.server.local","dns2.server.local" -zoneName "company.local" -recordType "A" -recordName "Host1" -recordData "10.17.1.41"

.NOTES
#>
# Удаляем запись указанного типа с DNS-зоны с указанным именем на указанных DNS-серверах
if([string]::IsNullOrEmpty($recordName) -eq $true)
{
	$recordName = ".";
}
	$idn = New-Object System.Globalization.IdnMapping;
	$zoneName = $idn.GetAscii($zoneName);
	foreach ($item in $dnsServers) {
		Write-Host ($MSG_DNS_RECORD_DELETING -f $item,$domainName, $recordType);
		Try
		{
			if($recordType -eq "MX")
			{
				$entry = Get-DnsServerResourceRecord -ZoneName $zoneName -ComputerName $item -RRType $recordType -Name $recordName -ErrorAction Stop | Where-Object { $_.RecordData.MailExchange -eq ($recordData + ".")  };
			}
			else
			{
				$entry = Get-DnsServerResourceRecord -ZoneName $zoneName -ComputerName $item -RRType $recordType -Name $recordName -ErrorAction Stop | Where-Object { $_.HostName -eq $recordName };
			
				switch ($recordType)
				{
					"A" { $entry = $entry | Where-Object { $_.RecordData.IPv4Address.IPAddressToString -eq $recordData } }
					"CNAME" { $entry = $entry | Where-Object { $_.RecordData.HostNameAlias -eq "$recordData." } }
					default { }
				}
			}
			if($entry -ne $null)
			{
				#$exception = New-Object InvalidOperationException ($MSG_DNS_ENTRY_NOT_FOUND_EXCEPTION -f $recordName);
				#throw $exception;
				$entry | Remove-DnsServerResourceRecord -ZoneName $zoneName -ComputerName $item -Force -ErrorAction Stop;
			}
		}
		Catch [Microsoft.Management.Infrastructure.CimException]
		{
			$category = $_.CategoryInfo.Category;
			if($category -ne [System.Management.Automation.ErrorCategory]::ObjectNotFound)
			{
				throw $_;
			}
		}
		
		Write-Host ($MSG_DNS_RECORD_DELETED -f $item,$domainName, $recordType) -ForegroundColor Yellow;
	}
}

function SyncZones($primaryDNSServer)
{
	$PrimaryDnsZones = Get-DnsServerZone -ComputerName $primaryDNSServer -ErrorAction Stop | Where { $_.ZoneType -eq "Primary" -and $_.IsReverseLookupZone -eq $false } -ErrorAction Stop;
	$SecondaryDnsZones = Get-DnsServerZone -ErrorAction Stop | Where { $_.ZoneType -eq "Secondary" -and $_.IsReverseLookupZone -eq $false } -ErrorAction Stop;
	
	$zonesToCreate = Compare-Object -ReferenceObject $PrimaryDnsZones -DifferenceObject $SecondaryDnsZones -Property ZoneName | Where { $_.SideIndicator -eq "<=" };
	$zonesToDelete = Compare-Object -ReferenceObject $SecondaryDnsZones -DifferenceObject $PrimaryDnsZones -Property ZoneName | Where { $_.SideIndicator -eq "<=" };
	
	$primaryDNSServerIP = GetAddressByDnsName -DNSName $primaryDNSServer;
	
	foreach ($zone in $zonesToCreate) {
		if($zone.ZoneName -ne "TrustAnchors")
		{
			Write-Host ($MSG_DNS_FORWARD_SECONDARY_ZONE_CREATING -f $item,$zone.ZoneName);
			Add-DnsServerSecondaryZone -Name $zone.ZoneName -ZoneFile ("{0}.dns" -f $zone.ZoneName) -MasterServers $primaryDNSServerIP -ErrorAction Stop;
			Write-Host ($MSG_DNS_FORWARD_SECONDARY_ZONE_CREATED -f $item,$zone.ZoneName) -ForegroundColor Yellow;
		}
	}
	
	foreach ($zone in $zonesToDelete) {
		Write-Host ($MSG_DNS_FORWARD_SECONDARY_ZONE_DELETING -f $item,$zone.ZoneName);
		Remove-DnsServerZone -Name $zone.ZoneName -Force -ErrorAction Stop;
		Write-Host ($MSG_DNS_FORWARD_SECONDARY_ZONE_DELETED -f $item,$zone.ZoneName) -ForegroundColor Yellow;
	}
}

function Exists($dnsServers, $domainName)
{
	$idn = New-Object System.Globalization.IdnMapping;
	$domainName = $idn.GetAscii($domainName);
	
	# Проверяем существование зоны прямого просмотра с указанным именем на указанных DNS-серверах
	foreach ($item in $dnsServers) {
		$zone = Get-DnsServerZone -ComputerName $item | Where-Object { $_.ZoneName -eq $domainName };
		if($zone -ne $null)
		{
			throw [System.Exception]($MSG_DNS_ZONE_ALREADY_EXISTS -f $domainName,$item);
		}
	}
}