Search This Blog

Showing posts with label Cloudflare. Show all posts
Showing posts with label Cloudflare. Show all posts

Monday, November 12, 2018

Powershell: Cloudflare List all domains and search for ip

Quick Note: This code is quickly put together to prompt for the Cloudflare API key and email, then will list all the domains in cloudflare and also prompt for an ip to search for within all domains. Please ignore the debugging and extra code

$ CloudflareAPIKey = Read-Host -Prompt 'Enter the API Key' ;

$ CloudflareAPIEmail = Read-Host -Prompt 'Enter the API email e.g. user@domain' ;

$ headers = @ {

    "X-Auth-Key" = $ CloudflareAPIKey ;

    "X-Auth-Email" = $ CloudflareAPIEmail ;

    "Content-Type" = 'application/json'

}

 

#this may need changing when Cloudflare update the api

[ string ] $ cloudFlareApiBaseUrl = "https://api.cloudflare.com/client/v4"

 

#Force TLS version to be 1.2 (cloudflare only allows tls1.2 now)

[ Net.ServicePointManager ]::SecurityProtocol = [ Net.SecurityProtocolType ]::Tls12

 

# Get Zones from cloudflare

$ request = Invoke-WebRequest -Uri " $ { cloudFlareApiBaseUrl }/zones" -Method "GET" -Headers $ headers

$ CloudflarePagedDomains = ConvertFrom-Json $ request .Content

[ int ] $ pageCount = $ CloudflarePagedDomains .result_info [ 0 ].total_pages

 

$ CloudflareAllDomains = @ ()

 

$ IpSearchValue = Read-Host -Prompt 'IP address to search for in Cloudflare' ;

 

write-host "List of all domains in cloudflare" -foregroundcolor "Yellow"

for ( $ i = 1 ; $ i -le $ pageCount ; $ i ++)

{

    $ Parameters = @ {

        page = $ i

      }

      $ request = Invoke-WebRequest -Uri " $ { cloudFlareApiBaseUrl }/zones" -Method "GET" -Headers $ headers -Body $ Parameters

      $ CloudflarePagedDomains = ConvertFrom-Json $ request .Content

    #loop through $request.result array...

    Foreach ( $ CloudflareDomain IN $ CloudflarePagedDomains .result ) {

        $ CloudflareAllDomains += $ CloudflareDomain .name ;

        write-host " $ ( $ CloudflareDomain .name ) `r " -foregroundcolor "DarkCyan"

    }

}

 

Foreach ( $ CloudflareDomain IN $ CloudflareAllDomains ) {

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

   

    $ zoneId = $ ( ConvertFrom-Json $ request .Content ).result[ 0 ].id

    write-host "Searching $ (( $ CloudflareDomain ).padright( 75 )) $ ( $ zoneId )" -foregroundcolor "Yellow"

    $ Parameters = @ {

        type = 'A'

        content = $ IpSearchValue

      }

    $ request = Invoke-WebRequest -Uri " $ { cloudFlareApiBaseUrl }/zones/ $ { zoneId }/dns_records" -Method "GET" -Headers $ headers -Body $ Parameters

 

    Foreach ( $ RecordFound IN $ ( ConvertFrom-Json $ request .Content ).result) {

        write-host " $ (( $ RecordFound .name ).padright( 75 )) $ ( $ RecordFound .content )" -foregroundcolor "Green"

    }

}

 

 


Share/Bookmark

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

Tuesday, June 07, 2016

Cloudflare API delete multiple records via Powershell

Recently whilst setting up cloudflare DNS, I had to delete a lot of records. With the API you can only do it one at a time. With thousands of records to remove I put together a little script tot do this.

Please ensure you fully test what you are doing with this, as I take no responsibility, but it worked for me.

You will various things to make this work, and I will assume you know how to use the API, by supplying your API key and email etc….

The script below can, with a small change, either read in the records to delete from a file or you can manually create the array in the script.

The script also contains output debugging that I left in.

Hope it helps somebody Smile

$headers = @{
"X-Auth-Key" = '<you need to get this from cloudflare>';
"X-Auth-Email" = '<replace this with email address>';
"Content-Type" = 'application/json'
}
#this may need changing when Cloudflare update the api
[string]$cloudFlareApiBaseUrl = "https://api.cloudflare.com/client/v4"
#file with records in it
[string]$recordlist= 'c:\path\fileRecordList.txt';
#dns domain to use
[string]$Zone = "contoso.com";

#Manually create array, add records here to delete.
<#
$ZoneRecords = @(
'example.contoso.com',
'example.subdomain.contoso.com'
)#>


#Create array from file, records to delete.
$ZoneRecords = Get-content -Path ".\${recordlist}"

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

Foreach ($Element IN $ZoneRecords) {
#debug
$Element

#GET record info from cloudflare
$Record = Invoke-WebRequest -Uri "${cloudFlareApiBaseUrl}/zones/${ZoneId}/dns_records/?name=${Element}" -Method "GET" -Headers $headers
$RecordID = $(ConvertFrom-Json $Record.Content).result[0].id
$RecordName = $(ConvertFrom-Json $Record.Content).result[2].id

#debug
$Record

#DELETE record info from cloudflare
$RecordDelete = Invoke-WebRequest -Uri "${cloudFlareApiBaseUrl}/zones/${ZoneId}/dns_records/${RecordID}" -Method "DELETE" -Headers $headers

#debug
$RecordDelete
'RecordName:' + $RecordName;
'RecordID:' + $RecordID;
}

The format of the text file is just a flat text file

test.qa.contoso.com
test.demo.contoso.com
test.demo.contoso.com
test.contoso.com
test1.contoso.com
test2.contoso.com
test.qa2.contoso.com
test2.qa.contoso.com
test.training.contoso.com
test3.contoso.com
test4.contoso.com

Share/Bookmark