この記事の概要を簡単まとめ!
- やりたいことが見つかってバッチファイル作成第5回
- IPアドレス(IPv4)やDNSサーバーは設定と編集が可能
- しかし編集するまでの画面を開く手順、編集方法は面倒である
- cmdから編集するにはSystem32にあるnetsh.exeを使う
- netshのオプションを利用することでcmdからでも可能になる
- バッチファイルにすれば簡単に変更が可能になる
- これでフリーのDNSサーバーも簡単に変えられる
ネタにするにあたり、事前準備が必要なものがある。プログラミングはその1つであろう。あらかじめ作成したソースコードとその結果を用意し、その上で文章を構成していかなければならないからである。ただ、文章そのものの構成は問題なく、不備無く完全に動くソースコードの開発がむしろ難しいものである。もっとも私は技術者ではないので、完璧なものを作れる保証はない。
さて、バッチファイルも一種のプログラミングと定義することができると思われるが、使いこなせばGUIでは面倒だったことがcmd(CUI)でさくっと完結できるものになる。第5回となる今回はPCを使う上で重要なことでもある「ネットワーク」に関係したものである。その中の最も初歩的かつ重要な事項として、IPアドレスとそれに付随する設定、そしてDNSサーバーについて取り上げる。特にDNSサーバーは公開DNSサーバーを利用する時に変更することが多いであろう。キャリア一般のDNSサーバーより高速でセキュリティの設定やログ保存をしないなどのポリシーの観点から、手動で設定することが多くなっている。
ただ、IPアドレスやDNSサーバーを設定する際のGUIはどうにも使いにくく、そしてそこまで辿り着くのが面倒になっている。Windows 10になって以降は尚更、コントロールパネルではなく設定を呼び出そうとする面倒な改悪が入っているため、面倒が増している。そんな面倒は、netsh.exeを使うことで解決することができるのである。これを使用したバッチファイル作成を書いていく。
ひとっ飛びできる目次
ブンブンハローnetsh.exe、どうもKIBEKINです。
PCとインターネット
前提:これまでのおさらい
Kibekin BLOG. では、私がKIBEKINになる前からバッチファイルについて取り上げていた。また、少し前に久々にバッチファイルについて書いた。それが以下の通りである。
- 第1回:【コマンド入力】CMDとバッチファイルでショートカット 入門編
- 第2回:【bat中級編】分岐と選択でまとまるバッチファイルの作成
- 第3回:【bat上級編】電源プランを操れ!powercfgとバッチファイル
- 第4回:【楽しようぜ】引数とバッチファイル:一気に「省略」する方法
これらがこれまでのバッチファイルについて書いた記事である。このうち第1回~第3回までは初心者が基礎から学べるように構成したもので、第3回でpowercfg.exeを使った電源プラン変更のバッチファイルを呼んでも分からないことがないようにしている。第4回についてはバッチファイル実行時の引数の扱いについて解説したものであり、これはバッチファイルの基本的な部分を知っている前提で構成している。これから解説するバッチファイルのコマンドについても、過去記事で解説済みのものについては過去記事を参照するようにして、本記事での解説は原則として行わないものとする。
PCとインターネットは切り離せない存在
今日に至るまで、インターネットに接続しないPCは果たしてどれくらい存在するであろうか。ある機械を動かすためにPCを利用する、或いはそもそもインターネットに接続することができない旧世代型のPCなどを考えても、インターネットに接続しているPCと比較しても圧倒的に少ないはずだ。それほどまでに、PCとインターネットは切り離せない存在である。
インターネットに接続するには、かつては電話回線を利用したダイアルアップ接続で、その後にADSLができ、後に有線(LANケーブル型)、そして無線LANというように進化していった。今では殆どの電子機器が無線LANに対応しているため、もはやインターネットに接続することは当たり前の時代である。ネット回線が無ければ人権はない、そう言いきってもいい程だ。
そのインターネットに接続する際、多くはルーターを介して接続する。このとき、自分で設定しているのでなければ、ルーターからIPアドレスが接続している全ての機器に割り当てられる。所謂DHCPであるが、基本的にはルーターへのアクセスができればインターネットに接続できると思って大丈夫だ。もちろん、IPアドレス(とサブネットマスク、デフォルトゲートウェイ、DNSサーバー)は後述するが手動設定が可能である。しかし設定を間違えればインターネットに接続できなくなるのでネットワークの仕組みについてあまり分かっていない人はDHCPに任せるべきである。
IPアドレスやDNSサーバは「ネットワークと共有センター」から編集と設定が可能
IPアドレスやDNSサーバは通常、インターネットに接続するだけであれば何も考える必要はない。DHCPサーバがIPアドレスを自動的に割り当て、DNSサーバーのアドレスを自動的に設定してくれるためである。したがって、ユーザーはこれらのことについて何も考える必要はないのである。楽な時代になったものである。
だが全部が自動だけで対応しているというわけでもなく、手動設定ももちろん可能である。手動設定はPCは当然ながら、スマートフォン、ゲーム機でも手動設定が可能である。ここではPCの話をしているので、PCについて解説する。なお当然のことながら、cmdを扱うのでOSはWindowsである。PCの場合は通常、この画面でIPアドレスやDNSサーバーを設定することができるようになっている。

Windowsにおいてはこの画像の一番右にある画面で、一般的なIPアドレスの書式である”[a].[b].[c].[d]”の形で、それぞれが0~255の範囲で値を入力する。また、サブネットマスク、デフォルトゲートウェイの設定項目もあり、これも同じ形式で入力する。そして下にはDNSサーバーの設定があり、IPアドレスを手動設定する場合、これも同時に設定しなければならない。DNSサーバーだけ自動というわけにはいかないようだ。
編集するまでの画面を開く手順、編集方法は面倒
だが、このIPアドレスは編集するにあたって、編集するまでの画面を開く手順、そして編集方法は面倒であるという欠点が存在する。編集するまでの画面を開く手順についてはWinodowsの標準のOSがWindows 10になったことによる弊害で、編集方法についてはWindows 10になる以前からの問題である。これらについてそれぞれどういうことかを解説する。
まず編集するまでの画面を開く手順についてである。Windows 10よりスタートメニューに「設定」という項目が追加されたが、これが面倒である。これが存在しなかったWindows 7の頃は、右下のLANケーブルマークまたは無線LANマークを右クリックして”ネットワークとインターネットの設定を開く”で簡単にその画面を呼び出すことができた。しかし現在はクソ使えない設定の”設定/ネットワークとインターネット”を開いてしまい、しかも画面が全く違うので(そもそもコントロールパネルですらない)、いちいちコントロールパネルのホームからそこまで行く必要がある。余計なことをしてくれた。
また、これは昔からであるが、IPアドレスをはじめとした10進数の入力は、実は面倒である。数値入力はドットで区切られていて、4つの区間に0~255を入れるわけだが、一度入力した値を消すにも1区間ずつしか消せず、数値が3桁ではない場合自動で右に入力カーソルが移動しない、タブキー操作で下に行ってしまう、エンターキーで変更反映になる、「自動」にチェックを入れた時点で入力が全て消えてしまうなど、面倒なことが多々存在する。あまり触らない人からすれば面倒ではないのであろう、しかしDNSサーバーが不調な時に変更することの多い私としては、実は面倒に感じるものである。もっとスマートにできないものか、そう考えていた。
cmdとnetsh.exe:netshのコマンド解説
GUIではわざわざそこまで行って、面倒な操作をして変えなければならないのでうんざりしていたわけである。だが、Windowsは幸いにして、疑似的だがCUI環境が未だに使える状態であり、一部の高度な機能についてはCUIからしか変更できないようになっている。これはWindowsにおいてはコマンドプロンプト、正式にはcmd.exe、単にcmdと呼ばれるものである。
いまでこそGUIが存在するため、何をするにもクリック1つで何とでもなるわけだが、その昔は黒い画面にコマンドを入力してあらゆる命令を行っていたことは想像に難くない。また、まだ不十分とはいえインターネットが利用できていたのなら、ネットワーク設定もコマンド入力でできたはずである。MS-DOSの頃はどうだったか不明であるが、System32にある”netsh.exe“でcmdからネットワーク設定を行えるのである。
ここからはバッチファイル記事ではお馴染みの、本体ソースコード掲載の前に今回使用するnetsh.exe(以下netsh)のコマンドについて解説を行う。なお、解説するにあたり過去4回の記事を閲覧済みで、バッチファイルに関する基礎的なものはわかっているものとして扱う。
前提:netshとは?
netsh は、現在実行中のコンピューターのネットワーク構成を表示したり変更したりするためのコマンド ライン スクリプト ユーティリティです。 netsh コマンドは、netsh プロンプトでコマンドを入力することで実行し、バッチ ファイルまたはスクリプトで使用できます。 リモート コンピューターとローカル コンピューターは、netsh コマンドを使用して構成できます。
また、指定したコンピューターに対して一連のコマンドをバッチ モードで実行できるスクリプト機能も備えています。 netsh では、構成スクリプトをテキスト ファイルに保存して、アーカイブとして保管したり、他のコンピューターの構成に利用したりできます。
netshは簡単に言えば、使用中のPCのネットワークを色々弄れるコマンドラインのスクリプトユーティリティの1つである。netshはcmdで単にnetsh
と入力して実行すると、netsh>
となり入力受付状態となる。cmdから直接操作する場合はこれでOKであるが、コマンドをいちいち入力するのはネットワーク管理者でもない限りは酷な話である。当然ながらこれもバッチファイルでの使用が可能であり、多くの場合はバッチファイルを介して利用するものとなる。
次項から、今回使用するnetshのオプション(コンテキスト)を解説する。なお、netshのヘルプ情報はこのテキストファイルから見れる。
netsh interfaceとコマンド
netsh interface
は今回のバッチファイルで絶対に使用するコンテキストである。このコンテキストのコマンドについてはこのテキストファイルを参照してもらうとして、実はこれ単体では何もできない。さらに半角スペースの後にコマンドを入力する必要がある。ただし、その中で使用するコマンド(コンテキスト)はipのみである。これを詳しく見ていく。
netsh interface ip
netsh interface ip
はコンテキストであり、IPアドレスの設定を行う。これもコマンド一覧はこのテキストファイルに掲載している。やはりこれも単体では機能せず、コマンド及びコンテキストの使用が前提となる。この中から使用するコマンド及びコンテキストは多数存在するため、順を追って解説する。
netsh interface ip show addresses
netsh interface ip show addresses
は、IPアドレスの構成を表示するものである。このテキストファイルに解説が載っている。書式はshow addresses "[インタフェース名]"
になる。インタフェース名についてはなくても問題なく、その場合は全てのインタフェースを対象にIPアドレスの構成を出力する。このとき、インターネット接続とは無関係のインタフェースについても出力される。VPNやBluetoothの構成を出力されてどうしろというのだろうか。
インタフェース名を指定した場合、指定したインタフェースの構成のみを表示する。例えば多くのPCにおいて、内蔵の無線LANカードの名前は”ワイヤレス ネットワーク接続 2″という名前になっていることであろう。スペースも含めてこの名前を指定すると、”ワイヤレス ネットワーク接続 2″の構成のみを表示して、他は表示しなくなる。したがって、ある名前の構成だけを取り出したい場合、これを利用する。なお、インタフェース名は将来的にも変わることがあり得ない名前であるので、バッチファイルで扱うにも困らないはずだ。

netsh interface ip set
netsh interface ip set
は、これ単体では何もできない。後に続くコマンドを指定する必要がある。ここで使用するのはaddressとdnsservers(=dns)である。それ以外のコマンドについてはこのテキストファイルを参照すること。
netsh interface ip set address
netsh interface ip set address
は、IPアドレスを設定するコマンドである。解説はこのテキストファイルから読める。書式はset address "[インタフェース名]" [ソース] [IPv4アドレス] [サブネットマスク] [デフォルトゲートウェイ] [ゲートウェイメトリック]
が基本である。例を挙げるのであれば、以下のように入力する。
1 2 3 4 5 6 |
@echo off rem netshでIPアドレスをセットする例。ここでは手動設定として次の値を設定する rem Interface: "ワイヤレス ネットワーク接続 3" IP: 114.51.48.10 mask: /24(255.255.255.0) gw: 114.51.48.1 netsh interface ip set address "ワイヤレス ネットワーク接続 3" static "114.51.48.10" "255.255.255.0" "114.51.48.1" 1 rem 成功した場合、何も表示されずにコマンド入力待機状態になる |
まずは対象となるインタフェース名を指定する。殆どのインタフェース名にスペースが入ることが多いため、ダブルクォーテーションを使用すると安全である。手動設定の場合、ソースをstatic(静的)と明示する。これにより手動設定が可能になる。その後にIPv4、サブネットマスク、デフォルトゲートウェイ、ゲートウェイメトリックを入力する。ゲートウェイメトリックについては、一般家庭であればルーターは1つしか存在しないことが多いので、1と指定しておけば問題ない。実は詳しいことは調べてもあまり出てこなかった。
また、手動設定が可能ならDHCPも可能である。DHCPに設定したい場合、ソースをdhcpにして、それ以降の値の入力は不要である。こうすることでDHCPが有効になる。
1 2 3 |
@echo off rem netshでDHCPを設定する場合のコマンド。必要な情報はインタフェース名のみ netsh interface ip set address "ワイヤレス ネットワーク接続 3" dhcp |
どちらの設定も可能であるので、これが使えることを知っていると設定も楽になる。
netsh interface ip set dns
IPアドレスがset addressなら、DNSサーバーはset dnsservers
で可能になる。解説はこのテキストファイルから読める。ただ、dnsserversと書くのは長くて面倒であるため、set dns
としても認識するようにエイリアスが設定されている。したがって、多くの場合は省略形であるset dnsと記述した方が楽である。DNSサーバーの場合の書式はset dns "[インタフェース名]" [ソース] [IPv4アドレス] [登録] [検証実施]
である。例として、任意の公開DNSサーバー及びDHCPに設定するコマンドを両方記述する。
1 2 3 4 5 6 7 8 9 |
@echo off rem netshでDNSサーバーを設定するコマンド。ここでは手動設定とDHCPの両方を取り扱う rem なお、このコマンドだけではセカンダリDNSを設定することはできない。別で解説するadd dnsも必要 rem DHCPを設定する場合は以下の通り netsh interface ip set dns "ワイヤレス ネットワーク接続 3" dhcp rem 手動設定する場合は以下の通り。ここではプライマリのみ設定可能。最後の検証実施は省略しても問題ない netsh interface ip set dns "ワイヤレス ネットワーク接続 3" static 8.8.8.8 primary |
コマンドはこの通りである。それほど難しいものではない。しかしこれには1つだけ問題が存在し、この方法ではプライマリDNSしか登録できないのである。多くの場合、公開DNSサーバーはプライマリとセカンダリが両方存在し、それを両方設定しなければ機能しないことが殆どだ。したがってこれとは別のコマンドを利用してセカンダリを登録する必要がある。これについては後述する。
ちなみに、DNSサーバーをDHCPにする場合、IPアドレスについてもDHCPを適用しておかなければ正常にインターネットに接続することはできない。したがって、DNSサーバーに対してDHCPを適用する場合、同時にIPアドレスもDHCPになるようにコマンドを実行する、またはバッチファイルで同時に処理できるようにしておく必要がある。逆に、IPアドレスがDHCPでDNSサーバーが手動設定である場合は問題ない。設定時はこの点には注意である。
netsh interface ip add dns
先のset dns
ではプライマリしか設定できなかった。セカンダリも設定する場合は、別のコマンドで設定しなければならない。それを実現するコマンドがadd dns
である。setとの違いは構成情報の追加であり、既存のものにプラスする形である。書式はadd dns "[インタフェース名]" [IPv4アドレス] [インデックス] [検証実施]
である。setとは書式が異なるものとなっている。
1 2 3 4 5 6 |
@echo off rem add dnsでDNSサーバーを追加する。基本はsetと同じだが、プライマリ設定等はないのが異なっている netsh interface ip add dns "ワイヤレス ネットワーク接続 3" 8.8.4.4 rem インデックスは省略しても問題ない rem 8.8.4.4はGoogle Public DNSのセカンダリDNSサーバーである |
このコマンドのヘルプの注釈には、『新しいDNSサーバーの IP アドレスを静的に構成された一覧に追加します。既定では、DNSサーバーが一覧の最後に追加されます。』と書かれている。つまり、普通にこのコマンドを実行すれば、既に存在するDNSサーバーの後ろに登録されることを意味する。この時にDNSサーバーが何も設定されていなかった場合、プライマリとして登録される。これは実際にコマンドを実行して確認した。
コマンドの意味で考えるのであれば、setは書き換え、addは書き換えず追加であると認識すればわかりやすい。何にせよ、これと先のset dnsと同時に利用することでDNSサーバーの変更が可能ということである。
netshの解説は以上である。
実践バッチファイル:netshでIPアドレスとDNSサーバーを変更する
解説事項が終了したため、いよいよそのバッチファイルのお披露目である。今回作成したバッチファイルは、これまでのバッチファイルの記述量及びファイルサイズを圧倒的に超えた、rem文(解説行)を含めて189行/10.4KBである。さて、重要な機能についてであるが、このバッチファイルだけでIPv4とDNSサーバーを変更できるように設計している。まずはソースコードを示し、そして実行結果の例を示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
@echo off rem ネットワーク関連をcmdから変更するバッチファイル。手動変更が面倒過ぎるのでcmdから変更可能にした rem 使用するSystem32のexe: netsh.exe ネットワーク関連の設定を行うものがこれである rem いつも通りsetlocalを有効にする。ただし変数の遅延展開を有効にする宣言を行う setlocal enabledelayedexpansion rem 対象のネットワーク名を変数に代入。通常は"ワイヤレス ネットワーク接続 2"がPCで使用される接続。これを基本とする rem デスクトップ、LANケーブル外付けWi-Fiの場合適宜変更すること。なお、多くの場合は空白が入るのでダブルクォーテーション囲いが前提 set interface_name="ワイヤレス ネットワーク接続 2" rem 変更するネットワーク名の明示を行う echo --Change network settings-- echo Target interface is %interface_name% rem メイン分岐。変更したい内容をここで選択する。内容はIPv4アドレス(マスクとGW含む)、DNSの2つのみ。v6は基本的に非対応 echo Which change settings? -^> ip: IP address, dns: DNS server echo If you quit, input "q". rem ここでset /pで選択させる。変数名はchoose_mode。初期化はループ開始タイミングで行う :choose_loop set choose_mode= set /p choose_mode="What? > "%choose_mode% rem if文分岐。3つの入力以外はループ開始点へ戻す。うちIPv4またはDNSを選択した場合call処理を開始。qの場合は終了処理へ直接飛ばす if /i "%choose_mode%"=="q" ( echo System quit. goto quit) rem call処理で入力が正しいかどうかを判定する。call後のErrorlevelで処理を変化させる。引数としてユーザに入力させた文字列と変更したいネットワークのインタフェース名を渡す rem ネットワーク名が何故か中途半端な位置で切られる。二重ダブルクォーテーションが必須? call :choose_mode_check ""%interface_name%"" "%choose_mode%" if Errorlevel 1 ( rem チェック後にモード選択が間違っている場合はこの表示を行い、もう一度選択させる echo No such mode. Select from list. goto choose_loop) rem 共通終了処理 echo System has terminated normally. :quit endlocal exit /b 0 rem サブルーチン置き場 rem 入力文字列判定。ipまたはdnsのみ許可する。それ以外はErrorlevel=1を返す :choose_mode_check rem 変数に一旦落とさないと機能しないことを確認 set temp_t01=%~1 rem ここで文字列判定を行う。該当する場合はcall処理を行ってErrorlevelを0で返す。なお、""付きでいいため通常の引数展開でOK。それ以外はErrorlevelを1で返す if /i %2=="ip" (call :ipv4_setting "%temp_t01%" exit /b 0) if /i %2=="dns" (call :dns_setting "%temp_t01%" exit /b 0) else (exit /b 1) rem ipv4の設定を行うサブルーチン。編集内容はIPアドレス、マスク、ゲートウェイの3項目。ただし殆どの場合マスクの編集は不要であり、ゲートウェイは末尾1であることが多い rem 一般家庭での使用を想定。通常は192.168.x.y/24で、0<=x<=255, 1<=y<=254。yが0と255を除外するのはネットワークアドレス及びブロードキャストアドレスを除外するためである rem もし使用しているアドレス等に相違があればその都度手動編集にて切り替えること(将来的には全てバッチファイル内で完結できるようにする予定) :ipv4_setting rem 受け取った引数を代入。ここではダブルクォーテーション除去の上で代入する set ifn_ipv4=%~1 echo Change IPv4 address. Show %ifn_ipv4% data. rem ここで対象のインタフェース名に対しnetsh interface ip show addresses "[インタフェース名]"を実行する。ここでサブネットマスクとデフォルトゲートウェイを示して入力の参考にする netsh interface ip show addresses "%ifn_ipv4%" rem トークン取り出しのfor文を利用する。一度に2つの項目を取り出すのは難しいようだ。ここではデフォルトゲートウェイを取り出し、それを利用する for /f "tokens=3 usebackq" %%i in (`netsh interface ip show addresses "%ifn_ipv4%" ^| find "デフォルト ゲートウェイ"`) do ( rem 絶対位置で3列目のトークン情報を変数に代入する set default_gw=%%i ) rem 次のfor文はサブネットマスクを取得する for /f "tokens=5 usebackq" %%i in (`netsh interface ip show addresses "%ifn_ipv4%" ^| find "サブネット プレフィックス"`) do ( rem 絶対位置で5列目のトークン情報を変数に代入する。しかしこのままだと')'も含んでしまうので、一旦tempに入れて変数展開書式を利用して')'を除外する set subnet_pfix_pre=%%i rem ここはfor内なので変数の遅延展開を利用しなければ正常に取り出せない set subnet_pfix=!subnet_pfix_pre:~0,-1! ) echo You need input new IP address. You input host address. echo CAUTION: You have to check subnet mask and default gateway. rem set /pを利用してIPアドレスを入力する。基本的には末尾だけ決定すればいい。ホスト部だけ入力させて、そこにデフォルトゲートウェイの値の一部と結合する rem ここにループ開始点をセットする。これは無入力および範囲外入力に対する対応である。変数初期化もここで行う :host_address_input_loop set host_address_input= set /p host_address_input="host address(1<=[n]<=254)? >"%host_address_input% rem ここで、範囲内であれば処理を続行、範囲外であればループ開始点へ戻す。処理続行はif内処理および終了処理を行う rem 最優先次項: 無入力除けは先頭で行わないと判定不可能 if "%host_address_input%"=="" ( echo Nothing has been entered. Try again. Push any keys... pause >nul goto host_address_input_loop) rem 現時点では1〜254なら許可。将来的には/24でない場合のネットワーク、ブロードキャスト、ゲートウェイの値であれば除外を行うように設定する rem ifやfor内では必ず変数の遅延展開を利用しなければ、変数が無入力扱いになってしまうので注意 if %host_address_input% geq 1 if %host_address_input% leq 254 ( rem for /fのdelimsを利用して、'.'区切りとして1つずつ区切ったうえで文字列連結を行う。これは全てが192.168.〜で始まるとは限らないため、全部対応のための処理である for /f "usebackq tokens=1,2,3 delims=." %%i in (`echo %default_gw%`) do ( rem ここでトークンを利用して文字列を切り出す。'.'を区切りに変更して末尾以外の値を取り出し、文字列結合を用いてIPアドレスを生成する rem トークンの切り出しは%%iを利用するのが一般的で、その場合i,j,k,...と変数が利用される。ここで入力させた値を遅延展開を用いて生成する set host_address=%%i.%%j.%%k.!host_address_input! ) rem 生成したIPアドレス、サブネットマスク、デフォルトゲートウェイ(既定値)をnetshを利用して変更を反映する。ゲートウェイメトリックはゲートウェイ設定時には必ず必要。値は1でOK netsh interface ip set address "!ifn_ipv4!" static "!host_address!" "!subnet_pfix!" "!default_gw!" 1 rem ここまで完了した場合、成功明示とErrorlevelを0にしてサブルーチンを終了する echo SUCCESS: Your IP address was changed. exit /b 0) rem 範囲外である場合はもう一度やり直させる echo No parameter or over range. Try again. Push any keys... pause >nul goto host_address_input_loop rem DNSサーバ選択を行う。ここではDNSをDHCPにするか、登録済みの公開DNSサーバにするかの2択である。登録済みの値を利用するのでIPアドレスより楽 :dns_setting set ifn_dns=%~1 echo Change DNS server setting. echo Choose DNS server. dhcp: DHCP man: Manual setting. rem 選択ループ開始点。変数は開始点の内側で初期化 :dns_server_setting_choose_loop set choose_dns_setting= set /p choose_dns_setting="Which server? >"%choose_dns_setting% rem DHCPまたはman以外の入力を弾く。大文字と小文字の区別は行わない。最初に無入力除けを行う if "%choose_dns_setting%"=="" ( echo Nothing has been entered. Try again. Push any keys... pause >nul goto dns_server_setting_choose_loop) if /i "%choose_dns_setting%"=="dhcp" ( rem DHCPの場合netshでDHCPを設定して終了。この場合IPアドレスもDHCPにしなければならない netsh interface ip set address "%ifn_dns%" dhcp netsh interface ip set dns "%ifn_dns%" dhcp echo SUCCESS: Your using DNS server was changed. exit /b 0) rem manならマニュアル設定になる。リストから選択させる。これについてはサブルーチンで処理させる if /i "%choose_dns_setting%"=="man" ( call :open_dns_server_choose "%ifn_dns%" exit /b 0) rem それ以外はループ開始点に戻す echo No such choices. Select from list. Push any keys... pause >nul goto dns_server_setting_choose_loop rem 公開DNSサーバ選択を行う :open_dns_server_choose rem 引数の変数への代入を行う set target_name=%~1 rem DNS一覧とその入力名を表示する echo Choose DNS server on the list. echo google:Google Public DNS, quad9:Quad9, cloud:Cloudflare, clouda:Cloudflare Anti-Virus, echo adg:AdGuard DNS, adgb: AdGuard AdBlock DNS, veri:Verisign Public DNS, quad101:Quad101 DNS(Taiwan), echo dyn:Dyn Internet Guide(Oracle), yan:Yandex DNS, yana:Yandex Anti-Virus rem echo open:Open DNS, pi:pi-dns, rem ループ開始点をセット。変数の初期化を行う :open_dns_server_choose_loop set choose_open_dns_server= set search_text= rem netshの処理は変数を利用する。ここではif文による変数代入の変化を扱う set /p choose_open_dns_server="Which server? >"%choose_open_dns_server% rem 無入力除けを行う if "%choose_open_dns_server%"=="" ( echo Nothing has been entered. Try again. Push any keys... pause >nul goto open_dns_server_choose_loop) rem 仕様変更:ファイル読み込みが正常に行えないので直接入力に変更。ここでプライマリとセカンダリを変数に代入する。&はくっつけないと空白を含めてしまうので注意 rem 一部のDNSサーバが使用できないことを確認したためコメントアウト対象にしている if /i "%choose_open_dns_server%"=="google" ( set primary_dns=8.8.8.8&set secondry_dns=8.8.4.4 rem ) else if /i "%choose_open_dns_server%"=="open" ( rem set primary_dns=208.64.222.222&set secondry_dns=208.67.220.220 ) else if /i "%choose_open_dns_server%"=="quad9" ( set primary_dns=9.9.9.9&set secondry_dns=149.112.112.112 rem ) else if /i "%choose_open_dns_server%"=="pi" ( rem set primary_dns=66.42.33.135&set secondry_dns=94.140.15.15 ) else if /i "%choose_open_dns_server%"=="adg" ( set primary_dns=94.140.14.140&set secondry_dns=94.140.14.141 ) else if /i "%choose_open_dns_server%"=="adgb" ( set primary_dns=94.140.14.14&set secondry_dns=94.140.15.15 ) else if /i "%choose_open_dns_server%"=="veri" ( set primary_dns=64.6.64.6&set secondry_dns=64.6.65.6 ) else if /i "%choose_open_dns_server%"=="cloud" ( set primary_dns=1.1.1.1&set secondry_dns=1.0.0.1 ) else if /i "%choose_open_dns_server%"=="clouda" ( set primary_dns=1.1.1.2&set secondry_dns=1.0.0.2 ) else if /i "%choose_open_dns_server%"=="quad101" ( set primary_dns=101.101.101.101&set secondry_dns=101.102.103.104 ) else if /i "%choose_open_dns_server%"=="dyn" ( set primary_dns=216.146.35.35&set secondry_dns=216.146.36.36 ) else if /i "%choose_open_dns_server%"=="yan" ( set primary_dns=77.88.8.8&set secondry_dns=77.88.8.1 ) else if /i "%choose_open_dns_server%"=="yana" ( set primary_dns=77.88.8.88&set secondry_dns=77.88.8.2 ) else ( rem 上記に当たらなかった場合はもう一度行わせる echo No chosen from list. Try again. Push any keys... pause >nul goto open_dns_server_choose_loop ) rem 上記のうちどれか1つでも当たっていればここまで来る。DNSサーバ設定処理を行う。当初はファイル読み込みの予定だがうまくいかないのでバッチファイル内で完結する netsh interface ip set dns "%target_name%" static %primary_dns% primary netsh interface ip add dns "%target_name%" %secondry_dns% echo SUCCESS: Your DNS server was changed. rem ここまで終われば正常終了である exit /b 0 |
まず注意事項であるが、このバッチファイルは権限の関係から、cmdを管理者権限で実行する必要がある。或いはこのバッチファイル自体を管理者権限で直接実行してもいい。このバッチファイルの場合、バッチファイルから直接実行しても弊害はないためである。とはいえ、cmdから実行した方がいいのは言うまでもない。
このバッチファイルの流れを分かりやすくリスト化すると、以下のようになる。
- バッチファイルを実行すると、IPアドレスまたはDNSサーバーの設定を行うか、バッチファイルを終了するかを選択する。バッチファイル終了を選択した場合、何もせずに終了する。
- IPアドレスを選択した場合、ホスト部([a].[b].[c].[d]で[d]にあたる部分)を1~254の範囲で入力する。将来的にはサブネットマスクの違いで自動的に範囲が指定できるようにする。
- DNSサーバーを選択した場合、DHCPにするか手動設定するかを選択する。
- DHCPにした場合、IPアドレス、DNSサーバー共にDHCPに設定してバッチファイルを終了する。
- 手動設定の場合、公開DNSサーバー一覧が表示される。この中から任意のサーバーを、表示されている選択文字列を入力して選択する。正しく選択されていれば、これを反映してバッチファイルを終了する。
簡単にまとめれば、このような処理を行っているということになる。ちなみに、エラー処理については省略しているが、想定されるエラー(入力ミス、無入力エンター)については既に検証済みであるため、解説する必要はないと判断したためである。ソースコードを確認すれば、どのような処理が行われているかはわかるはずである。
解説:バッチファイルの一部コマンドについて
バッチファイル内の一部コマンドについては、過去4回の記事で解説していないことがあるためこれを別途解説する。なお、サブルーチン処理、for /fの使い方は第3回記事、変数展開における特別な展開方法は第4回記事を参照すること。
バッチファイルを開始する際に冒頭及び終了時に記述するものとして、@echo off
やsetlocal
, endlocal
がある。これはバッチファイルを実行する際の処理としては必ず入れるほどにお馴染みのものであるが、このうちsetlocalには、変数に関する特殊な取り扱いを可能にする宣言を行うことができる。ソースコードでは5行目にsetlocalをしているが、その後ろにenabledelayedexpansion
とある。これは遅延環境変数を有効にする宣言である。今回のバッチファイルではこれが必要である。
「遅延環境変数」とは一体何なのか
これはバッチファイル(MS-DOS)の特性であるが、コマンドの実行はインタプリタである。つまり、1行単位で実行することになる。このときに変数展開の命令があれば展開し、全ての変数を一気に展開する。そしてバッチファイルでは()を使用すると、()内を1行として認識する。これが変数を展開する際には曲者で、1行ずつ認識・一気に変数展開される関係から、ifやforを利用して()内で変数を扱おうとした際、echoで表示してほしい内容が想定していたのと違ったり、ifのネスト処理がうまくいかずエラーになることが多発する。要するに、自分がしたいこととコンピュータの処理が異なるのである。例えば以下のような計算を行うと想定する。
1 2 3 4 5 6 7 8 |
@echo off rem if分岐を利用して()内で計算する例 set a=100 if %a%==100 ( set /a a+=200 echo %a% ) rem これを実行すると300ではなく100と表示される |
これを実行すると、300と表示されると予想するが実際は100が表示される。この理由は簡単で、ifの行に到達した時点で変数をあらかじめ展開するからである。つまり、もう100として表示されることが決まってしまっているのである。これでは、計算はおろかifの後でforやさらにifをして処理をしたいときに面倒が起きるのである。
遅延環境変数はこの問題を解決する。遅延環境変数はあらかじめsetlocalのタイミングで宣言しなければ使用できないが、この宣言後は通常変数を%で囲って展開するところ、!で変数を囲うことで変数が遅延展開される。これにより、通常は一気に変数展開されるのをあえて遅らせて、実行時に変数が展開されるようになる。上の場合はecho %a%
をecho !a!
とすることで、その直上の計算が行われた後で変数が展開されるので、表示は300となる。これが遅延環境変数でありその展開である1)参照:遅延環境変数とは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典。
ソースコードでは66, 88, 91行目にこれを使用している。これらはいずれもifやforの中にある変数であり、88行目はifとforの二重ネストである。この状態で通常の変数展開を行っても正常に展開できないが、遅延環境変数の展開を行えばほぼ想定通りの処理が可能になる。多数の変数を利用してif文のネストを構成する場合には非常に使える宣言であるので、覚えておいて損はない。
余談:1つのバッチファイル完結か、別途テキストファイル用意か
実はこのバッチファイルを作成するにあたり、公開DNSサーバーの扱いをどうするか考えていた。というのも、公開DNSサーバーの一覧をバッチファイル内に記述して直接実行するか、テキストファイルを用意して、for /fのトークン取り出しを利用して設定する、という2つの案があった。元々は後者の案を採用する予定であったが、テキストファイルを読み込んでその内容を表示するコマンドcat
がうまく機能しなかった(=テキストファイルが存在するにも関わらず解明不能な謎のエラーで読み込まなかった)ため、1つのバッチファイル内で完結するように変更したのである。それが今回のこれである。
バッチファイルを作成する上で考えるのは、そのバッチファイルだけで完結させるか、或いは別のバッチファイルかテキストファイルを用意して処理をするかである。それぞれのメリットとデメリットを考えると、以下のようになる。
- バッチファイル完結のメリット:そのバッチファイルだけで終わらせているため、他に必要な物がない
- バッチファイル完結のデメリット:記述量が多くなる。処理が増えすぎると整備するのが難しくなる
- 別のファイルを用意するメリット:単純な情報などを扱う場合、追加と削除が簡単に行える
- 別のファイルを用意するデメリット:パス指定の場合、バッチファイルやファイルを移動したらそれを修正しなければならない。コマンドの謎のエラーで読み込めない可能性もある
客観的評価を行うとすれば、このようなことが考えられる。このうち実際に発生したのがcatの読み込みエラーである。このエラーについては私の環境がそうなっているだけの可能性もあるが、しかしエラーはエラーであり、実際に発生したのであればこれへの対処を行い、バッチファイルの実行に支障がないようにしておく方が先決である。これを商売に使うわけではないのだから、それで問題ない。
しかし本音としては、管理が簡単なテキストファイル経由が良かったものである。これについては解決策を模索中であるが、おそらく解決は難しいと思われる。
解説は以上である。
これでフリーのDNSサーバーも簡単に変えられる
GUIでの設定は面倒で、CUIでの設定は簡単なものは何かあるかと探していた時、IPアドレスと(手動の)公開DNSサーバー設定はGUIでは面倒であることを思い出した。GUIでの設定は面倒さを感じる物であったし、設定画面を呼び出すまでもが面倒であった。これは、そこにいくまでに必要となる、何回かしなければならないマウス操作が煩わしいということである。
GUIのできる以前は、全てをコマンドで指定し、様々な処理を行っていたことは想像に難くない。確かにGUIでは直感的操作が可能である反面、平面的な移動距離と目的までの画面遷移の時間を要する。CUIは直感的操作は不可能だが、GUIのような画面的なタイムロスは殆どなしに命令を伝達し実行させることができる。GUIもCUIも、どちらも一長一短があるので、極端にどちらかが良いというわけではない。
しかしそれでも、cmd(バッチファイル)から数回のキー操作だけでさくっと変えられるのは非常に楽だ。もうあの面倒な画面遷移を行わず、cmdの黒い画面1つで完結できてしまう。そう思えば、わざわざバッチファイルを作って簡略化する意味はあるというものだ。そして、バッチファイルを作成することは、必然とPC(Windows)の勉強をすることにもなるので、この点でもやる意味はある。そして私はまだまだバッチファイルを作り続けることであろう。また新しくバッチファイルを作ることになったら、その時は書きたいと思う。
以上、バッチファイルとnetsh:簡単にIPとDNSを変える、であった。それでは、次回の記事で会おう。ン、バァーイ!
KIBEKIN at 11:11 May 15th, 2021
スポンサーリンク