Search This Blog

Wednesday, June 08, 2016

Powershell: Cloudflare autoupdate public IP and send SMS

[2020-12-24 Edit-start]
Two things here - 

1. Cloudflare now allows for access tokens which you can lock down to specific areas and actions.. like dns zones and read\edit. So its better to now use these than the global api key that was only available when I wrote this article. You will need to create the access token in cloudflare and then change the $header variable to something like this.

$headers = @{
    "Authorization" = 'Bearer <access token>';
    "Content-Type" = 'application/json'
}

2. Also now with the demise of internet explorer I have found that to use the Invoke-WebRequest
you have to add -UseBasicParsing to the command. So it will read like this.

$request = Invoke-WebRequest -Uri "${cloudFlareApiBaseUrl}/zones/?name=${Zone}" 
-Method 'GET' -Headers $headers -UseBasicParsing

[2020-12-24 Edit-end]

We had a connection that ran our company VPN. The VPN was available on a couple of URLs. This connection also had a backup connection, so if the primary link failed it would swap to the backup. However this would change the IP address.
I wanted to make it so that the when the connection failed over the VPN URLs were updated.
The script below achieves that by updating the DNS records in cloudflare with the new public IP of the connection.
It looks at the public IP and then compares it to the record in dns, if the same do nothing. If different then update and send SMS
The SMS api maybe different for you depending on the company you use.
 
function Get-ScriptDirectory
{
    #Determine the folder in which the script lives.
    $Invocation = (Get-Variable MyInvocation -Scope 1).Value
    Split-Path $Invocation.MyCommand.Path
}
#[string]$CRLF
#needed to find the location of the script.
$scriptPath = Get-ScriptDirectory

[String]$scriptCurrentDateTime = Get-Date -format "yyyyMMddHHmmss"

$headers = @{
        'X-Auth-Key' = '<auth-key>';
        'X-Auth-Email' = '<email>';
        'Content-Type' = 'application/json'
    }

[string]$urlRequest = 'https://api.smscompanyurl.com/api-adv.php?';
[string]$smsUsername = '<username>';
[string]$smsPassword = '<password>';
[string]$smsNumbers = '<phonenumber1>,<phonenumber2>,<phonenumber3>';
[string]$smsFrom = '<Company Name>';
[string]$smsMessage = [uri]::EscapeDataString('Office IP Address has changed. Attempting auto update.');



$ZoneRecords = @(
'temp.contoso.com',
'tempytemp.contoso.com'
)

[string]$Zone = 'contoso.com';
[string]$cloudFlareApiBaseUrl = 'https://api.cloudflare.com/client/v4';
[string]$public_IP='';
[string]$public_IP='';


# Get Zone ID from cloudflare
    try 
    {
        $request = Invoke-WebRequest -Uri "${cloudFlareApiBaseUrl}/zones/?name=${Zone}" -Method 'GET' -Headers $headers
    }
    catch
    {
        $MyError = $_
        Throw $MyError
    }
    $zoneId = $(ConvertFrom-Json $request.Content).result[0].id


#Lookup external ip
    try 
    {
        $public_IP = (Invoke-RestMethod https://api.ipify.org?format=json).ip.trim()
    }
    catch
    {
        $MyError = $_
        Throw $MyError
    }
     

Foreach ($Element IN $ZoneRecords) {

    #GET record info from cloudflare
    #$RecordVPNweb = Invoke-WebRequest -Uri "${cloudFlareApiBaseUrl}/zones/${ZoneId}/dns_records/?name=${Element}" -Method 'GET' -Headers $headers
    try 
    {
        $RecordVPN = Invoke-RestMethod -Uri "${cloudFlareApiBaseUrl}/zones/${ZoneId}/dns_records/?name=${Element}" -Method 'GET' -Headers $headers -ContentType 'application/json'   
    }
    catch
    {
        $MyError = $_
        Throw $MyError
    }
    
    #When using webrequest need to convert from jason
    #$RecordVPN_ID = $(ConvertFrom-Json $RecordVPN.Content).result[0].id
    #$RecordVPN_IP = $(ConvertFrom-Json $RecordVPN.Content).result[0].content
    $RecordVPN_ID = $RecordVPN.result[0].id
    $RecordVPN_IP = $RecordVPN.result[0].content
    
    if ($RecordVPN_IP -ne $public_IP) {

        $smsMessage = $smsMessage + [uri]::EscapeDataString("Changing from $RecordVPN_IP to new $public_IP");
        $queryString = "username=$smsUsername&password=${smsPassword}&to=${smsNumbers}&from=${smsFrom}&message=${smsMessage}";
        ${urlRequest}+${queryString}
        [string]$textfileName = "$scriptPath\IPChanged$scriptCurrentDateTime.txt"
        
        try 
        {
            #send sms
            [String]$scriptIPChangeDateTime = Get-Date -format "yyyy-MM-dd HHmmss"
            [string]$textfileContent = "IP Change attempted at $scriptIPChangeDateTime : ${urlRequest}+${queryString}"
            out-file -filepath $textfileName -inputobject $textfileContent -encoding ASCII
            Invoke-RestMethod -Uri "${urlRequest}+${queryString}" -Method 'GET';   
        }
        catch
        {
            $MyError = $_
            Throw $MyError
        }

        $Data = @{
        'id' = "${RecordVPN_ID}";
        'type' = 'A';
        'name' = "${Element}";
        'content' = "${public_IP}";
        }
    
        # If it exists, UPDATE (PUT), if not, CREATE (POST)
        [string]$method = 'PUT';
        if ($RecordVPN.result.Count -eq 0) {
            $method = 'POST';
            $Data.Remove('id');
        }

        $DataJson = ConvertTo-Json $Data

        try 
        {
            $JSONResponse = Invoke-RestMethod -Uri "${cloudFlareApiBaseUrl}/zones/${ZoneId}/dns_records/${RecordVPN_ID}/" -Headers $Headers -Body $DataJson -Method "${method}" -ContentType 'application/json' -ErrorAction Stop
        }
        catch
        {
            $MyError = $_
            Throw $MyError
        }
       
    }
}

Share/Bookmark

No comments:

Post a Comment