ConvertDhcpLeaseToReservation.ps1


<#PSScriptInfo
 
.VERSION 2.4.0
 
.GUID 8bcade2e-0988-40d3-aa37-071a2f8b4c79
 
.AUTHOR Pavel_Kandratsyeu@outlook.com
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES DhcpServer, ThreadJob
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
 
.RELEASENOTES
#>


<#
.SYNOPSIS
Convert IpV4 lease to dhcp reservation.
.DESCRIPTION
The script searches a dhcp lease by IP or MAC address on all dhcp servers in Active Directory using ThreadJob and converts it to reservation. If dhcp server has a failover partner, the script notifies partner server too.
The script requires DHCP admin credentials to work.
#>



#requires -Version 3.0 -Modules DhcpServer, ThreadJob


[CmdletBinding(
    SupportsShouldProcess = $true,
    ConfirmImpact = 'High',
    DefaultParametersetName = 'ByIPAddress'
)]
param(
    [Parameter (
        Position = 0,
        Mandatory = $true,
        ValueFromPipeline = $true,
        ValueFromPipelineByPropertyName = $true,
        ParameterSetName = 'ByIPAddress'
    )]
    [Alias('IP')]
    [ValidateNotNullOrEmpty()]
    [string]
    $IpAddress,

    [Parameter (
        Position = 0,
        Mandatory = $true,
        ValueFromPipeline = $true,
        ValueFromPipelineByPropertyName = $true,
        ParameterSetName = 'ByMACAddress'
    )]
    [Alias('MAC')]
    [ValidateNotNullOrEmpty()]
    [string]
    $ClientId,

    [Parameter (
        Mandatory = $false
    )]
    [Alias('Server')]
    [ValidateNotNullOrEmpty()]
    [string[]]
    $ComputerName,

    [Parameter (
        Mandatory = $false
    )]
    [Alias('Notes')]
    [ValidateNotNullOrEmpty()]
    [string]
    $Description
)

begin
{
    $DhcpServers = Get-DhcpServerInDC
}
process
{
    switch ($PsCmdlet.ParameterSetName)
    {
        'ByIPAddress'
        {
            Write-Verbose -Message 'Parameter set ByIPAddress has been chosen.'
            $ScripBlock = {
                $VerbosePreference = $Using:VerbosePreference
                try
                {
                    Get-DhcpServerv4Lease -IPAddress $Using:IpAddress -ComputerName $Using:Server -ErrorAction Stop |
                    Add-Member -NotePropertyName PSComputerName -NotePropertyValue $Using:Server -Force -PassThru
                }
                catch
                {
                    Write-Verbose -Message "Get-DhcpServerv4Lease Failed: IPAddress = $Using:IpAddress; Server = $Using:Server; Exception = $($_.Exception.Message)"
                }
            }
        }

        'ByMACAddress'
        {
            Write-Verbose -Message 'Parameter set By has been chosen.'
            $ScripBlock = {
                Import-Module -Name DhcpServer
                $VerbosePreference = $Using:VerbosePreference
                Get-DhcpServerv4Scope -ComputerName $Using:Server |
                ForEach-Object -Process {
                    try
                    {
                        $ScopeId = $_.ScopeId
                        $_ |
                        Get-DhcpServerv4Lease -ClientId ($Using:ClientId).Trim().Replace(':', '-') -ComputerName $Using:Server -ErrorAction Stop |
                        Add-Member -NotePropertyName PSComputerName -NotePropertyValue $Using:Server -Force -PassThru
                    }
                    catch
                    {
                        Write-Verbose -Message "Get-DhcpServerv4Lease Failed: ClientId = $Using:ClientId; Sope = $ScopeId; Server = $Using:Server; Exception = $($_.Exception.Message)"
                    }
                }
            }
        }
    }

    Write-Verbose -Message 'Searching dhcp lease...'
    foreach ($server in $(if ($ComputerName) { $ComputerName } else { $DhcpServers.DNSname }))
    {
        $null = Start-ThreadJob -ScriptBlock $ScripBlock -ThrottleLimit 32
    }

    Write-Verbose 'Waiting jobs to complete...'
    $DhcpV4Lease = Get-Job |
    Receive-Job -Wait -AutoRemoveJob |
    Group-Object -Property IPAddress |
    ForEach-Object -Process { $_.Group | Select-Object -First 1 }

    if (-not $DhcpV4Lease)
    {
        Write-Warning -Message "Lease with Id '$(if($IpAddress){$IpAddress}else{$ClientId})' was not found. Try later."

        exit 0
    }

    $DhcpV4Lease |
    ForEach-Object -Process {
        Write-Verbose -Message "Lease has been found on server $($_.PSComputerName):"
        Write-Verbose -Message "IpAddress: $($_.IpAddress)"
        Write-Verbose -Message "ClientId: $($_.ClientId)"
        Write-Verbose -Message "ScopeId: $($_.ScopeId)"
        Write-Verbose -Message "HostName: $($_.HostName)"
        Write-Verbose -Message "AddressState: $($_.AddressState)"
    }

    $DhcpV4Lease |
    Where-Object -Property AddressState -Like -Value '*Reservation' |
    ForEach-Object -Process {
        "Lease IpAddress $($_.IpAddress) already reserved on server $($_.PSComputerName):",
        "ClientId: $($_.ClientId)",
        "ScopeId: $($_.ScopeId)" ,
        "HostName: $($_.HostName)",
        "AddressState: $($_.AddressState)",
        "Description: $($_.Description)" |
        Write-Warning
    }

    try
    {
        $AddDhcpReservationParams = @{Type = 'Dhcp' }

        if ($Description)
        {
            $AddDhcpReservationParams.Add('Description', $Description)
        }

        $DhcpV4Lease |
        Where-Object -Property AddressState -NotLike -Value '*Reservation' |
        ForEach-Object -Process {
            $Computer = $_.PSComputerName

            if ($PsCmdlet.ShouldProcess($_.IPAddress, "Convert lease to reservation: [ScopeId: $($_.ScopeId); Server: $Computer]"))
            {
                $_ |
                Add-DhcpServerv4Reservation @AddDhcpReservationParams -ComputerName $Computer -PassThru -ErrorAction Stop |
                ForEach-Object {
                    if (Get-DhcpServerv4Failover -ComputerName $Computer -ScopeId $_.ScopeId -ErrorAction Ignore)
                    {
                        $null = Invoke-DhcpServerv4FailoverReplication -ComputerName $Computer -ScopeId $_.ScopeId -Force
                    }
                    Write-Host "[IpAddress: $($_.IpAddress); ClientId: $($_.ClientId); ScopeId: $($_.ScopeId); Server: $Computer] has been added to reservation." -ForegroundColor Green
                }
            }
        }
    }
    catch
    {
        Write-Host -Object "Failed to add address '$(if($IpAddress){$IpAddress}else{$ClientId})' to reservation on server '$($DhcpV4Lease.PSComputerName)': $($_.Exception.Message)" -ForegroundColor Red
        exit 1
    }
}