Error 422 When Using Powershell to Update DNS Reco

2019-05-23 00:06发布

I am trying to update my DNS with GoDaddy via their API (My home network is on a Dynamic IP).

I am able to succesfully update when using the script found at http://teanazar.com/2016/05/godaddy-ddns-updater/ when run through cygwin.

However I am trying to simply things, and do this in powershell instead.

However when trying to use the following script:

$IP = Invoke-WebRequest http://api.ipify.org?format=json
$IP2 = ConvertFrom-JSON $ip
$domain = 'example.com'
$type = 'A'
$name = '@'

$key = 'key'
$secret = 'secret'


$Request = @{ttl='600';data=$ip2.ip;priority='1'}

$JSON = Convertto-Json $request

$headers = @{}
$headers["Authorization"] = 'sso-key ' + $key + ':' + $secret

Invoke-WebRequest    https://api.godaddy.com/v1/domains/$domain/records/$Type/$Name -contenttype "application/json" -method put -body $json -headers $headers

I have managed to work through each issue so far, and I know it is authenticating. But when I execute, i am getting "The Remote Server returned an error: (422) Unprocessable Entity

6条回答
Melony?
2楼-- · 2019-05-23 00:31

The A record is set in line 20 rather than being the VAR $name and the TTL is set to 1 at line 11, I think godaddy kicks it at this value. set the TTL to 3600 and insert the var to 20 it should work, it did for me anyway.

Thanks for the pointer :)

$IP = Invoke-WebRequest http://api.ipify.org?format=json
$IP2 = ConvertFrom-JSON $ip
$domain = 'domain.co.uk'
$type = 'A'
$name = 'record'

$key = 'blahhhhh'
$secret = 'blahhh'


$Request = @{ttl=3600;data=$ip2.ip}

$JSON = Convertto-Json $request

$headers = @{}
$headers["Authorization"] = 'sso-key ' + $key + ':' + $secret


Invoke-WebRequest    https://api.godaddy.com/v1/domains/$domain/records  -method get -headers $headers
Invoke-WebRequest    https://api.godaddy.com/v1/domains/$domain/records/A/$name  -method put -headers $headers -Body $json -ContentType "application/json"
查看更多
太酷不给撩
3楼-- · 2019-05-23 00:36

I was able to get it working with the following:

$apiKey = 'YOUR API KEY'
$apiSecret = 'YOUR API SECRET'
$domain = 'YOUR DOMAIN NAME'
#ENTER THE NAME OF THE RECORD YOU WISH TO UPDATE#
$name = '@'
$Headers = @{}
$Headers["Authorization"] = 'sso-key ' + $apiKey + ':' + $apiSecret
$result = Invoke-WebRequest https://api.godaddy.com/v1/domains/$domain/records/A/$name -method get -headers $headers
$content = ConvertFrom-Json $result.content
$dnsIp = $content.data
$currentIp = Invoke-RestMethod http://ipinfo.io/json | Select -exp ip
#THIS SECTION CHECKS THE CURRENT IP ADDRESS AGAINST THE PULL AND WILL UPDATE IF NOT CORRECT#
if ( $currentIp -ne $dnsIp) {
    #$Request = @{ttl=600;data=$currentIp }
    $JSON = ConvertTo-Json @(@{data=$currentIp;ttl=600})
    Invoke-WebRequest https://api.godaddy.com/v1/domains/$domain/records/A/$name -method put -headers $headers -Body $json -ContentType "application/json"

}
#SHOWS RESULTS OF THE HEADER PULL
Invoke-WebRequest https://api.godaddy.com/v1/domains/$domain/records/ -Method Get -Headers $Headers | ConvertFrom-Json
查看更多
来,给爷笑一个
4楼-- · 2019-05-23 00:40

I'd been using an implementation based on the solution provided by drizin... and it worked very well up until recently.

It seems that GoDaddy have tightened up on the JSON validation and it now fails with the following error:

{
  "code": "INVALID_BODY",
  "fields": [
    {
      "code": "UNEXPECTED_TYPE",
      "message": "is not a array",
      "path": "records"
    }
  ],
  "message": "Request body doesn't fulfill schema, see details in `fields`"
}

According to the specification for the APIs at https://developer.godaddy.com/doc/endpoint/domains#/v1/recordReplaceTypeName the JSON sent should be an array... i.e. [ { ... } ] where the code creates { ... }.

To fix this it requires a simple change to the line of code that build the JSON...

From:

$JSON = ConvertTo-Json @{data=$IP;ttl=3600}

To:

$JSON = ConvertTo-Json @(@{data=$IP;ttl=3600})
查看更多
再贱就再见
5楼-- · 2019-05-23 00:48

Make a production key on godaddy. The test key did not work for me.

And your ttl need to be an integer. not string, remove the '' from it.

(and change your @ to %40)

$IP = Invoke-WebRequest http://api.ipify.org?format=json
$IP2 = ConvertFrom-JSON $ip
$domain = 'example.com'
$type = 'A'
$name = 'Test'

$key = 'key'
$secret = 'secret'


[array]$Request=@{data=$IP2.ip; "port"=1; "priority"=0; "protocol"="none"; "service"="none"; "ttl"=3600; "weight"=1}

$JSON = Convertto-Json $request

$headers = @{}
$headers["Authorization"] = 'sso-key ' + $key + ':' + $secret


Invoke-WebRequest    https://api.godaddy.com/v1/domains/$domain/records  -method get -headers $headers
Invoke-WebRequest    https://api.godaddy.com/v1/domains/$domain/records/A/Test  -method put -headers $headers -Body $json -ContentType "application/json"

Looks like GoDaddy updated the API. Updated the solution to include the "array" requirement for the JSON as well as additional fields that now appear to be required as well.

查看更多
萌系小妹纸
6楼-- · 2019-05-23 00:50

To solve this problem, I would first recommend you start with a GET operation of the same endpoint. What do you see when you run this command?

Invoke-WebRequest   https://api.godaddy.com/v1/domains/$domain/records `
  -contenttype "application/json" -method GET -headers $headers

Let's validate what kind of Data GoDaddy will show you via this endpoint. Maybe they have a different terminology for making an @ record? There's a lot of ways we could be running into issues.

Let me know what you see here and we'll work to a solution.

查看更多
Bombasti
7楼-- · 2019-05-23 00:50

Go Daddy has some type constraints (TTL should be numeric, Priority should be numeric [please note that priority should only used for SRV records]), and some business constraints (like forcing TTL to be at least 600, which is 10min), etc.

You can refer to their API here, where you can see data examples, and also try out commands and see the error messages.

On the other hand if you prefer to see the error messages directly in powershell, since Content property is not available when you get an HTTP error, you should extract the error message from the response stream like described here

Full sample with error handling:

$IPj = Invoke-WebRequest http://api.ipify.org?format=json
$IP = (ConvertFrom-JSON $IPj).ip
$domain = 'mydomain.com'
$type = 'A'
$alias = 'myalias' # myalias.mydomain.com

$key = 'etc'
$secret = 'etc'

$JSON = ConvertTo-Json @{data=$IP;ttl=3600}
# you can also use an array of values: @(@{data=$IP1;ttl=3600},@{data=$IP2;ttl=3600},etc...)

$headers = @{}
$headers["Authorization"] = 'sso-key ' + $key + ':' + $secret

try {
    $ret = Invoke-WebRequest https://api.godaddy.com/v1/domains/$domain/records/$type/$alias  -method put -headers $headers -Body $json -ContentType "application/json"
    if ($ret.StatusCode -eq 200) { Write-Host "Success!" -for yellow } else { Write-Host "ERROR" -for red }
}
catch {
    $result = $_.Exception.Response.GetResponseStream()
    $reader = New-Object System.IO.StreamReader($result)
    $reader.BaseStream.Position = 0
    $reader.DiscardBufferedData()
    $responseBody = $reader.ReadToEnd();
    $responseBody = $responseBody | ConvertFrom-Json | Format-Custom | Out-String
    Write-Host "ERROR: $responseBody" -for red
}
查看更多
登录 后发表回答