WindowsServerへのリモートデスクトップ接続を国内IPアドレスのみに限定する

#はじめに
備忘録と練習を兼ねて初投稿です。
読みづらいところがあればご指摘いただけると嬉しいですm(_ _)m

#概要
WANからのアクセスが可能で、リモートデスクトップサービスがインストールされたWindowsServerに、Windowsファイアウォールを使ってIPアドレス制限をかける方法です。
PowerShellのスクリプトを使います。
国内のIPアドレスを公開しているサイトからリストを取得し、事前に作成したwindowsファイアウォールのルールにスコープを追加します。
リストは[IPv46様](https://ipvx.info/)のhttps://ipvx.info/country/range/jp/p/ を利用させていただきます。

#環境
- OS
    - WindowsServer2012R2 Standard、WindowsServer2016 Standard
- ファイアウォール
    - Windowsファイアウォール 
- PowerShell
    - version4、version5

#準備
- リモートデスクトップの待受けポートは標準のままだとアタックされ放題なので、次のwebサイトを参考に、ポート変更とWindowsファイアウォールのルールの追加を行います。
  - [リモートデスクトップ接続で使用するポートを変更する方法(PROJECT-GROUP)](https://www.projectgroup.info/tips/Windows/comm_0091.html)
- windowsファイアウォールのルールの名前はサイトの通り「RDP」とします。

#PowerShellスクリプト
- Windowsファイアウォールのルール「RDP」にスコープを追加します。
- スクリプトと同じディレクトリに次の2つのファイルを出力します。
  - GIP.txt（追加したIPアドレスリスト、上書き）
  - GIPUpdate.log（実行時間と登録した件数、追記）

```FWaddRemoteIP.ps1
$scriptPath = $MyInvocation.MyCommand.Path
$scriptPath = Split-Path -Parent $scriptPath
$GIPFile = $scriptPath  + "\GIP.txt"
$logFile = $scriptPath  + "\GIPUpdate.log"

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

Write-Output (Get-Date)>>$logFile
Write-Output "GIPの取得を開始します。">>$logFile

try{

    $url = "https://ipvx.info/country/range/jp/p/"
    $response = Invoke-WebRequest $url
    $response.Content >$GIPFile


    #１．まずRDPのスコープをanyにします
    Get-NetFirewallRule | Where { $_.DisplayName -eq 'RDP'} | Set-NetFirewallRule -RemoteAddress any

    $fwRDP = New-object -comObject HNetCfg.FwPolicy2
    $myRDPrules = @($fwRDP.Rules | where {$_.Name -eq 'RDP'})  #@()で囲むと要素が1つでも配列になる

    $textlist = ($response.Content) -as [string[]]
    $lines = $textlist -split "`n"



    foreach ($myRDPrule in $myRDPrules){

        $lineCount = 0

        foreach ($line in $lines) {

            if ($line -match "^[0-9]"){
                if ($myRDPrule.RemoteAddresses -eq '*'){
                        $myRDPrule.RemoteAddresses = $line
                        $lineCount++
                }else{
                        $myRDPrule.RemoteAddresses += (","+ $line)
                        $lineCount++
                }
            }
    
        }

        Write-Output ("RDPのルール　" + $lineCount + "　件のアドレスが許可に設定されました。")>>$logFile
    }

}catch{

    $Error[0] >>$logFile

}
Write-Output "--------------------------------------------------------------------">>$logFile
```
出力されるファイルはこんな感じです。

```GIPUpdate.log
2019年4月19日 11:57:28

GIPの取得を開始します。
RDPのルール　2247　件のアドレスが許可に設定されました。
--------------------------------------------------------------------
```

#解説
```
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;
```
httpsにアクセスするためにTLS 1.2 を有効化します。

```
Get-NetFirewallRule | Where { $_.DisplayName -eq 'RDP'} | Set-NetFirewallRule -RemoteAddress any
```
定期的な実行を想定しているため、最初にスコープを削除します。

```
$myRDPrules = @($fwRDP.Rules | where {$_.Name -eq 'RDP'})  
```
Windowsファイアウォールでプロファイルをいじっていたら同じ名前のルールが複数できていたことがあったため、配列にしています。
いらないルールを消しておけばいいのですが。。


#実行方法
次のようなバッチファイルを作ってタスクスケジューラで定期的に実行しています。

```PSexe.bat
powershell -ExecutionPolicy RemoteSigned -File ＜スクリプトファイルのフルパス＞
```
スクリプトファイルのパスが`C:\GIP\FWaddRemoteIP.ps1`の場合、次のようになります。

```PSexe.bat
powershell -ExecutionPolicy RemoteSigned -File "C:\GIP\FWaddRemoteIP.ps1"
```

#WindowsServer2008R2の場合
- ルールのスコープが1000件までしか登録できないので、ルールを3つ作っておいて分割して登録する必要があります。
- PowerShell2.0ではGet-NetFirewallRuleが使えないのでnetshを使う必要があります。

#おわりに
VPNとかクライアントのIPを固定するとか上位ネットワークで対応するとか、もっと安全な方法があると思うのですが、今回はどれも許されなかったので、苦肉の策です。
#参考記事
- [PowerShellスクリプトを簡単実行](https://qiita.com/biginnings/items/f4e22ad275d9adfc1b57)
- [リモートデスクトップ接続で使用するポートを変更する方法(PROJECT-GROUP)](https://www.projectgroup.info/tips/Windows/comm_0091.html)
- [PowerShell で GitHub に wget(Invoke-WebRequest) できない場合の対処方法](https://qiita.com/tikkss@github/items/4db7bec95a7337ca826d)
- [WindowsServer2016でfail2banっぽいことをする](https://qiita.com/Tsukeyakiber/items/73240e9bad6653921982)