FILE: C:\Windows\System32\WindowsPowerShell\v1.0\Modules\DhcpServer\DhcpServerMigration.psm1
--
<#
DHCP Export Import Cmdlet Module
This module contains cmdlet for Export-DhcpServer & Import-DhcpServer
#>
# .ExternalHelp DhcpServerMigration.psm1-help.xml
function Export-DhcpServer
{
<#
Export-DhcpServer exports the input ScopeId/Prefix or the complete DhcpServer settings to given input file.
The xml file is created as per the DhcpServerSchema XSD (%systemdrive%\Windows\System32\WindowsPowerShell\v1.0\Modules\DhcpServer\DhcpServerSchema.xml)
Input Parameters:
File : Mandatory Parameter where Exported settings will be stored
ScopeId : v4ScopeId. If this parameter is a non-IPv4Address value, TE will be returned
If the ScopeId doesnt exist on target Dhcp Server, NTE will be returned
Prefix : v6Prefix. If this parameter is a non-IPv6Address value, TE will be returned
If the Prefix doesnt exist on target Dhcp Server, NTE will be returned
Leases : Switch parameter - if given, Leases for all the exported Scopes will also be exported
ComputerName: Hostname or IPAddress of the target Dhcp Server which need to be exported. If not given, localHost is used
CimSession : CimSession (of type Microsoft.Management.Infrastructure.CimSession) of the target Dhcp Server which need to be exported.
#>
#region Param declarations
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
Param(
[Parameter(Mandatory = $true, Position = 0)]
[string]
${File},
[Parameter(ValueFromPipelineByPropertyName = $true)]
[System.Net.IPAddress[]]
${ScopeId},
[Parameter(ValueFromPipelineByPropertyName = $true)]
[System.Net.IPAddress[]]
${Prefix},
[Parameter()]
[switch]
${Leases},
[Parameter()]
[switch]
${Force},
[Parameter()]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[Alias("Cn")]
[string]
${ComputerName},
[Parameter()]
[Alias('Session')]
[ValidateNotNullOrEmpty()]
[Microsoft.Management.Infrastructure.CimSession]
${CimSession} #TODO Need to test
)
#endregion
Begin {
try {
WriteTraceMessage "Export-DhcpServer::BEGIN Entered"
[string]$script:ExportFile = ""
[bool]$script:IsExport = $true
[bool]$script:ExportFileCreated = $false
[bool]$script:ExportFailed = $false
[int]$script:ExportSetting = $CompleteDhcpServer
[int]$script:ProcessEntryCount = 0
[string]$script:DhcpServerName = ""
$script:TargetMcVersion = $null
$script:writer = $null
WriteExportInputValue
#If ComputerName is not given, get the local computerName
#else user given ComputerName in $script:DhcpServerName variable
GetComputerName ${ComputerName}
$script:ExportFile = GetFullyQualifiedPath ${File}
if (Test-Path -LiteralPath $script:ExportFile -PathType leaf) {
if (${Force}) { #User has asked to delete the file if already present
#Dont delete the file if its ReadOnly or Hidden i.e. Dont use the 'Force' flag with 'Remote-Item'
Remove-Item -LiteralPath $script:ExportFile -ErrorAction Stop
}
else {#If input File already exists & Force is not given, throw TE
ThrowTEString ($_system_translations.ExportedFileExists -f $script:ExportFile) $EC_ResourceExists $EC_ResourceExists $script:ExportFile
}
}
WriteTraceMessage ($_system_translations.Ver_Export_Start -f $script:DhcpServerName,$script:ExportFile)
Write-Verbose ($_system_translations.Ver_Export_Start -f $script:DhcpServerName,$script:ExportFile)
}
catch {
WriteTraceMessage "Inside Export-DhcpServer BEGIN catch"
$script:ExportFailed = $true
WriteExportInputValue
throw
}
finally {
WriteTraceMessage "Inside Export-DhcpServer BEGIN finally"
WriteExportInputValue
if ($script:ExportFailed -and (NotNull $script:writer)) { $script:writer.Close(); $script:writer = $null }
}
}
Process {
$script:scopesToBeExported = @()
$script:prefixesToBeExported = @()
try
{
WriteTraceMessage "Export-DhcpServer::PROCESS Entered"
WriteExportInputValue
if (!(ValidateExportParams)) { WriteTraceMessage "Nothing to Export .. exiting"; return }
#Give the WhatIf/Confirm (ShouldProcess) message
if (!(HandleExportShouldProcess)) { WriteTraceMessage "ShouldProcess returned false .. exiting"; return }
WriteTraceMessage "ExportSetting is $script:ExportSetting [CompleteDhcpServer=0, SpecificV4AndV6Scopes=1, SpecificV4Scopes=2, SpecificV6Scopes=3"
$script:ProcessEntryCount += 1
#Create the XML if its the first call to Process function
if ($script:ProcessEntryCount -eq 1) {
#Create the XmlWriter, Xml Namespace and Version Info
PrepareExportXml $script:ExportFile
}
#Export v4 Server and v4 scopes
if ($SpecificV6Scopes -ne $script:ExportSetting) {
ExportDhcpv4Server
}
#Export v6 Server and v6 prefixes
if ($SpecificV4Scopes -ne $script:ExportSetting) {
ExportDhcpv6Server
}
WriteTraceMessage ($_system_translations.Ver_Export_End -f $script:DhcpServerName)
Write-Verbose ($_system_translations.Ver_Export_End -f $script:DhcpServerName)
}
catch {
WriteTraceMessage "Inside Export-DhcpServer PROCESS catch"
$script:ExportFailed = $true
throw
}
finally {
WriteTraceMessage "Inside Export-DhcpServer PROCESS finally"
if ($script:ExportFailed -and (NotNull $script:writer)) { $script:writer.Close(); $script:writer = $null }
}
}
End {
WriteTraceMessage "Entered Export END"
WriteExportInputValue
if (!$script:ExportFailed -and (NotNull $script:writer)) { $script:writer.Close() }
}
}
#region Export Util Functions
# Validates the input ScopeId and Prefix parameters
# Populates $script:ExportSetting, $script:scopesToBeExported and $script:prefixesToBeExported variables
# These variables are used to fill the apppropriate sections of the export file.
function ValidateExportParams()
{
$errNte = @()
$errTE = $null
#Set the level at which export need to happen
if ((IsNull ${ScopeId}) -and (IsNull ${Prefix})) {
$script:ExportSetting = $CompleteDhcpServer
} elseif ((NotNull ${ScopeId}) -and (NotNull ${Prefix})) {
$script:ExportSetting = $SpecificV4AndV6Scopes
} elseif (NotNull ${ScopeId}) {
$script:ExportSetting = $SpecificV4Scopes
} elseif (NotNull ${Prefix}) {
$script:ExportSetting = $SpecificV6Scopes
}
if (${ScopeId} -ne $null) #User has given ScopeId(s) to be to exported - If they dont exist return NTE
{
foreach ($scopeId in ${ScopeId})
{
if ($scopeId.AddressFamily -ne [System.Net.Sockets.AddressFamily]::InterNetwork) {
ThrowTEString ($_system_translations.InvalidIPv4ScopeAddress -f $scopeId) $EC_InvalidArgument $EC_InvalidArgument $scopeId
}
else {
$outObj = ExecuteCmdlet -CmdletName "Get-DhcpServerv4Scope" -MandatoryParams @{"ScopeId"=$scopeId} -Nte ([ref]$errNte)
if ($null -ne $errNte -and $errNte.Count -gt 0){
PostNteObject($errNte)
continue
}
if (NotNull $outObj) { $script:scopesToBeExported += $outObj }
}
}
}
if (${Prefix} -ne $null) #User has given Prefix(es) to be to exported - If they dont exist return NTE
{
foreach ($prefix in ${Prefix})
{
if ($prefix.AddressFamily -ne [System.Net.Sockets.AddressFamily]::InterNetworkV6) {
ThrowTEString ($_system_translations.InvalidIPv6ScopeAddress -f $prefix) $EC_InvalidArgument $EC_InvalidArgument $prefix
}
else {
$outObj = ExecuteCmdlet -CmdletName "Get-DhcpServerv6Scope" -MandatoryParams @{"Prefix"=$prefix} -Nte ([ref]$errNte)
if ($null -ne $errNte -and $errNte.count -gt 0){
PostNteObject($errNte)
continue
}
if (NotNull $outObj) { $script:prefixesToBeExported += $outObj }
}
}
}
#If Complete Server need to be Exported, get all the v4 and v6 scopes
if ($script:ExportSetting -eq $CompleteDhcpServer) {
$outObj = ExecuteCmdlet -CmdletName "Get-DhcpServerv4Scope" -Nte ([ref]$errNte) #Not catching TE here - if it happens let the Export fail
PostNteObject($errNte)
if (NotNull $outObj) { $script:scopesToBeExported += $outObj }
$outObj = ExecuteCmdlet -CmdletName "Get-DhcpServerv6Scope" -Nte ([ref]$errNte) #Not catching TE here - if it happens let the Export fail
PostNteObject($errNte)
if (NotNull $outObj) { $script:prefixesToBeExported += $outObj }
}
#Check if there is something to be exported
$needToExport = $true
if ($script:ExportSetting -eq $SpecificV4AndV6Scopes) {
if (!$script:scopesToBeExported.Count -and !$script:prefixesToBeExported.Count){ #if both v4 and v6 dont exist, need to exit w/o any export
$needToExport = $false;
}
elseif (($script:scopesToBeExported.Count -gt 0) -and !$script:prefixesToBeExported.Count) { #if only v4 exists and no v6 exists, need to export only v4 server and scope
$script:ExportSetting = $SpecificV4Scopes
}
elseif (($script:prefixesToBeExported.Count -gt 0) -and !$script:scopesToBeExported.Count) { #if only v6 exists and no v4 exists, need to export only v6 server and scope
$script:ExportSetting = $SpecificV6Scopes
}
}
elseif ($script:ExportSetting -eq $SpecificV4Scopes) {
if (!$script:scopesToBeExported.Count) {
$needToExport = $false;
}
}
elseif ($script:ExportSetting -eq $SpecificV6Scopes) {
if (!$script:prefixesToBeExported.Count) {
$needToExport = $false;
}
}
return $needToExport
}
#Handles the ShouldProcess for Export-DhcpServer
function HandleExportShouldProcess
{
if ($script:ExportSetting -eq $CompleteDhcpServer) {
if (${Leases}) { $shouldProcesMsg = ($_system_translations.Msg_Export_DhcpServer_2 -f $script:DhcpServerName, $script:ExportFile) }
else { $shouldProcesMsg = ($_system_translations.Msg_Export_DhcpServer_4 -f $script:DhcpServerName, $script:ExportFile) }
} else {
[string]$listOfScopes = ""
$firstPass = $true;
if (NotNull $script:scopesToBeExported) {
foreach ($scope in $script:scopesToBeExported) {
if (!$firstPass) { $listOfScopes += ", " + $scope.ScopeId.ToString() }
else { $listOfScopes = $scope.ScopeId.ToString(); $firstPass = $false }
}
}
if (NotNull $script:prefixesToBeExported) {
foreach ($prefix in $script:prefixesToBeExported) {
if (!$firstPass) { $listOfScopes += ", " + $prefix.Prefix.ToString() }
else { $listOfScopes += $prefix.Prefix.ToString(); $firstPass = $false }
}
}
if (${Leases}) { $shouldProcesMsg = ($_system_translations.Msg_Export_DhcpServer_1 -f $listOfScopes,$script:DhcpServerName, $script:ExportFile) }
else { $shouldProcesMsg = ($_system_translations.Msg_Export_DhcpServer_3 -f $listOfScopes,$script:DhcpServerName, $script:ExportFile) }
}
return ($PSCmdlet.ShouldProcess($shouldProcesMsg, $null, $null))
}
#Handles the ShouldProcess and ShouldContinue for Import-DhcpServer
function HandleImportShouldProcessAndShouldContinue
{
if ($script:ImportSetting -eq $CompleteDhcpServer) {
if (${Leases}) {
$shouldProcesMsg = ($_system_translations.Msg_Import_DhcpServer_2 -f $script:ImportFile,$script:DhcpServerName,"")
$shouldContinueMsg = ($_system_translations.Msg_Import_DhcpServer_2 -f $script:ImportFile,$script:DhcpServerName,$_system_translations.ShoudContinueConfirmation)
}
else {
$shouldProcesMsg = ($_system_translations.Msg_Import_DhcpServer_4 -f $script:ImportFile,$script:DhcpServerName,"")
$shouldContinueMsg = ($_system_translations.Msg_Import_DhcpServer_4 -f $script:ImportFile,$script:DhcpServerName,$_system_translations.ShoudContinueConfirmation)
}
} else {
[string]$listOfScopes = ""
$firstPass = $true;
if (NotNull $script:scopesToBeImported) {
foreach ($scope in $script:scopesToBeImported) {
if (!$firstPass) { $listOfScopes += ", " + $scope }
else { $listOfScopes = $scope; $firstPass = $false }
}
}
if (NotNull $script:prefixesToBeImported) {
foreach ($prefix in $script:prefixesToBeImported) {
if (!$firstPass) { $listOfScopes += ", " + $prefix }
else { $listOfScopes += $prefix; $firstPass = $false }
}
}
if (${Leases}) {
$shouldProcesMsg = ($_system_translations.Msg_Import_DhcpServer_1 -f $script:ImportFile,$script:DhcpServerName,$listOfScopes,"")
$shouldContinueMsg = ($_system_translations.Msg_Import_DhcpServer_1 -f $script:ImportFile,$script:DhcpServerName,$listOfScopes,$_system_translations.ShoudContinueConfirmation)
}
else {
$shouldProcesMsg = ($_system_translations.Msg_Import_DhcpServer_3 -f $script:ImportFile,$script:DhcpServerName,$listOfScopes,"")
$shouldContinueMsg = ($_system_translations.Msg_Import_DhcpServer_3 -f $script:ImportFile,$script:DhcpServerName,$listOfScopes,$_system_translations.ShoudContinueConfirmation)
}
}
$result = $PSCmdlet.ShouldProcess($shouldProcesMsg, $null, $null);
if ($result -and (!${Force})) {
$result = $PSCmdlet.ShouldContinue($shouldContinueMsg, $_system_translations.ShoudContinueCaption);
}
return $result;
}
# Creates the XmlWriter object ($script:writer)
# Initializes the Root Node and writes version information to Xml file
function PrepareExportXml([string] $file)
{
try {
InitializeXmlWriter $file
$script:writer.WriteStartElement($XmlRootNode, $DhcpSchemaName);
$outObj = ExecuteCmdlet -CmdletName Get-DhcpServerVersion
$script:writer.WriteElementString($MajorVersionElement, "", $outObj.MajorVersion);
$script:writer.WriteElementString($MinorVersionElement, "", $outObj.MinorVersion);
$script:writer.Flush()
$script:TargetMcVersion = $outObj
$script:ExportFileCreated = $true
}
catch {
WriteTraceMessage "PrepareExportXml failed"
throw
}
}
# Creates the XmlWriter object ($script:writer)
function InitializeXmlWriter([string] $file)
{
try {
WriteTraceMessage "File to be exported: $file"
$xmlSettings = new-object System.Xml.XmlWriterSettings
$xmlSettings.Indent = $true;
$xmlSettings.CheckCharacters = $false;
$script:writer = [Xml.XmlWriter]::Create($file, $xmlSettings)
}
catch {
WriteTraceMessage "InitializeXmlWriter threw exception"
throw
}
}
function GetClassHashTable($class, $mandatory, $optional, [bool]$IsV4)
{
$mandatory[$ClassPropertiesMandatory[0]] = $class.Name
$mandatory[$ClassPropertiesMandatory[1]] = $class.Type
$mandatory[$ClassPropertiesMandatory[2]] = $class.Data
if (NotNull $class.Description) { $optional[$ClassPropertiesOptional[0]] = $class.Description }
if (!($IsV4)) { $optional[$ClassPropertiesOptional[1]] = $class.VendorId }
}
function ExportDhcpClassElement($class, [bool]$IsV4)
{
$mandatory = @{}
$optional = @{}
GetClassHashTable $class $mandatory $optional $IsV4
GenericXmlWriter $mandatory $ClassPropertiesMandatory $optional $ClassPropertiesOptional
}
function ExportDhcpClasses([bool]$IsV4)
{
$errNte = $null
$errTE = $null
$classes = @()
Write-Verbose $_system_translations.Ver_Export_Classes
if ($IsV4) { $cmdlet = "Get-DhcpServerv4Class" } else { $cmdlet = "Get-DhcpServerv6Class" }
$temp = ExecuteCmdlet -CmdletName $cmdlet -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
if (NotNull $temp) { $classes += $temp }
WriteTraceMessage "Total number of classes: $($classes.Count)"
$script:writer.WriteStartElement($ClassesElement);
foreach($class in $classes){
$script:writer.WriteStartElement($ClassElement);
ExportDhcpClassElement $class $IsV4
$script:writer.WriteEndElement(); #Class node
}
$script:writer.WriteEndElement(); #Classes node
$script:writer.Flush();
}
function GetOptValueHashTable($optValue, $mandatory, $optional, [bool]$IsV4)
{
$mandatory[$OptValuePropertiesMandatory[0]] = $optValue.OptionId
if (NotNull $optValue.Value) { $optional[$OptValuePropertiesOptional[0]] = $optValue.Value }
if (NotNull $optValue.VendorClass) { $optional[$OptValuePropertiesOptional[1]] = $optValue.VendorClass }
if (NotNull $optValue.UserClass) { $optional[$OptValuePropertiesOptional[2]] = $optValue.UserClass }
}
function ExportDhcpOptValueElement($optValue, [bool]$IsV4)
{
$mandatory = @{}
$optional = @{}
GetOptValueHashTable $optValue $mandatory $optional $IsV4
GenericXmlWriter $mandatory $OptValuePropertiesMandatory $optional $OptValuePropertiesOptional
}
function ExportDhcpOptionValues ([bool]$IsV4, [string]$ScopeId=$null, [string]$ReservedIP=$null, [string]$PolicyName=$null)
{
$errNte = @()
$errTE = $null
[Array]$optValues = @()
if ($IsV4) { $scope = "ScopeId" } else { $scope = "Prefix" }
if ((IsNullOrEmptyString $ScopeId) -and (IsNullOrEmptyString $ReservedIP) -and (IsNullOrEmptyString $PolicyName)) {
Write-Verbose $_system_translations.Ver_Export_Server_OptValue;
$optionalParam = $null
}
elseif (!(IsNullOrEmptyString $ScopeId) -and (IsNullOrEmptyString $PolicyName)) {
Write-Verbose ($_system_translations.Ver_Export_Scope_OptValue -f $ScopeId);
$optionalParam = @{$scope=$ScopeId }
}
elseif (!(IsNullOrEmptyString $ScopeId) -and !(IsNullOrEmptyString $PolicyName)) {
Write-Verbose ($_system_translations.Ver_Export_Scope_Pol_OptValue -f $PolicyName,$ScopeId);
$optionalParam = @{$scope=$ScopeId; "PolicyName"=$PolicyName}
}
elseif (!(IsNullOrEmptyString $ReservedIP)) {
Write-Verbose ($_system_translations.Ver_Export_Rsvation_OptValue -f $ReservedIP);
$optionalParam = @{"ReservedIP"=$ReservedIP}
}
elseif ((IsNullOrEmptyString $ScopeId) -and !(IsNullOrEmptyString $PolicyName)) {
Write-Verbose ($_system_translations.Ver_Export_Server_Pol_OptValue -f $PolicyName);
$optionalParam = @{"PolicyName"=$PolicyName}
}
if ($IsV4) { $cmdlet = "Get-DhcpServerv4OptionValue -All -Brief" } else { $cmdlet = "Get-DhcpServerv6OptionValue -All -Brief" }
$temp = ExecuteCmdlet -CmdletName $cmdlet -OptionalParams $optionalParam -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
if (NotNull $temp) { $optValues += $temp; $optValues = $optValues | sort -Property OptionId,UserClass }
WriteTraceMessage "Total number of OptValues: $($optValues.Count)"
if ($optValues.Count -gt 0) {
$script:writer.WriteStartElement($OptValuesElement);
foreach($optValue in $optValues){
$script:writer.WriteStartElement($OptValueElement);
ExportDhcpOptValueElement $optValue $IsV4
$script:writer.WriteEndElement(); #OptionValue End node
}
$script:writer.WriteEndElement(); #OptionValues End node
$script:writer.Flush();
}
}
function ExportDhcpv6StatelessStore([string]$Prefix="")
{
$errNte = @()
$errTE = $null
[HashTable]$optionalParam = $null
if (IsNullOrEmptyString $Prefix) { $optionalParam = $null }
elseif (!(IsNullOrEmptyString $Prefix)) { $optionalParam = @{"Prefix"=$Prefix } }
$stateLessStore = ExecuteCmdlet -CmdletName Get-DhcpServerv6StatelessStore -OptionalParams $optionalParam -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
if (NotNull $stateLessStore) {
$script:writer.WriteStartElement($StatelessElement);
$script:writer.WriteElementString($StatelessEnabledElement, $stateLessStore.Enabled.ToString().ToLower());
$script:writer.WriteElementString($StatelessPurgeIntervalElement, $stateLessStore.PurgeInterval.ToString());
$script:writer.WriteEndElement(); #Stateless element End node
$script:writer.Flush();
}
}
function ExportIPRanges($IPRanges, $StartElement)
{
if ($IPRanges.Count -gt 0) {
$script:writer.WriteStartElement($StartElement);
foreach ($ipRange in $IPRanges) {
$script:writer.WriteStartElement($IPRangeElement);
$script:writer.WriteElementString($StartIPRangeElement, $ipRange.StartRange);
$script:writer.WriteElementString($EndIPRangeElement, $ipRange.EndRange);
$script:writer.WriteEndElement(); #IPRange End node
}
$script:writer.WriteEndElement(); #IPRanges End node
}
}
function GetPolicyHashTable($Policy, [HashTable]$mandatory, [HashTable]$optional)
{
$mandatory[$PolicyPropertiesMandatory[0]] = $Policy.Name
$mandatory[$PolicyPropertiesMandatory[1]] = $Policy.ProcessingOrder
$mandatory[$PolicyPropertiesMandatory[2]] = $Policy.Enabled.ToString().ToLower()
$mandatory[$PolicyPropertiesMandatory[3]] = $Policy.Condition
if (NotNull $Policy.Description) { $optional[$PolicyPropertiesOptional[0]] = $Policy.Description }
if (NotNull $Policy.VendorClass) { $optional[$PolicyPropertiesOptional[1]] = $Policy.VendorClass }
if (NotNull $Policy.UserClass) { $optional[$PolicyPropertiesOptional[2]] = $Policy.UserClass }
if (NotNull $Policy.MacAddress) { $optional[$PolicyPropertiesOptional[3]] = $Policy.MacAddress }
if (NotNull $Policy.ClientId) { $optional[$PolicyPropertiesOptional[4]] = $Policy.ClientId }
if (NotNull $Policy.RelayAgent) { $optional[$PolicyPropertiesOptional[5]] = $Policy.RelayAgent }
if (NotNull $Policy.CircuitId) { $optional[$PolicyPropertiesOptional[6]] = $Policy.CircuitId }
if (NotNull $Policy.RemoteId) { $optional[$PolicyPropertiesOptional[7]] = $Policy.RemoteId }
if (NotNull $Policy.SubscriberId) { $optional[$PolicyPropertiesOptional[8]] = $Policy.SubscriberId }
if (NotNull $Policy.Fqdn) { $optional[$PolicyPropertiesOptional[9]] = $Policy.Fqdn }
}
function ExportDhcpPolicyElement($Policy)
{
[HashTable]$mandatory = @{}
[HashTable]$optional = @{}
$policyIPRanges = @()
$errTE = $null; $errNte = @()
if ($Policy.ScopeId.ToString() -ne "0.0.0.0") {
$policyScopeId = $Policy.ScopeId.ToString()
$optionalParam = @{"ScopeId" = $Policy.ScopeId }
} else {
$policyScopeId = ""
$optionalParam = $null
}
GetPolicyHashTable $Policy $mandatory $optional
$temp = ExecuteCmdlet -CmdletName "Get-DhcpServerV4DnsSetting -PolicyName `"$($Policy.Name)`"" -OptionalParams $optionalParam -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
if (NotNull $temp.DnsSuffix) { $optional[$PolicyPropertiesOptional[10]] = $temp.DnsSuffix }
GenericXmlWriter $mandatory $PolicyPropertiesMandatory $optional $PolicyPropertiesOptional
#Export Policy IPRange if its at scope level
if (!(IsNullOrEmptyString $policyScopeId)) {
$temp = ExecuteCmdlet -CmdletName "Get-DhcpServerv4PolicyIPRange -Name `"$($Policy.Name)`" -ScopeId $($Policy.ScopeId)" -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject($errTE); PostNteObject($errNte)
if (NotNull $temp) { $policyIPRanges += $temp }
ExportIPRanges $policyIPRanges $IPRangesElement
}
ExportDhcpOptionValues $true $policyScopeId "" $Policy.Name
}
function ExportDhcpv4Policies([string]$ScopeId="")
{
$errNte = $null
$errTE = $null
[Array]$policies = @()
[string]$verboseExportMessage = ""
[HashTable]$optionalParam = $null
if (IsNullOrEmptyString $ScopeId) { $verboseExportMessage = $_system_translations.Ver_Export_Server_Policy; $optionalParam = $null }
elseif (!(IsNullOrEmptyString $ScopeId)) { $verboseExportMessage = ($_system_translations.Ver_Export_Scope_Policy -f $ScopeId); $optionalParam = @{"ScopeId" = $ScopeId } }
WriteTraceMessage $verboseExportMessage
Write-Verbose $verboseExportMessage
$temp = ExecuteCmdlet -CmdletName Get-DhcpServerv4Policy -OptionalParams $optionalParam -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
if (NotNull $temp) { $policies += $temp; $policies = $policies | sort -Property ProcessingOrder }
WriteTraceMessage "Total number of Policies: $($policies.Count)"
if ($policies.Count -gt 0) {
$script:writer.WriteStartElement($PoliciesElement);
foreach($policy in $policies){
$script:writer.WriteStartElement($PolicyElement);
ExportDhcpPolicyElement $policy
$script:writer.WriteEndElement(); #Policy End node
}
$script:writer.WriteEndElement(); #Policies End node
$script:writer.Flush();
}
}
function GetReservationHashTable([bool]$IsV4, $Reservation, [HashTable]$mandatory, [HashTable]$optional)
{
$mandatory[$ReservationPropertiesMandatory[0]] = $Reservation.Name
$mandatory[$ReservationPropertiesMandatory[1]] = $Reservation.IPAddress
if ($IsV4) {
$optional[$ReservationPropertiesOptional[0]] = $Reservation.ClientId
$optional[$ReservationPropertiesOptional[1]] = $Reservation.Type
}
else {
$optional[$ReservationPropertiesOptional[2]] = $Reservation.ClientDuid
$optional[$ReservationPropertiesOptional[3]] = $Reservation.IAID
}
if (NotNull $Reservation.Description) { $optional[$ReservationPropertiesOptional[4]] = $Reservation.Description }
}
function ExportDhcpReservationElement([bool]$IsV4, $Reservation)
{
[HashTable]$mandatory = @{}
[HashTable]$optional = @{}
$errTE = $null; $errNte = @()
GetReservationHashTable $IsV4 $Reservation $mandatory $optional
GenericXmlWriter $mandatory $ReservationPropertiesMandatory $optional $ReservationPropertiesOptional
#Export Reservation level option values
ExportDhcpOptionValues $IsV4 "" $Reservation.IPAddress.ToString()
}
function ExportDhcpReservations([bool] $IsV4, [string] $ScopeId)
{
$errNte = $null
$errTE = $null
[Array]$reservations = @()
WriteTraceMessage ($_system_translations.Ver_Export_Scope_Rsvation -f $ScopeId)
Write-Verbose ($_system_translations.Ver_Export_Scope_Rsvation -f $ScopeId)
if ($IsV4) { $cmdlet = "Get-DhcpServerv4Reservation -ScopeId $ScopeId" }
else { $cmdlet = "Get-DhcpServerv6Reservation -Prefix $ScopeId" }
$temp = ExecuteCmdlet -CmdletName $cmdlet -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
if (NotNull $temp) { $reservations += $temp }
WriteTraceMessage "Total number of Reservations: $($reservations.Count)"
if ($reservations.Count -gt 0) {
$script:writer.WriteStartElement($ReservationsElement);
foreach($reservation in $reservations){
$script:writer.WriteStartElement($ReservationElement);
ExportDhcpReservationElement $IsV4 $reservation
$script:writer.WriteEndElement(); #Reservation End node
}
$script:writer.WriteEndElement(); #Reservations End node
$script:writer.Flush();
}
}
function GetLeaseHashTable($Lease, [HashTable]$mandatory, [HashTable]$optional)
{
$mandatory[$LeasePropertiesMandatory[0]] = $Lease.IPAddress
$mandatory[$LeasePropertiesMandatory[1]] = $Lease.ScopeId
$mandatory[$LeasePropertiesMandatory[2]] = $Lease.ClientId
$mandatory[$LeasePropertiesMandatory[3]] = $Lease.AddressState
$mandatory[$LeasePropertiesMandatory[4]] = $Lease.ClientType
$mandatory[$LeasePropertiesMandatory[5]] = $Lease.NapCapable.ToString().ToLower()
if (NotNull $Lease.DnsRR) { $optional[$LeasePropertiesOptional[0]] = $Lease.DnsRR }
if (NotNull $Lease.DnsRegistration) { $optional[$LeasePropertiesOptional[1]] = $Lease.DnsRegistration }
if (NotNull $Lease.LeaseExpiryTime) { $optional[$LeasePropertiesOptional[2]] = $Lease.LeaseExpiryTime.ToUniversalTime().ToString("u") } #'u' format uses InvariantCulture and represents a UTC based time
if (NotNull $Lease.ProbationEnds) { $optional[$LeasePropertiesOptional[3]] = $Lease.ProbationEnds.ToUniversalTime().ToString("u") }
if (NotNull $Lease.NapStatus) { $optional[$LeasePropertiesOptional[4]] = $Lease.NapStatus }
if (NotNull $Lease.HostName) { $optional[$LeasePropertiesOptional[5]] = $Lease.HostName }
if (NotNull $Lease.PolicyName) { $optional[$LeasePropertiesOptional[6]] = $Lease.PolicyName }
if (NotNull $Lease.Description) { $optional[$LeasePropertiesOptional[7]] = $Lease.Description }
}
function ExportDhcpv4LeaseElement()
{
process {
$script:writer.WriteStartElement($LeaseElement);
[HashTable]$mandatory = @{}
[HashTable]$optional = @{}
GetLeaseHashTable $_ $mandatory $optional
GenericXmlWriter $mandatory $LeasePropertiesMandatory $optional $LeasePropertiesOptional
$script:writer.WriteEndElement(); #Lease End node
}
}
function ExportDhcpv4Leases([string] $ScopeId)
{
$errNte = $null
$errTE = $null
WriteTraceMessage ($_system_translations.Ver_Export_Scope_Lease -f $ScopeId)
Write-Verbose ($_system_translations.Ver_Export_Scope_Lease -f $ScopeId)
$script:writer.WriteStartElement($LeasesElement);
$cmdlet = ExecuteCmdlet -CmdletName "Get-DhcpServerv4Lease -ScopeId $ScopeId -AllLeases" -Nte ([ref]$errNte) -TE ([ref]$errTE) -DontRun
$pipelineCmdlet = "$cmdlet | ExportDhcpv4LeaseElement"
WriteTraceMessage "Running Cmdlet: $pipelineCmdlet"
try { Invoke-Expression $pipelineCmdlet}
catch { PostNteObject $_ }
$script:writer.WriteEndElement(); #Leases End node
$script:writer.Flush();
}
function Getv4ScopeHashTable($scopeToExport, [HashTable]$mandatory, [HashTable]$optional)
{
$mandatory[$Scopev4PropertiesMandatory[0]] = $scopeToExport.ScopeId
$mandatory[$Scopev4PropertiesMandatory[1]] = $scopeToExport.Name
$mandatory[$Scopev4PropertiesMandatory[2]] = $scopeToExport.SubnetMask
$mandatory[$Scopev4PropertiesMandatory[3]] = $scopeToExport.StartRange
$mandatory[$Scopev4PropertiesMandatory[4]] = $scopeToExport.EndRange
$mandatory[$Scopev4PropertiesMandatory[5]] = $scopeToExport.LeaseDuration.ToString()
$mandatory[$Scopev4PropertiesMandatory[6]] = $scopeToExport.State
$mandatory[$Scopev4PropertiesMandatory[7]] = $scopeToExport.Type
$mandatory[$Scopev4PropertiesMandatory[8]] = $scopeToExport.MaxBootpClients
$mandatory[$Scopev4PropertiesMandatory[9]] = $scopeToExport.NapEnable.ToString().ToLower()
if (NotNull $scopeToExport.Delay) { $optional[$Scopev4PropertiesOptional[0]] = $scopeToExport.Delay }
if (NotNull $scopeToExport.NapProfile) { $optional[$Scopev4PropertiesOptional[1]] = $scopeToExport.NapProfile }
if (NotNull $scopeToExport.Description) { $optional[$Scopev4PropertiesOptional[2]] = $scopeToExport.Description }
if (NotNull $scopeToExport.ActivatePolicies) { $optional[$Scopev4PropertiesOptional[3]] = $scopeToExport.ActivatePolicies.ToString().ToLower() }
if (NotNull $scopeToExport.SuperScopeName) { $optional[$Scopev4PropertiesOptional[4]] = $scopeToExport.SuperScopeName }
}
function ExportDhcpv4Scope($scopeToExport)
{
[HashTable]$mandatory = @{}
[HashTable]$optional = @{}
$errNte = @()
$errTE = $null
$exIPRanges = @()
Getv4ScopeHashTable $scopeToExport $mandatory $optional
GenericXmlWriter $mandatory $Scopev4PropertiesMandatory $optional $Scopev4PropertiesOptional
#Export Scope IPRange
$temp = ExecuteCmdlet -CmdletName "Get-DhcpServerv4ExclusionRange -ScopeId $($scopeToExport.ScopeId)" -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject($errTE); PostNteObject($errNte)
if (NotNull $temp) { $exIPRanges += $temp }
if ($exIPRanges.Count -gt 0) { Write-Verbose ($_system_translations.Ver_Export_Scope_ExRanges -f $($scopeToExport.ScopeId.ToString())) }
ExportIPRanges $exIPRanges $ExclusionRangesElement
if (IsWindows8OrHigher($script:TargetMcVersion)) {
#Export v4Scope Policies
ExportDhcpv4Policies $scopeToExport.ScopeId.ToString()
}
#Export v4Scope OptionValues
ExportDhcpOptionValues $true $scopeToExport.ScopeId.ToString()
#Export v4Scope Reservation
ExportDhcpReservations $true $scopeToExport.ScopeId.ToString()
#Export v4Scope Leases if Lease switch paramter is given
if (${Leases}) {
ExportDhcpv4Leases $scopeToExport.ScopeId.ToString()
}
}
function ExportDhcpv4Scopes()
{
$errNte = $null
$errTE = $null
[Array]$policies = @()
WriteTraceMessage "Started exporting v4Scopes"
if ($script:ProcessEntryCount -eq 1) { #Write Scopes Start Node only when the Process function is called for the first time
$script:writer.WriteStartElement($ScopesElement); #Scopes Start Element
}
foreach ($scopeToExport in $script:scopesToBeExported) {
WriteTraceMessage ($_system_translations.Ver_Export_Scope -f $scopeToExport.ScopeId.ToString(),$script:DhcpServerName)
Write-Verbose ($_system_translations.Ver_Export_Scope -f $scopeToExport.ScopeId.ToString(), $script:DhcpServerName)
$script:writer.WriteStartElement($ScopeElement); #Scope Start node
ExportDhcpv4Scope $scopeToExport
$script:writer.WriteEndElement(); #Scope End node
$script:writer.Flush();
}
if (($script:ExportSetting -eq $CompleteDhcpServer) -or ($script:ExportSetting -eq $SpecificV4AndV6Scopes)) {
$script:writer.WriteEndElement(); #Scopes End node
}
}
function GetFilterHashTable($Filter, [HashTable]$mandatory, [HashTable]$optional)
{
$mandatory[$FilterPropertiesMandatory[0]] = $Filter.List
$mandatory[$FilterPropertiesMandatory[1]] = $Filter.MacAddress
if (NotNull $Filter.Description) { $optional[$FilterPropertiesOptional[0]] = $Filter.Description }
}
function ExportDhcpFilterElement($Filter)
{
[HashTable]$mandatory = @{}
[HashTable]$optional = @{}
GetFilterHashTable $Filter $mandatory $optional
GenericXmlWriter $mandatory $FilterPropertiesMandatory $optional $FilterPropertiesOptional
}
function ExportDhcpv4Filters()
{
$errNte = @()
$errTE = $null
$filters = @()
WriteTraceMessage $_system_translations.Ver_Export_Server_Filter
Write-Verbose $_system_translations.Ver_Export_Server_Filter
$filterList = ExecuteCmdlet -CmdletName Get-DhcpServerv4FilterList -Nte ([ref]$errNte) -TE ([ref]$errTE)
if (NotNull $errTE) { $allow = $false; $deny = $false } else { $allow = $filterList.Allow; $deny = $filterList.Deny }
PostNteObject $errTE; PostNteObject $errNte
$script:writer.WriteStartElement($FiltersElement);
$script:writer.WriteElementString($FilterListAllowElement, $allow.ToString().ToLower());
$script:writer.WriteElementString($FilterListDenyElement, $deny.ToString().ToLower());
$temp = ExecuteCmdlet -CmdletName Get-DhcpServerv4Filter -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
if (NotNull $temp) { $filters += $temp}
if ($filters.Count -gt 0) {
foreach($filter in $filters){
$script:writer.WriteStartElement($FilterElement);
ExportDhcpFilterElement $filter
$script:writer.WriteEndElement(); #Filter End node
}
}
$script:writer.WriteEndElement(); #Filters End node
$script:writer.Flush();
}
function GetOptDefHashTable($optDef, $mandatory, $optional)
{
$mandatory[$OptDefPropertiesMandatory[0]] = $optDef.Name
$mandatory[$OptDefPropertiesMandatory[1]] = $optDef.OptionId
$mandatory[$OptDefPropertiesMandatory[2]] = $optDef.Type
$mandatory[$OptDefPropertiesMandatory[3]] = $optDef.MultiValued.ToString().ToLower()
if ((NotNull $optDef.DefaultValue) -and $optDef.DefaultValue.Count -gt 0) { $optional[$OptDefPropertiesOptional[0]] = $optDef.DefaultValue }
if (NotNull $optDef.Description) { $optional[$OptDefPropertiesOptional[1]] = $optDef.Description }
if (NotNull $optDef.VendorClass) { $optional[$OptDefPropertiesOptional[2]] = $optDef.VendorClass }
}
function ExportDhcpOptDefElement($optDef)
{
$mandatory = @{}
$optional = @{}
GetOptDefHashTable $optDef $mandatory $optional
GenericXmlWriter $mandatory $OptDefPropertiesMandatory $optional $OptDefPropertiesOptional
}
function GetAllOptionDefinitions([bool] $IsV4)
{
$errNte = @(); $errTE = $null
[Array]$allOptDefs = @()
if ($IsV4) { $cmdlet = "Get-DhcpServerv4OptionDefinition -All" } else { $cmdlet = "Get-DhcpServerv6OptionDefinition -All" }
$temp = ExecuteCmdlet -CmdletName $cmdlet -Nte ([ref]$errNte) -Te ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
if (NotNull $temp) { $allOptDefs += $temp }
return $allOptDefs
}
function ExportDhcpOptionDefinitions([bool]$IsV4)
{
$errNte = $null
$errTE = $null
[Array]$optDefs = @()
Write-Verbose $_system_translations.Ver_Export_OptDef
$optDefs = GetAllOptionDefinitions $IsV4
if ((NotNull $optDefs) -and ($optDefs.Count -gt 0)) {
WriteTraceMessage "Total number of OptDefinition: $($optDefs.Count)"
$script:writer.WriteStartElement($OptDefsElement);
foreach($optDef in $optDefs){
$script:writer.WriteStartElement($OptDefElement);
ExportDhcpOptDefElement $optDef
$script:writer.WriteEndElement(); #OptDef node
}
$script:writer.WriteEndElement(); #OptDefs node
$script:writer.Flush();
}
}
function ExportDhcpServerv4Setting()
{
#Dhcpv4 Server Settings
$outObj = ExecuteCmdlet -CmdletName Get-DhcpServerSetting
$script:writer.WriteElementString($ConflictDetAttemptsElement, $outObj.ConflictDetectionAttempts.ToString());
$script:writer.WriteElementString($NapEnabledElement, $outObj.NapEnabled.ToString().ToLower()); #ToString converts into 'True' while xsd:boolean takes 'true'
$script:writer.WriteElementString($NpsUnreachableActionElement, $outObj.NpsUnreachableAction.ToString());
if (NotNull $outObj.ActivatePolicies) {
$script:writer.WriteElementString($ActivatePoliciesElement, $outObj.ActivatePolicies.ToString().ToLower());
}
}
#Exports the DHCPv4 Server
function ExportDhcpv4Server()
{
if ($script:ProcessEntryCount -eq 1) { #Write Server level entries only when the Process function is called for the first time
#Write IPv4 Start element
$script:writer.WriteStartElement($IPv4Element, "");
#Write v4ServerSettings
ExportDhcpServerv4Setting
#Dhcpv4 Server Classes
ExportDhcpClasses $true
#Dhcpv4 Server OptionDefinition
ExportDhcpOptionDefinitions $true
if (IsWindows8OrHigher($script:TargetMcVersion)) {
#Dhcpv4 Server Policies (only available for Windows8 and above)
ExportDhcpv4Policies
}
#Dhcpv4 Server OptionValue
ExportDhcpOptionValues $true "" "" ""
if (IsWindows2008R2OrHigher($script:TargetMcVersion)) {
#Dhcpv4 Server Filters (only available for Windows2K8-R2 and above)
ExportDhcpv4Filters
}
}
#Dhcpv4 Server Scopes
if ((NotNull $script:scopesToBeExported) -and ($script:scopesToBeExported.Count -gt 0)) {
ExportDhcpv4Scopes
}
if (($script:ExportSetting -eq $CompleteDhcpServer) -or ($script:ExportSetting -eq $SpecificV4AndV6Scopes)) {
$script:writer.WriteEndElement(); #IPv4 End node
}
$script:writer.Flush()
}
function Getv6LeaseHashTable($Lease, [HashTable]$mandatory, [HashTable]$optional)
{
$mandatory[$Leasev6PropertiesMandatory[0]] = $Lease.IPAddress
$mandatory[$Leasev6PropertiesMandatory[1]] = $Lease.ClientDuid
$mandatory[$Leasev6PropertiesMandatory[2]] = $Lease.IAID
$mandatory[$Leasev6PropertiesMandatory[3]] = $Lease.AddressType
if (NotNull $Lease.HostName) { $optional[$Leasev6PropertiesOptional[0]] = $Lease.HostName }
if (NotNull $Lease.LeaseExpiryTime) { $optional[$Leasev6PropertiesOptional[1]] = $Lease.LeaseExpiryTime.ToUniversalTime().ToString("u") } #'u' format uses InvariantCulture and represents a UTC based time
if (NotNull $Lease.Description) { $optional[$Leasev6PropertiesOptional[2]] = $Lease.Description }
}
function ExportDhcpv6LeaseElement()
{
process {
$script:writer.WriteStartElement($LeaseElement);
[HashTable]$mandatory = @{}
[HashTable]$optional = @{}
Getv6LeaseHashTable $_ $mandatory $optional
GenericXmlWriter $mandatory $Leasev6PropertiesMandatory $optional $Leasev6PropertiesOptional
$script:writer.WriteEndElement(); #Lease End node
}
}
function ExportDhcpv6Leases([string] $Prefix)
{
$errNte = $null
$errTE = $null
WriteTraceMessage ($_system_translations.Ver_Export_Scope_Lease -f $Prefix)
Write-Verbose ($_system_translations.Ver_Export_Scope_Lease -f $Prefix)
$script:writer.WriteStartElement($LeasesElement);
$cmdlet = ExecuteCmdlet -CmdletName "Get-DhcpServerv6Lease -Prefix $Prefix" -Nte ([ref]$errNte) -TE ([ref]$errTE) -DontRun
$pipelineCmdlet = "$cmdlet | ExportDhcpv6LeaseElement"
WriteTraceMessage "Running Cmdlet: $pipelineCmdlet"
try { Invoke-Expression $pipelineCmdlet}
catch { PostNteObject $_ }
$script:writer.WriteEndElement(); #Leases End node
$script:writer.Flush();
}
function Getv6ScopeHashTable($prefixToExport, [HashTable]$mandatory, [HashTable]$optional)
{
$mandatory[$Scopev6PropertiesMandatory[0]] = $prefixToExport.Prefix
$mandatory[$Scopev6PropertiesMandatory[1]] = $prefixToExport.Name
$mandatory[$Scopev6PropertiesMandatory[2]] = $prefixToExport.Preference
$mandatory[$Scopev6PropertiesMandatory[3]] = $prefixToExport.State
if (NotNull $prefixToExport.PreferredLifeTime) { $optional[$Scopev6PropertiesOptional[0]] = $prefixToExport.PreferredLifeTime.ToString() } #'u' format uses InvariantCulture and represents a UTC based time }
if (NotNull $prefixToExport.ValidLifeTime) { $optional[$Scopev6PropertiesOptional[1]] = $prefixToExport.ValidLifeTime.ToString() }
if (NotNull $prefixToExport.T1) { $optional[$Scopev6PropertiesOptional[2]] = $prefixToExport.T1.ToString() }
if (NotNull $prefixToExport.T2) { $optional[$Scopev6PropertiesOptional[3]] = $prefixToExport.T2.ToString() }
if (NotNull $prefixToExport.Description) { $optional[$Scopev6PropertiesOptional[4]] = $prefixToExport.Description }
}
function ExportDhcpv6Scope($prefixToExport)
{
[HashTable]$mandatory = @{}
[HashTable]$optional = @{}
$errNte = @()
$errTE = $null
$exIPRanges = @()
#Export v6Scope properties
Getv6ScopeHashTable $prefixToExport $mandatory $optional
GenericXmlWriter $mandatory $Scopev6PropertiesMandatory $optional $Scopev6PropertiesOptional
#Export Scope ExRange
$temp = ExecuteCmdlet -CmdletName "Get-DhcpServerv6ExclusionRange -Prefix $($prefixToExport.Prefix)" -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject($errTE); PostNteObject($errNte)
if (NotNull $temp) { $exIPRanges += $temp }
if ($exIPRanges.Count -gt 0) { Write-Verbose ($_system_translations.Ver_Export_Scope_ExRanges -f $($prefixToExport.Prefix.ToString())) }
ExportIPRanges $exIPRanges $ExclusionRangesElement
#Export v6Scope OptionValues
ExportDhcpOptionValues $false $prefixToExport.Prefix.ToString()
#Export v6Scope Reservation
ExportDhcpReservations $false $prefixToExport.Prefix.ToString()
if (IsWindows8OrHigher($script:TargetMcVersion)) {
#Dhcpv6 Stateless Store
ExportDhcpv6StatelessStore $prefixToExport.Prefix.ToString()
}
#Export v6Scope Leases if Lease switch paramter is given
if (${Leases}) {
ExportDhcpv6Leases $prefixToExport.Prefix.ToString()
}
}
function ExportDhcpv6Scopes()
{
$errNte = $null
$errTE = $null
WriteTraceMessage "Started exporting v6Scopes"
if ($script:ProcessEntryCount -eq 1) { #Write Scopes Start Node only when the Process function is called for the first time
$script:writer.WriteStartElement($ScopesElement); #Scopes Start Element
}
foreach ($prefixToExport in $script:prefixesToBeExported) {
WriteTraceMessage ($_system_translations.Ver_Export_Scope -f $prefixToExport.Prefix.ToString(),$script:DhcpServerName)
Write-Verbose ($_system_translations.Ver_Export_Scope -f $prefixToExport.Prefix.ToString(), $script:DhcpServerName)
$script:writer.WriteStartElement($ScopeElement); #Scope Start node
ExportDhcpv6Scope $prefixToExport
$script:writer.WriteEndElement(); #Scope End node
$script:writer.Flush();
}
if (($script:ExportSetting -eq $CompleteDhcpServer) -or ($script:ExportSetting -eq $SpecificV4AndV6Scopes)) {
$script:writer.WriteEndElement(); #Scopes End node
}
}
function ExportDhcpv6Server()
{
if ($script:ProcessEntryCount -eq 1) { #Write Server level node only when the Process function is called for the first time
$script:writer.WriteStartElement($IPv6Element, "");
#Dhcpv6 Server Classes
ExportDhcpClasses $false
#Dhcpv6 Server OptionDefinition
ExportDhcpOptionDefinitions $false
#Dhcpv6 Server OptionValue
ExportDhcpOptionValues $false "" "" ""
if (IsWindows8OrHigher($script:TargetMcVersion)) {
#Dhcpv6 Stateless Store
ExportDhcpv6StatelessStore
}
}
#Dhcpv6 Server Scopes
if ((NotNull $script:prefixesToBeExported) -and ($script:prefixesToBeExported.Count -gt 0)) {
ExportDhcpv6Scopes
}
if (($script:ExportSetting -eq $CompleteDhcpServer) -or ($script:ExportSetting -eq $SpecificV4AndV6Scopes)) {
$script:writer.WriteEndElement(); #IPv6 End node
}
$script:writer.Flush()
}
#endregion
# .ExternalHelp DhcpServerMigration.psm1-help.xml
function Import-DhcpServer
{
<#
Import-DhcpServer imports the input ScopeId/Prefix or the complete DhcpServer settings from the given input file.
The xml file must be as per the DhcpServerSchema XSD (%systemdrive%\Windows\System32\WindowsPowerShell\v1.0\Modules\DhcpServer\DhcpServerSchema.xml)
Input Parameters:
File : Mandatory Parameter from where settings to be imported are read
ScopeId : v4ScopeId. If this parameter is a non-IPv4Address value, TE will be returned
If the ScopeId doesnt exist in import xml file, NTE will be returned
Prefix : v6Prefix. If this parameter is a non-IPv6Address value, TE will be returned
If the Prefix doesnt exist in import xml file, NTE will be returned
ScopeOverwrite : Switch parameter - if given and scope to be imported already exists on target machine, its overwritten else not overwritten
Force : Switch parameter - if given the default confirmation (ShouldContinue) is not asked
Leases : Switch parameter - if given, Leases for all the Scopes to be imported are also imported
ComputerName : Hostname or IPAddress of the target Dhcp Server on which settings need to be imported. If not given, localHost is used
CimSession : CimSession (of type Microsoft.Management.Infrastructure.CimSession) of the target Dhcp Server on which settings need to be imported.
#>
#region ParamDeclaration
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
Param(
[Parameter(Mandatory = $true, Position = 0)]
[string]
${File},
[Parameter(Mandatory = $true, Position = 1)]
[string]
${BackupPath},
[Parameter()]
[System.Net.IPAddress[]]
${ScopeId},
[Parameter()]
[System.Net.IPAddress[]]
${Prefix},
[Parameter()]
[switch]
${ScopeOverwrite},
[Parameter()]
[switch]
${Leases},
[Parameter()]
[switch]
${ServerConfigOnly},
[Parameter()]
[switch]
${Force},
[Parameter()]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[Alias("Cn")]
[string]
${ComputerName},
[Parameter()]
[Alias('Session')]
[ValidateNotNullOrEmpty()]
[Microsoft.Management.Infrastructure.CimSession]
${CimSession}
)
#endregion
Begin {
}
Process
{
[int]$script:ImportSetting = $CompleteDhcpServer
[string]$script:ImprotFile = ""
[bool]$script:IsExport = $false
[string]$script:DhcpServerName = ""
[bool]$BackupTaken = $false
$script:scopesToBeImported = @()
$script:prefixesToBeImported = @()
$script:reader = $null
$script:TargetMcVersion = $null
try {
WriteTraceMessage "Import-DhcpServer::Process Entered"
#If ComputerName is not given, get the local computerName
#else user given ComputerName in $script:DhcpServerName variable
GetComputerName ${ComputerName}
# If ${ServerConfigOnly} parameter is given and ScopeId and/or Prefix is given, return error
if (${ServerConfigOnly} -and (!(IsNull ${ScopeId}) -or !(IsNull ${Prefix})))
{
ThrowTEString $_system_translations.ErrServerConfigGivenWithScopePrefix $EC_InvalidArgument $EC_InvalidArgument
}
# If both ${ServerConfigOnly} and ${Lease} parameters are given, return error
if (${ServerConfigOnly} -and ${Leases})
{
ThrowTEString $_system_translations.ErrServerConfigGivenWithLeases $EC_InvalidArgument $EC_InvalidArgument
}
# If both ${ServerConfigOnly} and ${ScopeOverwrite} parameters are given, return error
if (${ServerConfigOnly} -and ${ScopeOverwrite})
{
ThrowTEString $_system_translations.ErrServerConfigGivenWithScopeOverwrite $EC_InvalidArgument $EC_InvalidArgument
}
#Validate if input ScopeId/Prefix is in correct format
#Returns the ImportSetting Mode [$CompleteDhcpServer=0, $SpecificV4AndV6Scopes=1, $SpecificV4Scopes=2, $SpecificV6Scopes=3]
$script:ImportSetting = ValidateImportParams
ValidateXml $script:ImportFile
#Give the default confirmation (ShouldContinue) and WhatIf/Confirm (ShouldProcess) message
if (!(HandleImportShouldProcessAndShouldContinue)) { WriteTraceMessage "ShouldProcess(SC) returned FALSE -- existing"; return }
#Initializes the XmlSetting, XSD Validating setting and $script:reader
InitializeXmlReader $script:ImportFile
#Take the Dhcp Backup before import starts
WriteTraceMessage "Taking DhcpServer Backup @ ${BackupPath} ..."
ExecuteCmdlet -CmdletName Backup-DhcpServer -MandatoryParams @{"Path"=${BackupPath}} #TE if thrown will be thrown back
WriteTraceMessage "DhcpServer Backup taken @ ${BackupPath}"
Write-Verbose ($_system_translations.Ver_Import_Backup -f ${BackupPath}, $script:DhcpServerName)
$BackupTaken = $true;
#Imports the Dhcp Server
ImportDhcpServerFromFile
WriteTraceMessage ($_system_translations.Ver_Import_End -f $script:DhcpServerName)
Write-Verbose ($_system_translations.Ver_Import_End -f $script:DhcpServerName)
}
catch {
#Give the Restore warning if backup has been taken
if ($BackupTaken) {
Write-Warning ($_system_translations.War_RestoreDhcpDatabase -f ${BackupPath})
}
throw
}
finally {
WriteTraceMessage "Inside Finally"
if ($null -ne $script:reader){ WriteTraceMessage "Closing the reader"; $script:reader.Close() }
}
}
End {
}
}
#region Import Util Functions
# Validates the input ScopeId and Prefix parameters
# Populates $script:scopesToBeImported and $script:prefixesToBeImported variables
# Returns the ImportSetting level
function ValidateImportParams()
{
$errNte = @()
$errTE = $null
#Get OS version of the target machine and check if its Win8 or higher
$outObj = ExecuteCmdlet -CmdletName "Get-DhcpServerVersion"
if (!(IsWindows8OrHigher($outObj))) {
ThrowTEString ($_system_translations.ImportedVersionMismatch -f $outObj.MajorVersion,$outObj.MinorVersion) $EC_InvalidOperation $EC_InvalidOperation
}
$script:TargetMcVersion = $outObj
#If input File doesnt exists - return TE
$script:ImportFile = GetFullyQualifiedPath ${File}
if (!(Test-Path -LiteralPath $script:ImportFile -PathType leaf)) {
ThrowTEString($_system_translations.ImportFileDoesNotExist -f $script:ImportFile) $EC_ResourceUnavailable $EC_ResourceUnavailable $script:ImportFile
}
if (${ScopeId} -ne $null) #User has given ScopeId(s) to be to imported
{
foreach ($scopeId in ${ScopeId})
{
if ($scopeId.AddressFamily -ne [System.Net.Sockets.AddressFamily]::InterNetwork) {
ThrowTEString ($_system_translations.InvalidIPv4ScopeAddress -f $scopeId) $EC_InvalidArgument $EC_InvalidArgument $scopeId
}
$script:scopesToBeImported += $scopeId.ToString()
}
}
else #Import all the Scopes in the file
{
$script:scopesToBeImported = @()
}
if (${Prefix} -ne $null) #User has given Prefix(es) to be to imported
{
foreach ($prefix in ${Prefix})
{
if ($prefix.AddressFamily -ne [System.Net.Sockets.AddressFamily]::InterNetworkV6) {
ThrowTEString ($_system_translations.InvalidIPv6ScopeAddress -f $prefix) $EC_InvalidArgument $EC_InvalidArgument $prefix
}
$script:prefixesToBeImported += $prefix.ToString()
}
}
else #Import all the Prefixes
{
$script:prefixesToBeImported = @()
}
if (!$script:prefixesToBeImported.Count -and !$script:scopesToBeImported.Count) {
return $CompleteDhcpServer
}
elseif ($script:prefixesToBeImported.Count -and $script:scopesToBeImported.Count) {
return $SpecificV4AndV6Scopes
}
elseif ($script:prefixesToBeImported.Count -and !$script:scopesToBeImported.Count) {
return $SpecificV6Scopes
}
elseif (!$script:prefixesToBeImported.Count -and $script:scopesToBeImported.Count) {
return $SpecificV4Scopes
}
}
function ValidateXml([string] $file)
{
$xmlReader = $null
try
{
$sc = New-Object System.Xml.Schema.XmlSchemaSet # Create the XmlSchemaSet class.
$sc.Add($DhcpSchemaName, $DhcpSchemaFile) > $null # Add the schema to the collection.
$xmlSettings = new-object System.Xml.XmlReaderSettings
$xmlSettings.IgnoreComments = $true;
$xmlSettings.IgnoreProcessingInstructions = $true;
$xmlSettings.IgnoreWhitespace = $true;
$xmlSettings.ValidationType = [System.Xml.ValidationType]::Schema;
$xmlSettings.Schemas = $sc;
$xmlSettings.CheckCharacters = $false;
$xmlReader = [Xml.XmlReader]::Create($file, $xmlSettings)
$xmlReader.MoveToContent() > $null # Current node is now root node (DHCPServer)
$xmlReader.Read() > $null # Move to MajorVersion element
$xmlReader.ReadToNextSibling("MajorVersion") > $null # Since there is no MajorVersion sibling at this level, it will move to end element of parent node (DHCPServer) of current node
while ($xmlReader.Read() > $null ) { } # This makes sure if there are more than 1 root element, it gives error
}
catch
{
WriteTraceMessage "ValidateXml failed $_"
ThrowTEString ($_system_translations.ErrXmlValidationFailed-f $file, $DhcpSchemaFile, $_.ToString())
}
finally
{
if ($null -ne $xmlReader) { $xmlReader.Close() }
}
}
# Initialzes XmlSetting and XmlSchemaSet (to $DhcpSchemaFile schema file)
# Initializes the XmlReader ($script:reader)
function InitializeXmlReader([string] $file)
{
try
{
$xmlSettings = new-object System.Xml.XmlReaderSettings
$xmlSettings.IgnoreComments = $true;
$xmlSettings.IgnoreProcessingInstructions = $true;
$xmlSettings.IgnoreWhitespace = $true;
$xmlSettings.ValidationType = [System.Xml.ValidationType]::None;
$xmlSettings.CheckCharacters = $false;
$script:reader = [Xml.XmlReader]::Create($file, $xmlSettings)
}
catch
{
WriteTraceMessage "InitializeXmlReader failed $_"
throw
}
}
# Reads the version info from Xml file
# Validate Xml version info is equal or greater than target machine version
function ReadAndVerifyVersionInfo()
{
#reader is at present on the MajorVersion element
$majorVer = $script:reader.ReadElementContentAsInt()
$minorVer = $script:reader.ReadElementContentAsInt()
WriteTraceMessage "MajorVersion: $majorVer MinorVersion: $minorVer"
#Allow Windows Server 2012 R2 and Windows Server 2012 compatibility
if (($script:TargetMcVersion.MajorVersion -eq $Win8MajorVersion) -and ($script:TargetMcVersion.MajorVersion -eq $majorVer) -and ($script:TargetMcVersion.MinorVersion -eq $Win8MinorVersion) -and ($minorVer -eq $Win9MinorVersion))
{
return
}
if (($script:TargetMcVersion.MajorVersion -lt $majorVer) -or (($script:TargetMcVersion.MajorVersion -eq $majorVer) -and ($script:TargetMcVersion.MinorVersion -lt $minorVer)))
{
ThrowTEString ($_system_translations.ImportedFileVersionMismatch -f $script:TargetMcVersion.MajorVersion,$script:TargetMcVersion.MinorVersion,$majorVer,$minorVer) $EC_InvalidOperation $EC_InvalidOperation
}
#reader is now positioned at element after Minor version
}
function ReadAndApplyServerSetting
{
[hashtable] $mandatory = @{}
$errNte = @(); $errTE = $null
#reader is at present on the ConflictDetectionAttempts element
$conflictDetAttempts = $script:reader.ReadElementContentAsInt(); $mandatory.Add($ConflictDetAttemptsElement, $conflictDetAttempts)
$napEnabled = $script:reader.ReadElementContentAsBoolean(); $mandatory.Add($NapEnabledElement, $napEnabled)
$npsUnreachableAction = $script:reader.ReadElementContentAsString(); $mandatory.Add($NpsUnreachableActionElement, $npsUnreachableAction)
if ($script:reader.IsStartElement($ActivatePoliciesElement)) {
$activatePolicies = $script:reader.ReadElementContentAsBoolean()
$mandatory.Add($ActivatePoliciesElement, $activatePolicies)
}
WriteTraceMessage "$mandatory"
$temp = ExecuteCmdlet -CmdletName Set-DhcpServerSetting -MandatoryParams $mandatory -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
#reader is now positioned at the element next to last server setting element (which is ActivatePolicies or NpsUnreachableAction)
}
#While entring node is startElement 'Class' / While leaving Node is EndElement 'Class'
function ReadAndApplyClass([bool]$IsV4, [Array]$allClasses)
{
$errNte = @(); $errTE = $null
$mandatory = @{}; $optional = @{}
$script:reader.Read() > $null #current node is 'Class' move it to next node
GenericXmlReader $mandatory $ClassPropertiesMandatory $optional $ClassPropertiesOptional
#$mandatory | ft; $optional | ft
#Check if the Class in XML is present on target machine
foreach ($class in $allClasses) {
if ($class.Data -ceq $mandatory["Data"]) {
#WriteTraceMessage "Class $($mandatory["Name"]) is found conflicting - wont be imported"
Write-Verbose ($_system_translations.Ver_Import_ClassAlreadyExist -f $mandatory["Name"],$mandatory["Type"],$script:DhcpServerName)
return
}
}
if ($IsV4) { $cmdlet = "Add-DhcpServerv4Class" } else { $cmdlet = "Add-DhcpServerv6Class" }
WriteTraceMessage "Class $($mandatory["Name"]) is NOT found conflicting - WILL BE IMPORTED"
$temp = ExecuteCmdlet -CmdletName $cmdlet -MandatoryParams $mandatory -OptionalParams $optional -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
}
#While entring node is startElement 'Classes' / While leaving Node is EndElement 'Classes'
function ReadAndApplyClasses([bool] $IsV4)
{
WriteTraceMessage "Started reading Classes node"
Write-Verbose $_system_translations.Ver_Import_Classes
[Array]$allClasses = @()
$errNte = @(); $errTE = $null
#Get all the classes
if ($IsV4) { $cmdlet = "Get-DhcpServerv4Class" } else { $cmdlet = "Get-DhcpServerv6Class" }
$temp = ExecuteCmdlet -CmdletName $cmdlet -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
if (NotNull $temp) { $allClasses += $temp }
while ($script:reader.Read()) {
if ($script:reader.IsStartElement($ClassElement)) {
ReadAndApplyClass $IsV4 $allClasses
}
else { break }
}
}
#While entring node is startElement 'OptionDefinition' / While leaving Node is EndElement 'OptionDefinition'
function ReadAndApplyOptDefintion([bool]$IsV4, [Array]$allOptDefs)
{
$errNte = @(); $errTE = $null
$mandatory = @{}; $optional = @{}
$script:reader.Read() > $null #current node is 'OptionDefinition' move it to next node
GenericXmlReader $mandatory $OptDefPropertiesMandatory $optional $OptDefPropertiesOptional
#$mandatory | ft; $optional | ft
#Check if the OptDef in XML is present on target machine - Dont Import if its already present
foreach ($optDef in $allOptDefs) {
if (($optDef.OptionId.ToString() -eq $mandatory["OptionId"]) -and ($optDef.VendorClass -eq $optional["VendorClass"])) {
#WriteTraceMessage "OptDef $($mandatory["Name"]) with Id=$($mandatory["OptionId"]) is found conflicting - wont be imported"
Write-Verbose ($_system_translations.Ver_Import_OptDefAlreadyExist -f $mandatory["Name"],$script:DhcpServerName)
return
}
}
#Update the bool field from true/1 or false/0 to $true or $false
if (("true" -eq $mandatory["MultiValued"]) -or ("1" -eq $mandatory["MultiValued"])) { $switchParam = @{"MultiValued"=$true} } else { $switchParam = @{"MultiValued"=$false} }
$mandatory.Remove("MultiValued")
if ($IsV4) { $cmdlet = "Add-DhcpServerv4OptionDefinition" } else { $cmdlet = "Add-DhcpServerv6OptionDefinition" }
WriteTraceMessage "OptDef $($mandatory["Name"]) with Id=$($mandatory["OptionId"]) is NOT found conflicting - WILL BE IMPORTED"
$temp = ExecuteCmdlet -CmdletName $cmdlet -MandatoryParams $mandatory -OptionalParams $optional -SwitchParams $switchParam -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
}
#While entring node is startElement 'OptionDefinitions' / While leaving Node is EndElement 'OptionDefinitions'
function ReadAndApplyOptionDefintions([bool] $IsV4)
{
WriteTraceMessage "Started reading OptionDefinitions node"
Write-Verbose $_system_translations.Ver_Import_OptDef
[Array]$allOptDefs = GetAllOptionDefinitions $IsV4
while ($script:reader.Read()) {
if ($script:reader.IsStartElement($OptDefElement)) {
ReadAndApplyOptDefintion $IsV4 $allOptDefs
}
else { break }
}
}
#While entring node is startElement 'OptionValue' / While leaving Node is EndElement 'OptionValue'
function ReadAndApplyOptValue([bool]$IsV4, [HashTable]$levelToSetParams)
{
$errNte = @(); $errTE = $null
$mandatory = @{}; $optional = @{}
$script:reader.Read() > $null #current node is 'OptionValue' move it to next node
GenericXmlReader $mandatory $OptValuePropertiesMandatory $optional $OptValuePropertiesOptional
if (!$optional.Contains("Value")) {
$optId = $mandatory["OptionId"] ; $warnMesg = ""
if ($IsV4) { $scopeTag = "ScopeId" } else { $scopeTag = "Prefix" }
if (IsNull $levelToSetParams) {
$warnMesg = ($_system_translations.War_ImportOptValueServerLevelWithoutValue -f $optId,$script:DhcpServerName)
}
elseif ($levelToSetParams.Contains("PolicyName") -and $levelToSetParams.Contains($scopeTag)) {
$warnMesg = ($_system_translations.War_ImportOptValueScopePolicyLevelWithoutValue -f $optId,$levelToSetParams["PolicyName"],$levelToSetParams[$scopeTag],$script:DhcpServerName)
}
elseif ($levelToSetParams.Contains("PolicyName")) {
$warnMesg = ($_system_translations.War_ImportOptValueServerPolicyLevelWithoutValue -f $optId,$levelToSetParams["PolicyName"],$script:DhcpServerName)
}
elseif ($levelToSetParams.Contains("$scopeTag")) {
$warnMesg = ($_system_translations.War_ImportOptValueScopeLevelWithoutValue -f $optId,$levelToSetParams[$scopeTag],$script:DhcpServerName)
}
elseif ($levelToSetParams.Contains("ReservedIP")) {
$warnMesg = ($_system_translations.War_ImportOptValueReservationLevelWithoutValue -f $optId,$levelToSetParams["ReservedIP"],$script:DhcpServerName)
}
Write-Warning $warnMesg
return
}
if (NotNull $levelToSetParams) { $optional += $levelToSetParams }
if ($IsV4) { $cmdlet = "Set-DhcpServerv4OptionValue" } else { $cmdlet = "Set-DhcpServerv6OptionValue" }
$temp = ExecuteCmdlet -CmdletName $cmdlet -MandatoryParams $mandatory -OptionalParams $optional -SwitchParams @{"Force"=$true} -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
}
# All the OptValues on the target machine will be deleted if DeleteExisting is True
# If While entring the function, the StartElement is 'OptionValues'' then all the OptionValue elements under it would be imported AND while leaving the function, the node is EndElement 'OptionValues'
# Else Xml is not processed
function ReadAndApplyOptionValues([bool] $IsV4, [string] $ScopeId="", [string]$ReservedIP="", [string]$PolicyName="", [bool]$DeleteExisting=$true)
{
[string]$verboseDelMessage = "";
[string]$verboseImportMessage = ""
[HashTable]$optionalParam = $null
if ($IsV4) { $scope = "ScopeId" } else { $scope = "Prefix" }
if ((IsNullOrEmptyString $ScopeId) -and (IsNullOrEmptyString $ReservedIP) -and (IsNullOrEmptyString $PolicyName)) {
$verboseDelMessage = $_system_translations.Ver_Import_Server_OptVal_Del
$verboseImportMessage = $_system_translations.Ver_Import_Server_OptVal
$optionalParam = $null
}
if ((IsNullOrEmptyString $ScopeId) -and (IsNullOrEmptyString $ReservedIP) -and (!(IsNullOrEmptyString $PolicyName))) {
$verboseImportMessage = ($_system_translations.Ver_Import_Server_Pol_OptVal -f $PolicyName)
$optionalParam = @{ "PolicyName"=$PolicyName }
}
elseif (!(IsNullOrEmptyString $ScopeId) -and (IsNullOrEmptyString $PolicyName)) {
$verboseDelMessage = ($_system_translations.Ver_Import_Scope_OptVal_Del -f $ScopeId)
$verboseImportMessage = ($_system_translations.Ver_Import_Scope_OptVal -f $ScopeId)
$optionalParam = @{$scope = $ScopeId }
}
elseif (!(IsNullOrEmptyString $ReservedIP)) {
$verboseDelMessage = ($_system_translations.Ver_Import_Rsvation_OptVal_Del -f $ReservedIP);
$verboseImportMessage = ($_system_translations.Ver_Import_Rsvation_OptVal -f $ReservedIP)
$optionalParam = @{"ReservedIP" = $ReservedIP }
}
elseif (!(IsNullOrEmptyString $ScopeId) -and (!(IsNullOrEmptyString $PolicyName))) {
$verboseImportMessage = ($_system_translations.Ver_Import_Scope__PolOptVal -f $PolicyName,$ScopeId)
$optionalParam = @{$scope = $ScopeId; "PolicyName"=$PolicyName }
}
#WriteTraceMessage $verboseImportMessage
if ($DeleteExisting) {
if (IsNullOrEmptyString $PolicyName) {
Write-Verbose $verboseDelMessage
#Get & Delete all the existing OptionValues for v4Server/Scope/Reservation on targetServer
if ($IsV4) { $cmdletGet = "Get-DhcpServerv4OptionValue -All -Brief"; $cmdletDel = "Remove-DhcpServerv4OptionValue" }
else { $cmdletGet = "Get-DhcpServerv6OptionValue -All -Brief"; $cmdletDel = "Remove-DhcpServerv6OptionValue" }
$GetOptValueCmdlet = ExecuteCmdlet -CmdletName $cmdletGet -OptionalParams $optionalParam -DontRun
$RemoveOptValueCmdlet = ExecuteCmdlet -CmdletName $cmdletDel -OptionalParams $optionalParam -DontRun
$pipelineCmdlet = "$GetOptValueCmdlet | $RemoveOptValueCmdlet"
WriteTraceMessage "Running Cmdlet: $pipelineCmdlet"
try { Invoke-Expression $pipelineCmdlet}
catch { PostNteObject $_ } #All NTEs will be given back to user - while TE will be posted as NTE
}
}
if ($script:reader.IsStartElement($OptValuesElement)) { #If OptionValues start element is present, import all the OptionValue elements under it
Write-Verbose $verboseImportMessage
while ($script:reader.Read()) { #Reader is at present on OptionValues start element - move it to OptoinValue start element
if ($script:reader.IsStartElement($OptValueElement)) {
ReadAndApplyOptValue $IsV4 $optionalParam
}
else { break }
}
$script:reader.Read() > $null #Move to element after OptionValues End element
}
}
#While entring node is startElement 'Reservation' / While leaving Node is EndElement 'Reservation'
function ReadAndApplyReservation([bool] $IsV4, [string]$ScopeId)
{
$errNte = @(); $errTE = $null
$mandatory = @{}; $optional = @{}
$script:reader.Read() > $null #current node is 'Reservation' move it to next node
if ($IsV4) { $cmdlet = "Add-DhcpServerv4Reservation -ScopeId $ScopeId" } else { $cmdlet = "Add-DhcpServerv6Reservation -Prefix $ScopeId" }
GenericXmlReader $mandatory $ReservationPropertiesMandatory $optional $ReservationPropertiesOptional
#$mandatory | ft; $optional | ft
$temp = ExecuteCmdlet -CmdletName $cmdlet -MandatoryParams $mandatory -OptionalParams $optional -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
#If Add reservation fails, no need to process further on this reservation
if ((NotNull $errTE) -or ($errNte.Count -gt 0)) {
WriteTraceMessage "ReadAndApplyReservation: Add Reservation for IP $($mandatory["IPAddress"]) failed -- exiting the function" $true
return
}
#If there is a OptionValues Node, import all v4 OptValues for this reservation
ReadAndApplyOptionValues $IsV4 "" $mandatory["IPAddress"] "" $false
}
#While entring node is startElement 'Reservations' / While leaving Node is EndElement 'Reservations'
# All the Reservations on the target machine will be deleted if DeleteExisting is True
# If While entring the function, the StartElement is 'Reservations' then all the Reservation elements under it would be imported AND while leaving the function, the node is EndElement 'Reservations'
# Else Xml is not processed
function ReadAndApplyReservations([bool]$IsV4, [string] $ScopeId, [bool]$DeleteExisting=$true)
{
[string]$verboseDelMessage = ""
[string]$verboseImportMessage = ""
[HashTable]$optionalParam = $null
$errNte = @()
$errTE = $null
if ($DeleteExisting) {
#WriteTraceMessage ($_system_translations.Ver_Import_Scope_Rsvation_Del -f $scopeId)
Write-Verbose ($_system_translations.Ver_Import_Scope_Rsvation_Del -f $scopeId)
if ($IsV4) { $cmdlet = "Remove-DhcpServerv4Reservation -Scope $ScopeId" }
else { $cmdlet = "Remove-DhcpServerv6Reservation -Prefix $ScopeId" }
#Delete all the existing Reservations for the Scope
ExecuteCmdlet -CmdletName $cmdlet -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject($errTE); PostNteObject($errNte)
}
if ($script:reader.IsStartElement($ReservationsElement)) { #If Reservations start element is present, import all the Reservation elements under it
Write-Verbose ($_system_translations.Ver_Import_Scope_Rsvation -f $scopeId)
while ($script:reader.Read()) { #Reader is at present on Reservations start element - move it to Reservation start element
if ($script:reader.IsStartElement($ReservationElement)) {
ReadAndApplyReservation $IsV4 $ScopeId
}
else { break }
}
$script:reader.Read() > $null #Move to element after Reservations End element
}
}
#While entring node is startElement 'Policy' / While leaving Node is EndElement 'Policy'
function ReadAndApplyPolicy([HashTable]$levelToSetParams, $skipProcessingOrder)
{
$errNte = @(); $errTE = $null
$mandatory = @{}; $optional = @{}
$script:reader.Read() > $null #current node is 'Policy' move it to next node
$DnsSuffix = $null;
$RetVal = $true;
GenericXmlReader $mandatory $PolicyPropertiesMandatory $optional $PolicyPropertiesOptional
#$mandatory | ft; $optional | ft
$DnsSuffix=$optional[$PolicyPropertiesOptional[10]];
$optional.Remove($PolicyPropertiesOptional[10]);
$scopeId = ""
if (NotNull $levelToSetParams) { $optional += $levelToSetParams; $scopeId = $levelToSetParams["ScopeId"] }
#Update the Enabled bool field from true/1 or false/0 to $true or $false
if (("true" -eq $mandatory["Enabled"]) -or ("1" -eq $mandatory["Enabled"])) { $mandatory["Enabled"]=$true } else { $mandatory["Enabled"] = $false }
if ($true -eq $skipProcessingOrder)
{
$mandatory.Remove("ProcessingOrder");
}
$temp = ExecuteCmdlet -CmdletName Add-DhcpServerv4Policy -MandatoryParams $mandatory -OptionalParams $optional -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
#If Add Policy fails, no need to process further on this Policy
if ((NotNull $errTE) -or ($errNte.Count -gt 0)) {
WriteTraceMessage "ReadAndApplyPolicy: Add Policy for $($mandatory["Name"]) failed -- existing the function" $true
$RetVal = $false;
}
if (NotNull $DnsSuffix) {
if (IsNullOrEmptyString $ScopeId) {
$optionalScopeParam = $null
}
elseif (!(IsNullOrEmptyString $ScopeId)) {
$optionalScopeParam = @{"ScopeId" = $ScopeId }
}
$temp = ExecuteCmdlet -CmdletName "Set-DhcpServerV4DnsSetting -PolicyName `"$($mandatory["Name"])`" -DnsSuffix `"$($DnsSuffix)`" " -OptionalParams $optionalScopeParam -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
#If Add Policy fails, no need to process further on this Policy
if ((NotNull $errTE) -or ($errNte.Count -gt 0)) {
WriteTraceMessage "ReadAndApplyPolicy: Setting DNSSuffix for $($mandatory["Name"]) failed" $true
}
}
if ((NotNull $levelToSetParams) -and ($script:reader.IsStartElement($IPRangesElement))) {
while ($script:reader.Read()) { #Reader is at present on IPRanges start element - move it to IPRange start element
if ($script:reader.IsStartElement($IPRangeElement))
{
$script:reader.Read() > $null #Move element to StartRange element
$startRange = $script:reader.ReadElementString($StartIPRangeElement);
$endRange = $script:reader.ReadElementString($EndIPRangeElement);
$temp = ExecuteCmdlet -CmdletName "Add-DhcpServerv4PolicyIPRange -Name `"$($mandatory["Name"])`" -ScopeId $scopeId -StartRange $startRange -EndRange $endRange" -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
}
else { break }
}
$script:reader.Read() > $null #Move element to IPRanges end element
}
#If current node is at OptionValues, import all the OptValues for this Policy
ReadAndApplyOptionValues $true $scopeId "" $mandatory["Name"] $false
return $RetVal;
}
# All the Policies on the target machine will be deleted if DeleteExisting is True
# If While entring the function, the StartElement is 'Policies' then all the Policy elements under it would be imported AND while leaving the function, the node is EndElement 'Policies'
# Else Xml is not processed
function ReadAndApplyPolicies([string] $ScopeId="", [bool]$DeleteExisting=$true)
{
[string]$verboseDelMessage = ""
[string]$verboseImportMessage = ""
[HashTable]$optionalParam = $null
[string[]]$polNames = @()
$errNte = @()
$errTE = $null
$policies = @()
$skipProcessingOrder = $false;
$addPolicySuccess = $false;
if (IsNullOrEmptyString $ScopeId) {
$verboseDelMessage = $_system_translations.Ver_Import_Server_Policy_Del;
$verboseImportMessage = $_system_translations.Ver_Import_Server_Policy;
$optionalParam = $null
}
elseif (!(IsNullOrEmptyString $ScopeId)) {
$verboseDelMessage = ($_system_translations.Ver_Import_Scope_Policy_Del -f $ScopeId);
$verboseImportMessage = ($_system_translations.Ver_Import_Scope_Policy -f $ScopeId);
$optionalParam = @{"ScopeId" = $ScopeId }
}
#WriteTraceMessage $verboseImportMessage
if ($DeleteExisting) {
Write-Verbose $verboseDelMessage
#Get & Delete all the existing Policies for v4Server/Scope on targetServer
$temp = ExecuteCmdlet -CmdletName Get-DhcpServerv4Policy -OptionalParams $optionalParam -Nte ([ref]$errNte) -TE ([ref]$errTE)
if (NotNull $temp) { $policies += $temp }
PostNteObject $errTE; PostNteObject $errNte
foreach ($policy in $policies) { $polNames += $policy.Name }
if ($polNames.Count -gt 0) {
ExecuteCmdlet -CmdletName Remove-DhcpServerv4Policy -MandatoryParams @{"Name"=$polNames} -OptionalParams $optionalParam -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
}
}
if ($script:reader.IsStartElement($PoliciesElement)) { #If Policies start element is present, import all the Policy elements under it
Write-Verbose $verboseImportMessage
while ($script:reader.Read()) { #Reader is at present on Policies start element - move it to Policy start element
if ($script:reader.IsStartElement($PolicyElement)) {
$addPolicySuccess = ReadAndApplyPolicy $optionalParam $skipProcessingOrder
if ($false -eq $addPolicySuccess)
{
$skipProcessingOrder = $true;
}
}
else { break }
}
$script:reader.Read() > $null #Move element to after Policies end element
}
}
#While entring node is startElement 'Lease' / While leaving Node is EndElement 'Lease'
function ReadAndApplyv4Lease([string]$ScopeId)
{
$errNte = @(); $errTE = $null
$mandatory = @{}; $optional = @{}
$script:reader.Read() > $null #current node is 'Lease' move it to next node
GenericXmlReader $mandatory $LeasePropertiesMandatory $optional $LeasePropertiesOptional
#$mandatory | ft; $optional | ft
if ($mandatory["AddressState"] -eq "InactiveReservation") {
WriteTraceMessage ("ReadAndApplyv4Lease: Lease {0} is an InactiveReservation - skipping .." -f $mandatory["IPAddress"])
return
}
#Update the NapCapable bool field from true/1 or false/0 to $true or $false
if (("true" -eq $mandatory["NapCapable"]) -or ("1" -eq $mandatory["NapCapable"])) { $mandatory["NapCapable"]=$true } else { $mandatory["NapCapable"] = $false }
#For downlevel systems A is not supported so change it to AandPTR
if (("A" -eq $optional["DnsRR"]) -and (($script:TargetMcVersion.MajorVersion -lt $Win8MajorVersion) -or (($script:TargetMcVersion.MajorVersion -eq $Win8MajorVersion) -and ($script:TargetMcVersion.MinorVersion -lt $Win9MinorVersion))))
{
$optional["DnsRR"] = "AandPTR";
}
$temp = ExecuteCmdlet -CmdletName Add-DhcpServerv4Lease -MandatoryParams $mandatory -OptionalParams $optional -Nte ([ref]$errNte) -TE ([ref]$errTE)
#If leases addition fails with 20014 (Client Already Exist) error, ignore the error
if ((NotNull $errTE) -and ($errTE.Exception -is [Microsoft.Management.Infrastructure.CimException]) -and ($errTE.Exception.ErrorData.error_Code -eq 20014)) { return }
if ((NotNull $errNte) -and ($errNte.Count -gt 0) -and ($errNte[0].Exception.ErrorData.error_Code -eq 20014)) { return }
PostNteObject $errTE; PostNteObject $errNte
}
#While entring node is startElement 'Leases' / While leaving Node is EndElement 'Leases'
function ReadAndApplyv4Leases([string] $ScopeId="")
{
WriteTraceMessage ($_system_translations.Ver_Import_Scope_Leases -f $ScopeId)
Write-Verbose ($_system_translations.Ver_Import_Scope_Leases -f $ScopeId)
while ($script:reader.Read()) { #Reader is at present on Leases start element - move it to Lease start element
if ($script:reader.IsStartElement($LeaseElement)) {
ReadAndApplyv4Lease $ScopeId
}
else { break }
}
}
# All the ExclusionRanges on the target machine will be deleted if DeleteExisting is True
# If While entring the function, the StartElement is 'ExclusionRanges' then all the ExclusionRange elements under it would be imported AND while leaving the function, the node is EndElement 'ExclusionRanges'
# Else Xml is not processed
function ReadAndApplyExclusionRanges([bool]$IsV4, [string]$ScopeId, [bool]$DeleteExisting=$true)
{
$errNte = @(); $errTE = $null
$localEV = @()
if ($DeleteExisting) {
#Delete All the existing Exclusion range for the scope
Write-Verbose ($_system_translations.Ver_Import_Scope_ExRange_Del -f $ScopeId)
#Get & Delete all the existing ExclusionRanges for this scope
if ($IsV4) {
$GetExRangeCmdlet = ExecuteCmdlet -CmdletName "Get-DhcpServerv4ExclusionRange -ScopeId $ScopeId" -Nte ([ref]$errNte) -DontRun
$RemoveExRangeCmdlet = ExecuteCmdlet -CmdletName "Remove-DhcpServerv4ExclusionRange -ScopeId $ScopeId" -Nte ([ref]$errNte) -DontRun
}
else {
$GetExRangeCmdlet = ExecuteCmdlet -CmdletName "Get-DhcpServerv6ExclusionRange -Prefix $ScopeId" -Nte ([ref]$errNte) -DontRun
$RemoveExRangeCmdlet = ExecuteCmdlet -CmdletName "Remove-DhcpServerv6ExclusionRange -Prefix $ScopeId" -Nte ([ref]$errNte) -DontRun
}
$pipelineCmdlet = "$GetExRangeCmdlet | $RemoveExRangeCmdlet"
WriteTraceMessage "Running Cmdlet: $pipelineCmdlet"
try { Invoke-Expression $pipelineCmdlet }
catch { PostNteObject $_ } #catch the TE & post it as NTE
PostNteObject($localEV)
}
if ($script:reader.IsStartElement($ExclusionRangesElement)) { #If ExclusionRanges start element is present, import all the ExclusionRange elements under it
Write-Verbose ($_system_translations.Ver_Import_Scope_ExRange -f $ScopeId)
while ($script:reader.Read()) { #Reader is at present on ExclusionRanges start element - move it to IPRange start element
if ($script:reader.IsStartElement($IPRangeElement))
{
$script:reader.Read() > $null #Move to StartRange element
$startRange = $script:reader.ReadElementString($StartIPRangeElement);
$endRange = $script:reader.ReadElementString($EndIPRangeElement);
if ($IsV4) {
$temp = ExecuteCmdlet -CmdletName "Add-DhcpServerv4ExclusionRange -ScopeId $ScopeId -StartRange $startRange -EndRange $endRange" -Nte ([ref]$errNte) -TE ([ref]$errTE)
}
else {
$temp = ExecuteCmdlet -CmdletName "Add-DhcpServerv6ExclusionRange -Prefix $ScopeId -StartRange $startRange -EndRange $endRange" -Nte ([ref]$errNte) -TE ([ref]$errTE)
}
PostNteObject $errTE; PostNteObject $errNte
}
else { break }
}
$script:reader.Read() > $null #Move to node next to ExclusionRanges end element
}
}
#Checks if $CurrentScopeId and $CurrentSubnetMask is exact match of any element in $Existingv4Scopes
#If yes, return $true else $false
function IsConflictingv4Scope([string]$CurrentScopeId, [string] $CurrentSubnetMask)
{
foreach ($scope in $script:Existingv4Scopes) {
if (($CurrentScopeId -eq $scope.ScopeId.ToString()) -and ($CurrentSubnetMask -eq $scope.SubnetMask.ToString())) {
return $true
}
}
return $false
}
#Checks if $CurrentScopeId is exact match of any element in $Existingv6Scopes
#If yes, return $true else $false
function IsConflictingv6Scope([string]$CurrentScopeId)
{
foreach ($scope in $script:Existingv6Scopes) {
if ($CurrentScopeId -eq $scope.Prefix.ToString()) {
return $true
}
}
return $false
}
#While entring reader is at startElement 'Scope' []and while leaving reader is at EndElement 'Scope' []
function ReadAndApplyv4Scope()
{
WriteTraceMessage "Entered ReadAndApplyv4Scope"
$errNte = @(); $errTE = $null
$mandatory = @{}; $optional = @{}
$script:reader.Read() > $null #current node is 'Scope' move it to next node
GenericXmlReader $mandatory $Scopev4PropertiesMandatory $optional $Scopev4PropertiesOptional
#Reader is now at 'Superscope' node
$currentScopeId = $mandatory["ScopeId"]
$script:ImportFilev4Scopes += $currentScopeId
WriteTraceMessage "Current ImportFile v4Scope is $currentScopeId"
#If !CompleteServerImport AND ImportFileScope is not part of inputScope List, skip to end Scope element & return
#If ImportFileScope exists on destination
#if ScopeOverwrite and lease is given, delete the scope and then Add it
#if ScopeOverwrite is given, update the scope
#If ScopeOverwrite is not given, skip to next element
#Delete and add all the sub-elements of the scope
#If ImportFileScope does not exist on destination
#Add the scope and all it sub-element
if ($script:ImportSetting -ne $CompleteDhcpServer) {
#One of more v4scopes given to be imported
#Check if ImportFile current v4scope is part of input v4scope list
#If not, skip to end scope element for current scope
if ($script:scopesToBeImported -notcontains $currentScopeId) {
$script:reader.ReadToNextSibling($ScopeElement) > $null #Since there is no sibling at this level, it will move to end element of parent node of current node
WriteTraceMessage ("Current ImportFile scope $currentScopeId not part of input scope List. Skipping to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
return;
}
}
$toAdd = $false; $toUpdate = $false; $toDeleteScopeSubElement = $false;
if (IsConflictingv4Scope $currentScopeId $mandatory["SubnetMask"])
{
#Conflicting v4 Scope is present
if (${ScopeOverwrite} -and ${Leases}) { #Both ScopeOverwrite and Leases are given - delete & add the scope
Write-Verbose ($_system_translations.Ver_Import_Scope_Exists_3 -f $currentScopeId,$script:DhcpServerName)
#Remove the v4 scope on the target machine
ExecuteCmdlet -CmdletName "Remove-DhcpServerv4Scope -ScopeId $currentScopeId -Force" -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
$toAdd = $true
}
elseif (${ScopeOverwrite}) { #Only ScopeOverwrite is given
$toUpdate = $true
$toDeleteScopeSubElement = $true #Need to delete all the scope subelement other than leases
Write-Verbose ($_system_translations.Ver_Import_Scope_Exists_1 -f $currentScopeId,$script:DhcpServerName)
}
else { #ScopeOverwrite is not given
#Move to scope end element []
Write-Warning ($_system_translations.War_Import_Scope_Exists_2 -f $currentScopeId,$script:DhcpServerName)
$script:reader.ReadToNextSibling($ScopeElement) > $null #Since there is no sibling at this level, it will move to end element of parent node of current node
WriteTraceMessage ("Current ImportFile v4scope $currentScopeId already present on destination. Skipping to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
return;
}
}
else
{
#No conflicting scope found - Add the scope
$toAdd = $true
}
WriteTraceMessage ($_system_translations.Ver_Import_Scope -f $currentScopeId, $script:DhcpServerName)
Write-Verbose ($_system_translations.Ver_Import_Scope -f $currentScopeId, $script:DhcpServerName)
$switchParam = $null
if ($toUpdate) { #Update the current ImportFile v4Scope on the target machine
#Update the NapEnable bool field from true/1 or false/0 to $true or $false
if (("true" -eq $mandatory["NapEnable"]) -or ("1" -eq $mandatory["NapEnable"])) { $mandatory["NapEnable"]=$true } else { $mandatory["NapEnable"]=$false }
if ($optional.Contains("ActivatePolicies")) {
if (("true" -eq $optional["ActivatePolicies"]) -or ("1" -eq $optional["ActivatePolicies"])) { $optional["ActivatePolicies"]=$true } else { $optional["ActivatePolicies"]=$false }
}
$cmdlet = "Set-DhcpServerv4Scope"
#Remove the SubnetMask mandatory field since Set-Scope doesnt take it
$mandatory.Remove("SubnetMask")
WriteTraceMessage "Updating (SET) the Scope"
}
elseif ($toAdd) { #Add the current ImportFile v4Scope on the target machine
#Update the NapEnable bool field from true/1 or false/0 to $true or $false and add this as switch parameter
if (("true" -eq $mandatory["NapEnable"]) -or ("1" -eq $mandatory["NapEnable"])) { $switchParam = @{"NapEnable"=$true} } else { $switchParam = @{"NapEnable"=$false} }
$mandatory.Remove("NapEnable")
#Remove the ScopeId mandatory field since Add-Scope doesnt take it
$mandatory.Remove("ScopeId")
if ($optional.Contains("ActivatePolicies")) {
if (("true" -eq $optional["ActivatePolicies"]) -or ("1" -eq $optional["ActivatePolicies"])) { $optional["ActivatePolicies"]=$true } else { $optional["ActivatePolicies"]=$false }
}
$cmdlet = "Add-DhcpServerv4Scope"
WriteTraceMessage "Adding the v4 Scope"
}
#Add/Set the current ImportFile Scope
$temp = ExecuteCmdlet -CmdletName $cmdlet -MandatoryParams $mandatory -OptionalParams $optional -SwitchParams $switchParam -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
#If Add scope fails, no need to process further
if ($toAdd -and (NotNull $errTE)) {
WriteTraceMessage "ReadAndApplyv4Scope: Add v4Scope failed -- existing the function" $true
$script:reader.ReadToNextSibling($ScopeElement) > $null #Since there is no sibling at this level, it will move to end element of parent node of current node
WriteTraceMessage ("ReadAndApplyv4Scope: Add v4Scope failed - Skipping to end of scope - {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
return
}
ImportDhcpv4ScopeSubElements $currentScopeId $toDeleteScopeSubElement
}
function ImportDhcpv4ScopeSubElements([string]$ScopeId, [bool]$ToDeleteScopeSubElement=$true)
{
WriteTraceMessage ("ImportDhcpv4ScopeSubElement: ScopeId= {0}, DeleteSubElement= {1}" -f $ScopeId,$ToDeleteScopeSubElement)
ReadAndApplyExclusionRanges $true $ScopeId $ToDeleteScopeSubElement
#If there is a Policies Node, import all v4 Policies for this scope
ReadAndApplyPolicies $ScopeId $ToDeleteScopeSubElement
#If there is a OptionValues Node, import all v4 OptValues for this scope
ReadAndApplyOptionValues $true $ScopeId "" "" $ToDeleteScopeSubElement
#If there is a Reservations Node, import all v4 Reservation for this scope
ReadAndApplyReservations $true $ScopeId $ToDeleteScopeSubElement
#If there is a Leases Node and Leases switch parameter is given, import all v4 Leases for this scope
if ($script:reader.IsStartElement($LeasesElement)) {
if (!($script:reader.IsEmptyElement)) {
if (${Leases}) {
ReadAndApplyv4Leases $ScopeId
$script:reader.Read() > $null #Move to element after Leases End element
}
else {
$script:reader.Skip() #Move to element after Leases End element
WriteTraceMessage ("Skipping v4 Leases to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
}
}
else { #Empty element - move to element after empty Leases node
WriteTraceMessage "Empty Leases element ..."
$script:reader.Read() > $null
}
}
}
#Get all existing v4 or v6 scopes on destination machine
function GetAllScopes([bool]$IsV4)
{
$errNte = @(); $errTE = $null
[Array]$allScopes = @()
if ($IsV4) { $cmdlet = "Get-DhcpServerv4Scope" } else { $cmdlet = "Get-DhcpServerv6Scope" }
$temp = ExecuteCmdlet -CmdletName $cmdlet -Nte ([ref]$errNte) -Te ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
if (NotNull $temp) { $allScopes += $temp }
return $allScopes
}
#While entring node is startElement 'Scopes' / While leaving Node is EndElement 'Scopes'
function ReadAndApplyv4Scopes()
{
WriteTraceMessage "Entered ReadAndApplyv4Scopes"
WriteTraceMessage "Input v4 Scopes: $script:scopesToBeImported"
#Get all the existings v4 scopes on the destination machine
$script:Existingv4Scopes = GetAllScopes $true
WriteTraceMessage "Existing v4 scopes on destination are:"
if ($global:TraceMessage) { $script:Existingv4Scopes }
while ($script:reader.Read()) { #Reader is at present on Scopes start element - move it to Scope start element
if ($script:reader.IsStartElement($ScopeElement)) {
ReadAndApplyv4Scope
}
else { break }
}
}
#While entring node is startElement 'Filter' / While leaving Node is EndElement 'Filter'
function ReadAndApplyFilter()
{
$errNte = @(); $errTE = $null
$mandatory = @{}; $optional = @{}
$script:reader.Read() > $null #current node is 'Filter' move it to next node
GenericXmlReader $mandatory $FilterPropertiesMandatory $optional $FilterPropertiesOptional
#$mandatory | ft; $optional | ft
$temp = ExecuteCmdlet -CmdletName Add-DhcpServerv4Filter -MandatoryParams $mandatory -OptionalParams $optional -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
}
# All the Filters on the target machine will be deleted
# If While entring the function, the StartElement is 'Filters' then all the Filters elements under it would be imported AND while leaving the function, the node is EndElement 'Filters'
function ReadAndApplyFilters()
{
$errNte = @()
$localEV = @()
$errTE = $null
WriteTraceMessage $_system_translations.Ver_Import_Server_Filter
Write-Verbose $_system_translations.Ver_Import_Server_Filter_Del
#Get & Delete all the existing Filters for v4Server on targetServer
$GetFilterCmdlet = ExecuteCmdlet -CmdletName Get-DhcpServerv4Filter -Nte ([ref]$errNte) -DontRun
$RemoveFilterCmdlet = ExecuteCmdlet -CmdletName Remove-DhcpServerv4Filter -Nte ([ref]$errNte) -DontRun
$pipelineCmdlet = "$GetFilterCmdlet | $RemoveFilterCmdlet"
WriteTraceMessage "Running Cmdlet: $pipelineCmdlet"
try { Invoke-Expression $pipelineCmdlet }
catch { PostNteObject $_ } #catch the TE & post it as NTE
PostNteObject($localEV)
if ($script:reader.IsStartElement($FiltersElement)) { #If Filters start element is present, import all the Filter elements under it
Write-Verbose $_system_translations.Ver_Import_Server_Filter
$script:reader.Read() > $null #Reader is at present on Filters start element - move it to next (Allow) start element
[bool]$allowFilterList = $script:reader.ReadElementContentAsBoolean() #Read Allow element
[bool]$denyFilterList = $script:reader.ReadElementContentAsBoolean() #Read Deny element
$temp = ExecuteCmdlet -CmdletName Set-DhcpServerv4FilterList -OptionalParams @{"Allow"=$allowFilterList;"Deny"=$denyFilterList} -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject($errTE); PostNteObject($errNte)
while ($script:reader.IsStartElement($FilterElement)) #If there are filter elements - import them
{
ReadAndApplyFilter
$script:reader.Read() > $null #reader is at present at Filter end element - move it to next node
}
$script:reader.Read() > $null #Move to element after Filters End element
}
}
#While entring node is startElement 'StatelessStore' / While leaving Node is EndElement 'StatelessStore'
function ReadAndApplyStatelessStore([string]$Prefix="")
{
[HashTable]$optionalParam = $null
$errNte = @()
$errTE = $null
if (IsNullOrEmptyString $Prefix) { WriteTraceMessage "Importing Server level Stateless"; $optionalParam = $null }
elseif (!(IsNullOrEmptyString $Prefix)) { WriteTraceMessage ("Importing scope={0} level Stateless" -f $Prefix); $optionalParam = @{"Prefix" = $Prefix} }
$script:reader.Read() > $null #Move reader to 'Enabled' node
[bool]$enabled = $script:reader.ReadElementContentAsBoolean()
$purgeInterval = $script:reader.ReadElementString("PurgeInterval");
$mandatory = @{ "Enabled"=$enabled; "PurgeInterval"=$purgeInterval }
[TimeSpan]$timeSpan = $purgeInterval
if ($timeSpan.TotalSeconds -ne 0) { #If PurgeInterval is 0, dont set it since its an error
$temp = ExecuteCmdlet -CmdletName Set-DhcpServerv6StatelessStore -MandatoryParams $mandatory -OptionalParams $optionalParam -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject($errTE); PostNteObject($errNte)
}
}
#While entring node is startElement 'IPv4' / While leaving Node is EndElement 'IPv4'
function ImportDhcpv4Server()
{
# ReadAndApplyClasses, ReadAndApplyOptionDefintions, ReadAndApplyv4Scopes will always be called
# ReadAndApplyServerSetting, ReadAndApplyOptionValues, ReadAndApplyPolicies, ReadAndApplyFilters will be called only for CompleteServer Import
WriteTraceMessage "Entered ImportDhcpv4Server"
$script:reader.Read() > $null #Move to element after IPv4 element
# Import the server setting only if import Mode is CompleteDhcpServer
if ($script:ImportSetting -eq $CompleteDhcpServer) {
ReadAndApplyServerSetting
#Current Node will be element after ActivatePolicies
}
else {
$script:reader.ReadToFollowing($NpsUnreachableActionElement) > $null # Move to NpsUnreachableActionElement start node
$script:reader.Skip() # Move to element after NpsUnreachableActionElement end node
if ($script:reader.IsStartElement($ActivatePoliciesElement)) { # ActivatePoliciesElement is an optional element, if it is present, move past it
$script:reader.Skip() # Move to element after ActivatePolicies end node
}
WriteTraceMessage ("Skipping v4ServerSetting to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
}
#If there is a Classes Node, import all v4 Classes
if ($script:reader.IsStartElement($ClassesElement)) {
ReadAndApplyClasses $true
$script:reader.Read() > $null #Move to element after Classes End element
}
#If there is a OptionDefinitions Node, import all v4 OptDefs
if ($script:reader.IsStartElement($OptDefsElement)) {
ReadAndApplyOptionDefintions $true
$script:reader.Read() > $null #Move to element after OptionDefinition End element
}
#If there is a Policies Node and CompleteDhcpServer is getting imported, import all Policies @ v4Server Level
if ($script:ImportSetting -eq $CompleteDhcpServer) {
ReadAndApplyPolicies
}
else {
if ($script:reader.IsStartElement($PoliciesElement)) {
$script:reader.Skip() #Move to element after Policies End element
WriteTraceMessage ("Skipping v4 Policies to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
}
}
#If there is a OptionValues Node and CompleteDhcpServer is getting imported, import all v4 OptValues @ v4Server Level
if ($script:ImportSetting -eq $CompleteDhcpServer) {
ReadAndApplyOptionValues $true
}
else {
if ($script:reader.IsStartElement($OptValuesElement)) {
$script:reader.Skip() #Move to element after OptionValues End element
WriteTraceMessage ("Skipping v4 OptionValues to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
}
}
#If there is a Filters Node and CompleteDhcpServer is getting imported, import all Filters @ v4Server Level
if ($script:ImportSetting -eq $CompleteDhcpServer) {
ReadAndApplyFilters
}
else {
if ($script:reader.IsStartElement($FiltersElement)) {
$script:reader.Skip() #Move to element after Filters End element
WriteTraceMessage ("Skipping v4 Filters to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
}
}
#If there is a Scopes Node, import all (or particular) v4 Scopes
if ($script:reader.IsStartElement($ScopesElement)) {
if (!${ServerConfigOnly}) { # Import Scope Nodes if ServerConfigOnly is not given
ReadAndApplyv4Scopes
$script:reader.Read() > $null #Move to element after Scopes End element
}
else {
$script:reader.Skip() #Move to element after Scopes End element
WriteTraceMessage ("ServerConfigOnly parameter was provided: Skipped v4 Scopes node to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
}
}
}
#While entring node is startElement 'Lease' / While leaving Node is EndElement 'Lease'
function ReadAndApplyv6Lease([string]$Prefix)
{
$errNte = @(); $errTE = $null
$mandatory = @{}; $optional = @{}
$script:reader.Read() > $null #current node is 'Lease' move it to next node
GenericXmlReader $mandatory $Leasev6PropertiesMandatory $optional $Leasev6PropertiesOptional
#$mandatory | ft; $optional | ft
$temp = ExecuteCmdlet -CmdletName Add-DhcpServerv6Lease -MandatoryParams $mandatory -OptionalParams $optional -Nte ([ref]$errNte) -TE ([ref]$errTE)
#If error returned is 'Client already exist (20014)', dont post the error since for reservation, the client lease already exist and adding it will give 20014 error
if ((NotNull $errTE) -and ($errTE.Exception -is [Microsoft.Management.Infrastructure.CimException]) -and ($errTE.Exception.ErrorData.error_Code -eq 20014)) { return }
if ((NotNull $errNte) -and ($errNte.Count -gt 0) -and ($errNte[0].Exception.ErrorData.error_Code -eq 20014)) { return }
PostNteObject $errTE
PostNteObject $errNte
}
#While entring node is startElement 'Leases' / While leaving Node is EndElement 'Leases'
function ReadAndApplyv6Leases([string] $Prefix="")
{
WriteTraceMessage ($_system_translations.Ver_Import_Scope_Leases -f $Prefix)
Write-Verbose ($_system_translations.Ver_Import_Scope_Leases -f $Prefix)
while ($script:reader.Read()) { #Reader is at present on Leases start element - move it to Lease start element
if ($script:reader.IsStartElement($LeaseElement)) {
ReadAndApplyv6Lease $Prefix
}
else { break }
}
}
#While entring node is startElement 'Scope' / While leaving Node is EndElement 'Scope'
function ReadAndApplyv6Scope()
{
WriteTraceMessage "Entered ReadAndApplyv6Scope"
$errNte = @(); $errTE = $null
$mandatory = @{}; $optional = @{}
$script:reader.Read() > $null #current node is 'Scope' move it to next node
GenericXmlReader $mandatory $Scopev6PropertiesMandatory $optional $Scopev6PropertiesOptional
#$mandatory | ft; $optional | ft
$currentScopeId = $mandatory["Prefix"]
$script:ImportFilev6Scopes += $currentScopeId
WriteTraceMessage "Current ImportFile v6Scope is $currentScopeId"
#If !CompleteServerImport AND ImportFileScope is not part of inputScope List, skip to end Scope element & return
#If ImportFileScope exists on destination
#if ScopeOverwrite and lease is given, delete the scope and then Add it
#if ScopeOverwrite is given, update the scope
#If ScopeOverwrite is not given, skip to next element
#Delete and add all the sub-elements of the scope
#If ImportFileScope does not exist on destination
#Add the scope and all it sub-element
if ($script:ImportSetting -ne $CompleteDhcpServer) {
#One of more v6scopes given to be imported
#Check if ImportFile current v6scope is part of input v6scope list
#If not, skip to end scope element for current scope
if ($script:prefixesToBeImported -notcontains $currentScopeId) {
$script:reader.ReadToNextSibling($ScopeElement) > $null #Since there is no sibling at this level, it will move to end element of parent node of current node
WriteTraceMessage ("Current ImportFile scope $currentScopeId not part of input scope List. Skipping to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
return;
}
}
$toAdd = $false; $toUpdate = $false; $toDeleteScopeSubElement = $false
if (IsConflictingv6Scope $currentScopeId)
{
#Conflicting v6 Scope is present
if (${ScopeOverwrite} -and ${Leases}) { #Both ScopeOverwrite and Leases are given, delete and then add the scope
Write-Verbose ($_system_translations.Ver_Import_Scope_Exists_3 -f $currentScopeId,$script:DhcpServerName)
#Remove the v6 scope on the target machine
ExecuteCmdlet -CmdletName "Remove-DhcpServerv6Scope -Prefix $currentScopeId -Force" -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
$toAdd = $true
}
elseif (${ScopeOverwrite}) { #Only ScopeOverwrite is given
$toUpdate = $true
$toDeleteScopeSubElement = $true
Write-Verbose ($_system_translations.Ver_Import_Scope_Exists_1 -f $currentScopeId,$script:DhcpServerName)
}
else { #ScopeOverwrite is not given
#Move to scope end element []
Write-Warning ($_system_translations.War_Import_Scope_Exists_2 -f $currentScopeId,$script:DhcpServerName)
$script:reader.ReadToNextSibling($ScopeElement) > $null #Since there is no sibling at this level, it will move to end element of parent node of current node
WriteTraceMessage ("Current ImportFile v6scope $currentScopeId already present on destination. Skipping to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
return;
}
}
else
{
#No conflicting scope found - Add the scope
$toAdd = $true
}
WriteTraceMessage ($_system_translations.Ver_Import_Scope -f $currentScopeId, $script:DhcpServerName)
Write-Verbose ($_system_translations.Ver_Import_Scope -f $currentScopeId, $script:DhcpServerName)
if ($toUpdate) { #Update the current ImportFile v6Scope on the target machine
$cmdlet = "Set-DhcpServerv6Scope"
WriteTraceMessage "Updating (SET) the Scope"
}
elseif ($toAdd) { #Add the current ImportFile v6Scope on the target machine
$cmdlet = "Add-DhcpServerv6Scope"
WriteTraceMessage "Adding the v6 Scope"
}
#Add/Set the current ImportFile Scope
$temp = ExecuteCmdlet -CmdletName $cmdlet -MandatoryParams $mandatory -OptionalParams $optional -Nte ([ref]$errNte) -TE ([ref]$errTE)
PostNteObject $errTE; PostNteObject $errNte
#If Add scope fails, no need to process further
if ($toAdd -and ((NotNull $errTE) -or ($errNte.Count -gt 0))) {
WriteTraceMessage "ReadAndApplyv6Scope: Add v6Scope failed -- existing the function" $true
return
}
ImportDhcpv6ScopeSubElements $currentScopeId $toDeleteScopeSubElement
}
function ImportDhcpv6ScopeSubElements([string] $Prefix, [bool] $ToDeleteScopeSubElement=$true)
{
WriteTraceMessage ("ImportDhcpv6ScopeSubElement: Prefix= {0}, DeleteSubElement= {1}" -f $ScopeId,$ToDeleteScopeSubElement)
#If there is a ExclusionRanges Node, import all v6 ExclusionRanges for this scope
ReadAndApplyExclusionRanges $false $Prefix $ToDeleteScopeSubElement
#If there is a OptionValues Node, import all v6 OptValues for this scope
ReadAndApplyOptionValues $false $Prefix $ToDeleteScopeSubElement
#If there is a Reservations Node, import all v6 Reservation for this scope
ReadAndApplyReservations $false $Prefix $ToDeleteScopeSubElement
#If there is a Stateless Node, import the Stateless config for this scope
if ($script:reader.IsStartElement($StatelessElement)) {
ReadAndApplyStatelessStore $Prefix
$script:reader.Read() > $null #Move to element after Stateless End element
}
#If there is a Leases Node and Leases switch parameter is given, import all v6 Leases for this scope
if ($script:reader.IsStartElement($LeasesElement)) {
if (!($script:reader.IsEmptyElement)) {
if (${Leases}) {
ReadAndApplyv6Leases $Prefix
$script:reader.Read() > $null #Move to element after Leases End element
}
else {
$script:reader.Skip() #Move to element after Leases End element
WriteTraceMessage ("Skipping v6 Leases to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
}
}
else {
WriteTraceMessage "Empty Leases element ..."
$script:reader.Read() > $null #Empty element - move to element after Leases empty element
}
}
}
#While entring node is startElement 'Scopes' / While leaving Node is EndElement 'Scopes'
function ReadAndApplyv6Scopes()
{
WriteTraceMessage "Entered ReadAndApplyv6Scopes"
WriteTraceMessage "Input v6 Scopes: $script:prefixesToBeImported"
#Get all the existings v6 scopes on the destination machine
$script:Existingv6Scopes = GetAllScopes $false
WriteTraceMessage "Existing v6 scopes on destination are:"
if ($global:TraceMessage) { $script:Existingv6Scopes }
while ($script:reader.Read()) { #Reader is at present on Scopes start element - move it to Scope start element
if ($script:reader.IsStartElement($ScopeElement)) {
ReadAndApplyv6Scope
}
else { break }
}
}
#While entring node is startElement 'IPv6' / While leaving Node is EndElement 'IPv6'
function ImportDhcpv6Server()
{
# ReadAndApplyClasses, ReadAndApplyOptionDefintions, ReadAndApplyv6Scopes will always be called
# ReadAndApplyOptionValues, ReadAndApplyStatelessStore will be called only for CompleteServer Import
WriteTraceMessage "Entered ImportDhcpv6Server"
$script:reader.Read() > $null #Move to element after IPv6 element
#If there is a Classes Node, import all v6 Classes
if ($script:reader.IsStartElement($ClassesElement)) {
ReadAndApplyClasses $false
$script:reader.Read() > $null #Move to element after Classes End element
}
#If there is a OptionDefinitions Node, import all v6 OptDefs
if ($script:reader.IsStartElement($OptDefsElement)) {
ReadAndApplyOptionDefintions $false
$script:reader.Read() > $null #Move to element after OptionDefinition End element
}
#If there is a OptionValues Node and CompleteDhcpServer is getting imported, import all v6 OptValues @ v6Server Level
if ($script:ImportSetting -eq $CompleteDhcpServer) {
ReadAndApplyOptionValues $false
}
else {
if ($script:reader.IsStartElement($OptValuesElement)) {
$script:reader.Skip() #Move to element after OptionValues End element
WriteTraceMessage ("Skipping v6 OptionValues to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
}
}
#If there is a Stateless Node and CompleteDhcpServer is getting imported, import the Stateless config
if ($script:reader.IsStartElement($StatelessElement)) {
if ($script:ImportSetting -eq $CompleteDhcpServer) {
ReadAndApplyStatelessStore
$script:reader.Read() > $null #Move to element after Stateless End element
}
else {
$script:reader.Skip() #Move to element after Stateless End element
WriteTraceMessage ("Skipping v6 Stateless to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
}
}
#If there is a Scopes Node, import v6 Scopes
if ($script:reader.IsStartElement($ScopesElement)) {
if (!${ServerConfigOnly}) { # Import Scope Nodes if ServerConfigOnly is not given
ReadAndApplyv6Scopes
$script:reader.Read() > $null #Move to element after Scopes End element
}
else {
$script:reader.Skip() #Move to element after Scopes End element
WriteTraceMessage ("ServerConfigOnly parameter was provided: Skipped v6 Scopes node to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
}
}
}
# Read the Xml file and imports all the relevant settings
function ImportDhcpServerFromFile()
{
[String[]] $script:ImportFilev4Scopes = @()
[String[]] $script:ImportFilev6Scopes = @()
#Move to root node
$script:reader.MoveToContent() > $null #Current node is now root (DHCPServer) node
$script:reader.Read() > $null #Move to MajorVersion element
#Reads the version info and checks if ImportFile can be imported to destinatin machine
#After this call, reader is positioned at start element after 'MinorVersion'
ReadAndVerifyVersionInfo
Write-Verbose ($_system_translations.Ver_Import_Started -f $script:DhcpServerName, $script:ImportFile)
WriteTraceMessage "ImportSetting is $script:ImportSetting [CompleteDhcpServer=0, SpecificV4AndV6Scopes=1, SpecificV4Scopes=2, SpecificV6Scopes=3"
if ($script:reader.IsStartElement($IPv4Element)) { #There is IPv4 Node
if ($script:ImportSetting -ne $SpecificV6Scopes) { #User has asked for v4 Scopes import
ImportDhcpv4Server
$script:reader.Read() > $null #Move to element after IPv4 End element
}
else {
#User has not asked for v4 scopes imports
#Move reader to start element after
$script:reader.Skip() #This call will move the Reader to element after the End Node of the current node
WriteTraceMessage ("Skipping the IPv4 Node since ImportSetting is SpecificV6Scope to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
}
}
if ($script:reader.IsStartElement($IPv6Element)) { #There is a IPv6 Node
if ($script:ImportSetting -ne $SpecificV4Scopes) { #User has asked for v6 Scopes import
ImportDhcpv6Server
$script:reader.Read() > $null #Move to element after IPv6 End element
}
else {
#User has not asked for v6 scopes imports
#Move reader to start element after
$script:reader.Skip()
WriteTraceMessage ("Skipping the IPv6 Node since ImportSetting is SpecificV4Scope to {1}({0})" -f $script:reader.NodeType, $script:reader.Name) $true
}
}
#Give NTE for all the v4/v6 scopes which were given as input but were not part of Import File
foreach ($scope in $script:scopesToBeImported) {
if ($script:ImportFilev4Scopes -notcontains $scope) {
PostNteString ($_system_translations.ErrInputScopeNotInImportFile -f $scope, $script:ImportFile) "ObjectNotFound" "ObjectNotFound" $scope
}
}
foreach ($scope in $script:prefixesToBeImported) {
if ($script:ImportFilev6Scopes -notcontains $scope) {
PostNteString ($_system_translations.ErrInputScopeNotInImportFile -f $scope, $script:ImportFile) "ObjectNotFound" "ObjectNotFound" $scope
}
}
}
#endregion
#region XML Util Functions
# Generic XML Writer - writes the Key of the HashTable as ElementName and Value of the HashTable as ElementValue of the XML
# Takes 2 HashTables and 2 Arrays of Xml Element names - these corresponds to Mandatory and Optional elements of XML
# Since there is no way to enumeration HashTable in a desired sequence (Note HashTable enumeration is based on its key assignment logic)
# a separate array is maintained for the name of the keys (Xml Element name) in the HashTable
# XML is written as per the sequence of this array
# Fluses the XML at the end so that in-memory XML data is written to the file
function GenericXmlWriter([HashTable]$mandatory, [String[]] $mandatoryKeys, [HashTable]$optional=@(), [String[]] $optionalKeys)
{
foreach ($key in $mandatoryKeys)
{
foreach($value in $mandatory[$key]){
$script:writer.WriteElementString($key, $value);
}
}
foreach ($key in $optionalKeys)
{
if ($optional.Contains($key)){
foreach($value in $optional[$key]){
$script:writer.WriteElementString($key, $value);
}
}
}
$script:writer.Flush()
}
# Generic XML Reader - Reads the XML and populates the Hashtable. XmlElementName and XmlElementValue goes as Key and Value respectively for the HashTable
# XML is read in the same order as the corresponding array for mandatory/optional hashtable
# XML with multiple sequential elements with same name is taken care of
function GenericXmlReader([HashTable]$mandatory, [String[]] $mandatoryKeys, [HashTable]$optional=@(), [String[]] $optionalKeys)
{
foreach ($key in $mandatoryKeys)
{
[string]$singleValue = $null
[array]$multiValue = $null
$isMultiValue = $false
$singleValue = $script:reader.ReadElementString($key);
while($script:reader.IsStartElement($key)) { #This is a multi value case
if (!($isMultiValue)) { $multiValue += $singleValue }
$multiValue += $script:reader.ReadElementString($key);
$isMultiValue = $true
}
if ($isMultiValue) { $mandatory[$key] = $multiValue } else { $mandatory[$key] = $singleValue }
}
foreach ($key in $optionalKeys)
{
[string]$singleValue = $null
[array]$multiValue = $null
$isMultiValue = $false
if ($script:reader.IsStartElement($key)) {
$singleValue = $script:reader.ReadElementString($key);
while ($script:reader.IsStartElement($key)) { #This is a multi value case
if (!($isMultiValue)) { $multiValue += $singleValue }
$multiValue += $script:reader.ReadElementString($key);
$isMultiValue = $true
}
if ($isMultiValue) { $optional[$key] = $multiValue } else { $optional[$key] = $singleValue }
}
}
}
#endregion
#region UtilFunctions
# ExecuteCmdlet function is used either to execute a given cmdlet or return the full formed cmdlet expression
# [Later is used when more than 1 cmdlet full expression is needed for running them in pipeline]
# $CmdletName : Name of the cmdlet
# MandatoryParams : Mandatory parameters needs to be passed to Cmdlet
# OptionalParams : Optional parameters needs to be passed to Cmdlet
# SwitchParams : Switch parameters to be passed to Cmdlet
# Nte : [Out parameters] If given and NTE occurs while executing th cmdlets, populated with the NTE(s) occurred
# TE : [Out parameters] If given and TE occurs while executing th cmdlets, populated with the TE occurred, else TE is thrown back to caller
# $DontRun : Switch parameter - if given the cmdlet is not run - instead its constructed and returned
function ExecuteCmdlet([string]$CmdletName, [HashTable]$MandatoryParams=$null, [HashTable]$OptionalParams=$null, [HashTable]$SwitchParams=$null, [ref]$Nte, [ref]$TE, [Switch]$DontRun)
{
try
{
$localEV = @()
$result = $null
$cmdletToRun = $cmdletName
$displayStr = $cmdletName
if ($null -ne $Nte){
$Nte.Value = @()
}
if ($null -ne $TE){
$TE.Value = $null
}
if ($null -ne $mandatoryParams){
foreach ($paramKey in $mandatoryParams.Keys){
$cmdletToRun += " -$paramKey `$mandatoryParams[`"$paramKey`"]"
$displayStr += " -$paramKey $(__ParamToString $mandatoryParams[$paramKey])"
}
}
if ($null -ne $optionalParams){
foreach ($paramKey in $optionalParams.Keys){
if ($null -ne $optionalParams[$paramKey]){
$cmdletToRun += " -$paramKey `$optionalParams[`"$paramKey`"]"
$displayStr += " -$paramKey $(__ParamToString $optionalParams[$paramKey])"
}
}
}
if ($null -ne $SwitchParams){
foreach ($paramKey in $SwitchParams.Keys){
if (($null -ne $SwitchParams[$paramKey]) -and ($true -eq $SwitchParams[$paramKey])) {
$cmdletToRun += " -$paramKey"
$displayStr += " -$paramKey"
}
}
}
if (!(IsNullOrEmptyString ${ComputerName})) {
$cmdletToRun += " -ComputerName ${ComputerName}"
$displayStr += " -ComputerName ${ComputerName}"
}
if ($null -ne ${CimSession}) {
$cmdletToRun += " -CimSession $(${CimSession}.ComputerName)"
$displayStr += " -CimSession $(${CimSession}.ComputerName)"
}
if ($null -ne $Nte) {
$cmdletToRun += " -EV +localEV"
$displayStr += " -EV +localEV"
}
$cmdletToRun += " 2> `$null"
$displayStr += " 2> `$null"
if ($DontRun) { WriteTraceMessage "Cmdlet string to Return: $displayStr" }
else { WriteTraceMessage "Running Cmdlet: $displayStr" }
if ($DontRun) { return $displayStr }
else {
$result = Invoke-Expression $cmdletToRun
if ($null -ne $Nte) {
$Nte.value = $localEV
}
return $result
}
}
catch
{
if ($null -ne $TE) {
$TE.value = $_
}
else{
throw
}
}
}
# Helper function for ExecuteCmdlet - Used for display purpose or when DontRun is given
function __ParamToString($obj)
{
[String]$str = $null
if($null -ne $obj) {
if(($obj.GetType().Name -eq "Object[]") -or ($obj.GetType().Name -eq "String[]")){
if($obj.count -gt 0) {
$str = "@(`"$($obj[0])`""
for($i=1; $i -lt $obj.count; $i++){
$str += ", `"$($Obj[$i])`""
}
$str+=")"
} else {
$str="@()"
}
} elseif($obj.GetType().Name -eq "String"){
$str = "`"$obj`""
} elseif($obj.GetType().Name -eq "Boolean"){
if($true -eq $obj ) {
$str = "`$true"
} else {
$str = "`$false"
}
} else {
$str = "$obj"
}
}
return $str
}
#Input $fileName can be a relative or Full Path
#The function returns a canonical fully qualified path
function GetFullyQualifiedPath([string] $fileName)
{
[string] $temp = $fileName
try
{
if ([System.IO.Path]::IsPathRooted($fileName)) {
#This is a complete path
#Get canonical path
$fullPath = [System.IO.Path]::GetFullPath($fileName)
}
else {
#It is a relative path - add current directory to it
$temp = ($pwd.Path) + "\" + $fileName
#Get canonical path
$fullPath = [System.IO.Path]::GetFullPath($temp)
}
}
catch
{
ThrowTEString($_system_translations.ErrFilePathInvalid -f $temp,$_.ToString()) $EC_InvalidArgument $EC_InvalidArgument $temp
}
return $fullPath
}
# If $ComputerName is empty or null string, $script:DhcpServerName is set to the localHost name
# Else copies $ComputerName to $script:DhcpServerName
function GetComputerName ([string]$ComputerName) {
if (!(IsNullOrEmptyString($ComputerName))) {
$script:DhcpServerName = $ComputerName
} else {
$script:DhcpServerName = [System.Net.Dns]::GetHostName()
}
}
# Returns $true if $DhcpServerVersion represents a DhcpVersion equal to or greater than WIN8 (MajorVersion=6, MinorVersion=2)
function IsWindows8OrHigher($DhcpServerVersion)
{
if (($DhcpServerVersion.MajorVersion -gt $Win8MajorVersion) -or (($DhcpServerVersion.MajorVersion -eq $Win8MajorVersion) -and ($DhcpServerVersion.MinorVersion -ge $Win8MinorVersion))) {
return $true
}
else { return $false }
}
# Returns $true if $DhcpServerVersion represents a DhcpVersion equal to or greater than WIN2K8-R2 (MajorVersion=6, MinorVersion=1)
function IsWindows2008R2OrHigher($DhcpServerVersion)
{
if (($DhcpServerVersion.MajorVersion -gt $Win8MajorVersion) -or (($DhcpServerVersion.MajorVersion -eq $Win8MajorVersion) -and ($DhcpServerVersion.MinorVersion -ge $Win2K8R2MinorVersion))) {
return $true
}
else { return $false }
}
# Return $true if given variable is $null
function IsNull($var) { return ($null -eq $var) }
# Return $true if given variable is NOT $null
function NotNull($var) { return ($null -ne $var) }
# Return $true if given input string is $null or EmptyString ("")
function IsNullOrEmptyString([string] $str) { return ($null -eq $str -or "" -eq $str) }
# Throws TE or Post NTE for Export
function ExportDhcpServer([System.Management.Automation.ErrorRecord]$err, [bool]$isTE)
{
if (!$isTE)
{
if ($err.Exception -is [Microsoft.Management.Infrastructure.CimException]) {
#This is CimException returned by DHCP Cmdlets
$errMsg = ($_system_translations.GenericErrorMsg -f $err.ToString(), $err.Exception.ErrorData.error_WindowsErrorMessage, $err.Exception.ErrorData.error_Code)
$err.ErrorDetails = $errMsg
$PSCmdlet.WriteError($err)
}
else {
$PSCmdlet.WriteError($err)
}
}
else
{
$PSCmdlet.ThrowTerminatingError($err)
}
}
# Throws TE or Post NTE for Import
function ImportDhcpServer([System.Management.Automation.ErrorRecord]$err, [bool]$isTE)
{
if (!$isTE)
{
if ($err.Exception -is [Microsoft.Management.Infrastructure.CimException]) {
#This is CimException returned by DHCP Cmdlets
$errMsg = ($_system_translations.GenericErrorMsg -f $err.ToString(), $err.Exception.ErrorData.error_WindowsErrorMessage, $err.Exception.ErrorData.error_Code)
$err.ErrorDetails = $errMsg
$PSCmdlet.WriteError($err)
}
else {
$PSCmdlet.WriteError($err)
}
}
else
{
if ($BackupTaken) {
Write-Warning ($_system_translations.War_RestoreDhcpDatabase -f ${BackupPath})
}
$PSCmdlet.ThrowTerminatingError($err)
}
}
# Prepares a ErrorRecord Object and calls ExportDhcpServer/ImportDhcpServer to Post NTE
function PostNteString([string]$errMessage, [string] $errorId=$EC_InvalidOperation, [System.Management.Automation.ErrorCategory]$errorCategory=$EC_InvalidOperation, [Object] $targetObject=$null)
{
$exception = New-Object System.Exception $errMessage
$err = New-Object System.Management.Automation.ErrorRecord (
$exception,
$errorId,
$errorCategory,
$targetObject
)
if ($script:IsExport) { ExportDhcpServer $err $false }
else { ImportDhcpServer $err $false }
}
# Prepares a ErrorRecord Object and calls ExportDhcpServer/ImportDhcpServer to throw TE
function ThrowTEString([string]$errMessage, [string] $errorId=$EC_InvalidOperation, [System.Management.Automation.ErrorCategory]$errorCategory=$EC_InvalidOperation, [Object] $targetObject=$null)
{
$exception = New-Object System.Exception $errMessage
$err = New-Object System.Management.Automation.ErrorRecord (
$exception,
$errorId,
$errorCategory,
$targetObject
)
if ($script:IsExport) { ExportDhcpServer $err $true }
else { ImportDhcpServer $err $true }
}
# Pass the ErrorRecord objects as returned as a result of executing internal cmdlets to ExportDhcpServer/ImportDhcpServer to Post NTE
function PostNteObject($errorObj)
{
if (NotNull $errorObj ) {
if (($errorObj -is [System.Collections.ArrayList]) -or ($errorObj -is [Array])) {
foreach ($err in $errorObj){
if ($script:IsExport) { ExportDhcpServer $err $false}
else { ImportDhcpServer $err $false}
}
}
else {
if ($script:IsExport) { ExportDhcpServer $errorObj $false}
else { ImportDhcpServer $errorObj $false}
}
}
}
# Helper function to write trace messages only when $global:TraceMessage is set to $true
function WriteTraceMessage([string] $message, [bool]$isRed=$false) {
if ($global:TraceMessage) {
Write-Host -ForegroundColor ([System.ConsoleColor]::Cyan) $message
}
}
# Helper function to write trace messages for different Export variables
function WriteExportInputValue()
{
WriteTraceMessage "File : ${File}"
WriteTraceMessage "RFile : $script:ExportFile"
WriteTraceMessage "ScopeId : ${ScopeId}"
WriteTraceMessage "Prefix : ${Prefix}"
WriteTraceMessage "Leases : ${Leases}"
WriteTraceMessage "ComputerName : ${ComputerName}"
WriteTraceMessage "RComputerName : $script:DhcpServerName"
if (NotNull ${CimSession}) {$cimSession = ${CimSession}.ComputerName } else { $cimSession = "NULL" }
WriteTraceMessage "CimSession : $cimSession"
WriteTraceMessage "ProcessEntryCount: $script:ProcessEntryCount"
WriteTraceMessage ""
}
#endregion
#region LocalizedString
# Localized strings
data _system_translations {
ConvertFrom-StringData @'
# fallback text goes here
#Error Msg
ExportedFileExists= File {0} already exists.
InvalidIPv4ScopeAddress= ScopeID {0} is not a valid IPv4 address.
InvalidIPv6ScopeAddress= Prefix {0} is not a valid IPv6 address.
NothingToExport= Nothing is exported. File {0} is not created.
ImportedVersionMismatch= The functionality is not available on this server version. Version of DHCP server is {0}.{1}.
ImportedFileVersionMismatch= The DHCP server version {0}.{1} is not compatible with the file version {2}.{3}.
ImportFileDoesNotExist= File {0} does not exists.
ErrInputScopeNotInImportFile= Input scope {0} is not present in the specified file {1}.
GenericErrorMsg= {0} : {1}({2})
ErrXmlValidationFailed= XML schema validation for {0} failed. Please ensure that import file {0} is valid as per the XML schema in {1}. {2}
ErrServerConfigGivenWithScopePrefix= ScopeId/Prefix cannot be specified when ServerConfigOnly is specified.
ErrServerConfigGivenWithLeases= Leases cannot be specified when ServerConfigOnly is specified.
ErrServerConfigGivenWithScopeOverwrite= ScopeOverwrite cannot be specified when ServerConfigOnly is specified.
ErrFilePathInvalid= Invalid path {0}. {1}
#ShouldProcess/ShouldContinue Messages
Msg_Export_DhcpServer_1= The configuration (and leases) for the scope(s) {0} on server {1} will be exported to the file {2}.
Msg_Export_DhcpServer_2= The configuration (and leases) on server {0} will be exported to the file {1}.
Msg_Export_DhcpServer_3= The configuration for the scope(s) {0} on server {1} will be exported to the file {2}.
Msg_Export_DhcpServer_4= The configuration on server {0} will be exported to the file {1}.
Msg_Import_DhcpServer_1= The configuration (and leases) for following scopes will be imported from the file {0} to server {1}: {2}.{3}
Msg_Import_DhcpServer_2= The configuration (and leases) from the file {0} will be imported to server {1}.{2}
Msg_Import_DhcpServer_3= The configuration for following scopes will be imported from the file {0} to server {1}: {2}.{3}
Msg_Import_DhcpServer_4= The configuration from the file {0} will be imported to server {1}. {2}
ShoudContinueCaption= Confirm
ShoudContinueConfirmation= Do you want to perform this action?
#Export Verbose Msg
Ver_Export_Start= Exporting configuration from server {0} to file {1}.
Ver_Export_Classes= Exporting classes from server...
Ver_Export_OptDef= Exporting option definitions from server...
Ver_Export_Server_OptValue= Exporting server wide option values...
Ver_Export_Server_Pol_OptValue= Exporting server wide option values from policy {0}...
Ver_Export_Scope_OptValue= Exporting option values from scope {0}...
Ver_Export_Rsvation_OptValue= Exporting option values from reservation {0}...
Ver_Export_Scope_Pol_OptValue= Exporting option values from policy {0} of scope {1}...
Ver_Export_Server_Policy= Exporting server wide policies...
Ver_Export_Server_Filter= Exporting Link Layer Filters...
Ver_Export_Scope= Exporting scope {0} from server {1}...
Ver_Export_Scope_ExRanges= Exporting exclusion ranges from scope {0}...
Ver_Export_Scope_Policy= Exporting policies from scope {0}...
Ver_Export_Scope_Rsvation= Exporting reservations from scope {0}. This operation may take some time.
Ver_Export_Scope_ExRange= Exporting exclusion ranges from scope {0}...
Ver_Export_Scope_Lease= Exporting leases from scope {0}. This operation may take some time.
Ver_Export_End= Export operation on server {0} completed.
#Import Verbose Msg
Ver_Import_Started= Importing configuration on server {0} from file {1}.
Ver_Import_Backup= Dhcp Server database has been backed up at {0} on {1}.
Ver_Import_Classes= Importing classes on server...
Ver_Import_OptDef= Importing option definitions on server...
Ver_Import_Server_OptVal= Importing server wide option values...
Ver_Import_Server_Pol_OptVal= Importing server wide option values for policy {0}...
Ver_Import_Scope_OptVal= Importing option values for scope {0}...
Ver_Import_Rsvation_OptVal= Importing option values for reservation {0}...
Ver_Import_Scope__PolOptVal= Importing option values for policy {0} to scope {1}...
Ver_Import_Server_OptVal_Del= Deleting server wide option values...
Ver_Import_Scope_OptVal_Del= Deleting existing option values from scope {0}...
Ver_Import_Scope_ExRange= Importing exclusion ranges to scope {0}...
Ver_Import_Scope_ExRange_Del= Deleting existing exclusion ranges in scope {0}...
Ver_Import_Rsvation_OptVal_Del= Deleting existing option values on reservation {0}...
Ver_Import_Server_Policy= Importing server wide policies...
Ver_Import_Scope_Policy= Importing policies to scope {0}...
Ver_Import_Server_Policy_Del= Deleting server wide policies...
Ver_Import_Scope_Policy_Del= Deleting existing policies in scope {0}...
Ver_Import_Server_Filter_Del= Deleting link layer filters...
Ver_Import_Server_Filter= Importing link layer filters...
Ver_Import_Scope= Importing scope {0} on server {1}...
Ver_Import_Scope_Rsvation= Importing reservations to scope {0}. This operation may take some time.
Ver_Import_Scope_Leases= Importing leases to scope {0}. This operation may take some time.
Ver_Import_Scope_Del= Deleting existing scope {0} on server {1}...
Ver_Import_Scope_Rsvation_Del= Deleting existing reservations in scope {0}...
Ver_Import_End= Import operation on server {0} completed.
Ver_Import_Scope_Exists_1= Scope {0} exists on server {1}. This scope will be overwritten with data in the import file.
War_Import_Scope_Exists_2= Scope {0} exists on server {1}. This scope will not be imported.
Ver_Import_Scope_Exists_3= Scope {0} exists on server {1}. This scope will be deleted and imported from the data in the import file.
Ver_Import_ClassAlreadyExist= Class '{0}' of type {1} already exists on server {2} and will not be changed.
Ver_Import_OptDefAlreadyExist= Option definition {0} already exists on server {1} and will not be changed.
War_RestoreDhcpDatabase= To restore the DHCP server configuration to the previous state, restore the DHCP database from {0}.
War_ImportOptValueServerLevelWithoutValue= Server wide option value {0} was not imported on server {1} because it did not have any value associated with it.
War_ImportOptValueServerPolicyLevelWithoutValue= Server wide option value {0} for policy {1} was not imported on server {2} because it did not have any value associated with it.
War_ImportOptValueScopeLevelWithoutValue= Option value {0} for scope {1} was not imported on server {2} because it did not have any value associated with it.
War_ImportOptValueReservationLevelWithoutValue= Option value {0} for reservation {1} was not imported on server {2} because it did not have any value associated with it.
War_ImportOptValueScopePolicyLevelWithoutValue= Option value {0} for policy {1} of scope {2} was not imported on server {3} because it did not have any value associated with it.
'@
}
Import-LocalizedData -BindingVariable _system_translations -filename DhcpServerMigration.psd1
#endregion
#region Constants
#Constants used
New-Variable -Option constant -Name Win8MajorVersion -Value 6
New-Variable -Option constant -Name Win8MinorVersion -Value 2
New-Variable -Option constant -Name Win9MinorVersion -Value 3
New-Variable -Option constant -Name Win2K8R2MinorVersion -Value 1
New-Variable -Option constant -Name DhcpSchemaName -Value "http://schemas.microsoft.com/windows/DHCPServer"
New-Variable -Option constant -Name DhcpSchemaFile -Value ($env:windir + "\System32\WindowsPowerShell\v1.0\Modules\DhcpServer\DhcpServerSchema.xml")
New-Variable -Option constant -Name CompleteDhcpServer -Value 0
New-Variable -Option constant -Name SpecificV4AndV6Scopes -Value 1
New-Variable -Option constant -Name SpecificV4Scopes -Value 2
New-Variable -Option constant -Name SpecificV6Scopes -Value 3
New-Variable -Option constant -Name EC_ResourceExists -Value "ResourceExists"
New-Variable -Option constant -Name EC_InvalidArgument -Value "InvalidArgument"
New-Variable -Option constant -Name EC_InvalidOperation -Value "InvalidOperation"
New-Variable -Option constant -Name EC_ResourceUnavailable -Value "ResourceUnavailable"
#XML Tags
New-Variable -Option constant -Name XmlRootNode -Value "DHCPServer"
New-Variable -Option constant -Name MajorVersionElement -Value "MajorVersion"
New-Variable -Option constant -Name MinorVersionElement -Value "MinorVersion"
New-Variable -Option constant -Name IPv4Element -Value "IPv4"
New-Variable -Option constant -Name IPv6Element -Value "IPv6"
New-Variable -Option constant -Name ConflictDetAttemptsElement -Value "ConflictDetectionAttempts"
New-Variable -Option constant -Name NapEnabledElement -Value "NapEnabled"
New-Variable -Option constant -Name NpsUnreachableActionElement -Value "NpsUnreachableAction"
New-Variable -Option constant -Name ActivatePoliciesElement -Value "ActivatePolicies"
New-Variable -Option constant -Name ClassesElement -Value "Classes"
New-Variable -Option constant -Name ClassElement -Value "Class"
New-Variable -Option constant -Name OptDefsElement -Value "OptionDefinitions"
New-Variable -Option constant -Name OptDefElement -Value "OptionDefinition"
New-Variable -Option constant -Name OptValuesElement -Value "OptionValues"
New-Variable -Option constant -Name OptValueElement -Value "OptionValue"
New-Variable -Option constant -Name PoliciesElement -Value "Policies"
New-Variable -Option constant -Name PolicyElement -Value "Policy"
New-Variable -Option constant -Name FiltersElement -Value "Filters"
New-Variable -Option constant -Name FilterElement -Value "Filter"
New-Variable -Option constant -Name FilterListAllowElement -Value "Allow"
New-Variable -Option constant -Name FilterListDenyElement -Value "Deny"
New-Variable -Option constant -Name ScopesElement -Value "Scopes"
New-Variable -Option constant -Name ScopeElement -Value "Scope"
New-Variable -Option constant -Name IPRangesElement -Value "IPRanges"
New-Variable -Option constant -Name ExclusionRangesElement -Value "ExclusionRanges"
New-Variable -Option constant -Name IPRangeElement -Value "IPRange"
New-Variable -Option constant -Name StartIPRangeElement -Value "StartRange"
New-Variable -Option constant -Name EndIPRangeElement -Value "EndRange"
New-Variable -Option constant -Name ReservationsElement -Value "Reservations"
New-Variable -Option constant -Name ReservationElement -Value "Reservation"
New-Variable -Option constant -Name LeasesElement -Value "Leases"
New-Variable -Option constant -Name LeaseElement -Value "Lease"
New-Variable -Option constant -Name StatelessElement -Value "StatelessStore"
New-Variable -Option constant -Name StatelessEnabledElement -Value "Enabled"
New-Variable -Option constant -Name StatelessPurgeIntervalElement -Value "PurgeInterval"
$ClassPropertiesMandatory = @("Name", "Type", "Data")
$ClassPropertiesOptional = @("Description", "VendorId")
$OptDefPropertiesMandatory = @("Name", "OptionId", "Type", "MultiValued")
$OptDefPropertiesOptional = @("DefaultValue", "Description", "VendorClass")
$OptValuePropertiesMandatory = @("OptionId")
$OptValuePropertiesOptional = @("Value", "VendorClass", "UserClass")
$PolicyPropertiesMandatory = @("Name", "ProcessingOrder", "Enabled", "Condition")
$PolicyPropertiesOptional = @("Description", "VendorClass", "UserClass", "MacAddress", "ClientId", "RelayAgent", "CircuitId", "RemoteId", "SubscriberId", "Fqdn", "DnsSuffix")
$FilterPropertiesMandatory = @("List", "MacAddress")
$FilterPropertiesOptional = @("Description")
$Scopev4PropertiesMandatory = @("ScopeId", "Name", "SubnetMask", "StartRange", "EndRange", "LeaseDuration", "State", "Type", "MaxBootpClients", "NapEnable")
$Scopev4PropertiesOptional = @("Delay", "NapProfile", "Description", "ActivatePolicies", "SuperScopeName")
$Scopev6PropertiesMandatory = @("Prefix", "Name", "Preference", "State")
$Scopev6PropertiesOptional = @("PreferredLifeTime", "ValidLifeTime", "T1", "T2", "Description")
$ReservationPropertiesMandatory = @("Name", "IPAddress")
$ReservationPropertiesOptional = @("ClientId", "Type", "ClientDuid", "IAID", "Description")
$LeasePropertiesMandatory = @("IPAddress", "ScopeId", "ClientId", "AddressState", "ClientType", "NapCapable")
$LeasePropertiesOptional = @("DnsRR", "DnsRegistration", "LeaseExpiryTime", "ProbationEnds", "NapStatus", "HostName", "PolicyName", "Description")
$Leasev6PropertiesMandatory = @("IPAddress", "ClientDuid", "IAID", "AddressType")
$Leasev6PropertiesOptional = @("HostName", "LeaseExpiryTime", "Description")
#endregion
#region ScriptVariable
[bool]$global:TraceMessage = $false
#endregion
Set-StrictMode -Version 3
Export-ModuleMember Export-DhcpServer, Import-DhcpServer
--