Windows OS標準機能(Powershell)でDDNSの更新を行う


ieserver.netさんを利用されている方で、余計なアプリは入れたくないというような方向けのScriptです。
Windows8/2012以降のOSで実行可能です。
Invoke-RestMethodの箇所を弄れば、Windows7/2008R2でも動きます。

実装している処理と流れは、下記の3つです。

1. ISPから付与されたGlobalIPの変更をチェック(外部サイトを利用)
	* GlobalIPを取得するサイトは2つ準備し、1箇所目がダウンしていた場合も2箇所目で取得させています
2. 変更があったらUpdate
3. 変更されたIPとプロバイダで付与されているFQDNをメール通知

汚いソースなので、「こうすれば綺麗だよ」とか優しく教えていただける方はコメントお願いします。

----
[2015.04.12 追記]
　IPアドレス更新に失敗した場合、メール通知されずIP変更に気づかないケースが発生したため
　旧IP記録ファイルにLoopBackを書き込むことでメール通知されるまで
　IP変更時と同様の動作となるよう改版しました。
　$LOOPBACKの記述があるところが該当箇所です。

----
```text:ieserverUpdater.ps1
# ドメイン名
$DOMAIN = "ieserverで選択したドメイン名:dip.jp等"

# パスワード
$PASS = "ieserverで登録したパスワード"

# サブドメイン名
$HOSTNAME = "取得したサブドメイン名"

# FQDN
$DDNS_FQDN = $HOSTNAME + "." + $DOMAIN

# IP アドレスを取得するページのURL
$IP_URL1 = "http://www.forts.jp/ip"
$IP_URL2 = "http://httpbin.org/ip"

# ieserver.net のDDNSサーバーの登録ページのURL
$DDNS_URL = "https://ieserver.net/cgi-bin/dip.cgi?" 
$UPDATE_URL = $DDNS_URL + "username=" + $HOSTNAME + "&password=" + $PASS + "&domain=" + $DOMAIN + "&updatehost=Go"

# ログファイルを保存するディレクトリ
$DATAPATH = "ログを保存するディレクトリパス"
$WAN_IP_FILE = "wan_ip.txt"
$OLD_IP_FILE = "old_ip.txt"
$LOG = "log.txt"

# メール通知失敗対策用 旧IPアドレス
$LOOPBACK = "127.0.0.1"

# メール送信設定(Gmailを使う想定です)
$SMTPSERVER = "smtp.gmail.com"
$EMAILFROM = "Gmailのメールアドレス"
$EMAILTO = "送信先メールアドレス(複数の場合、コンマで区切る)"
$SUBJECT = "Change IP Notification"
$GMAILPWD = "Gmailのパスワード:アプリパスワード設定時はそれを。。。"

# ログの削除日数指定
$DELDAYS = 7

# ログの出力
function WRITE_LOG($LOGMSG)
{
  $TIMESTAMP = Get-Date;
  Add-Content ($DATAPATH + "\" + $LOG) ($TIMESTAMP.ToString("yyyy/MM/dd HH:mm:ss") + " " + $LOGMSG)
}

# 変更有無チェック
function COMP_IP
{
  if ($OLD_IP -eq $NEW_IP)
  {
    WRITE_LOG("01:IPアドレス変更無し")
    Set-Content ($DATAPATH + "\" + $WAN_IP_FILE) $NEW_IP
  }
  else
  {
    WRITE_LOG("02:IPアドレス変更有り")
    Set-Content ($DATAPATH + "\" + $OLD_IP_FILE) $NEW_IP
    Set-Content ($DATAPATH + "\" + $WAN_IP_FILE) $NEW_IP
    UPDATE_AND_CHECK
  }
}

# IPアドレスの更新と確認
function UPDATE_AND_CHECK
{
  $RESLT_UPDATE = Invoke-WebRequest $UPDATE_URL
  ECHO $RESLT_UPDATE.StatusCode
  if ($RESLT_UPDATE.StatusCode -eq 200)
  {
    $UPDATE_CHECK = Resolve-DnsName $DDNS_FQDN -Server $DOMAIN
    ECHO $UPDATE_CHECK.IPAddress
    if ($UPDATE_CHECK.IPAddress -eq $NEW_IP)
    {
      WRITE_LOG("13:IPアドレス更新成功")
      SEND_MAIL
    }
    else
    {
      WRITE_LOG("93:IPアドレス更新失敗")
      Set-Content ($DATAPATH + "\" + $OLD_IP_FILE) $LOOPBACK
      WRITE_LOG("94:LOOPBACKアドレスセット")
    }
  }
  else
  {
    WRITE_LOG("94:ieServer接続不可")
  }
}

# メール通知
function SEND_MAIL
{
  $BODY = "New IP = " + $NEW_IP + "`nISP FQDN = " + $ISP_FQDN
  $SMTPCLIENT = New-Object Net.Mail.SmtpClient($SMTPSERVER, 587)
  $SMTPCLIENT.EnableSsl = $true
  $SMTPCLIENT.Credentials = New-Object System.Net.NetworkCredential($EMAILFROM, $GMAILPWD);
  $SMTPCLIENT.Send($EMAILFROM, $EMAILTO, $SUBJECT, $BODY)
  WRITE_LOG("14:メール通知完了")
}

# ログの自動削除
Get-ChildItem ($DATAPATH + "\" + $LOG) | Where-Object{((Get-Date) - $_.CreationTime).Days -gt $DELDAYS } | ForEach-Object { $_.Delete() }

# 記録しているIPアドレスの取得
if (Test-Path ($DATAPATH + "\" + $OLD_IP_FILE))
{
  $LAST_IP = Get-Content ($DATAPATH + "\" + $OLD_IP_FILE)
}
else
{
  $LAST_IP = "0.0.0.0"
}
$LAST_IP=$LAST_IP.Split("`n")
$OLD_IP = $LAST_IP[0]
ECHO $OLD_IP

# IPアドレスの取得
try
{
  $URL1_IP = Invoke-RestMethod -Uri $IP_URL1
  $NEW_IP1 = $URL1_IP.Split("`n")
  $NEW_IP = $NEW_IP1[0]
  ECHO $NEW_IP
  $ISP_FQDN = (nslookup $NEW_IP).Split(" ")
  $ISP_FQDN = $ISP_FQDN[11]
  ECHO $ISP_FQDN
  WRITE_LOG("11:URL1でIPアドレス取得")
  COMP_IP
}
catch
{
  WRITE_LOG("91:URL1でIPアドレスが取得できませんでした")
  try
  {
    $URL2_IP = Invoke-RestMethod -Uri $IP_URL2
    $NEW_IP = $URL2_IP.origin
    ECHO $NEW_IP
    $ISP_FQDN = (nslookup $NEW_IP).Split(" ")
    $ISP_FQDN = $ISP_FQDN[11]
    ECHO $ISP_FQDN
    WRITE_LOG("12:URL2でIPアドレス取得")
    COMP_IP
  }
  catch
  {
    WRITE_LOG("92:URL2でIPアドレスが取得できませんでした")
  }
}
```