PowershellからBITS(Background Intelligent Transfer Service)を使用して大容量ファイルを配布する

BITSはMicrosoftがWindowsに標準機能として載せている分散ダウンロード機能です。WindowsUpdateもバックグラウンドでBITSを利用しており、LAN内の複数のPCからWindowsUpdateをダウンロードする場合には、他のパソコンが自動的にキャッシュサーバーとなることで、インターネットとの通信負荷を押させてくれます。このBITSはWindowsUpdate専用の機能というわけではなく、簡単なプログラムを用意すれば、大容量ファイルを配布するときに自由に活用することができます。

昨今、プログラムやセキュリティパッチのフットプリント(ファイルサイズ)が大きく鳴り続ける、パッチ配布のネットワーク負荷が原因でインターネットが輻輳するなんて事件もありましたね。社内ネットワーク(WAN)はその構造上、どうしても一か所に負荷が集中しやすく、分散ダウンロードができると随分と助かりますね。

BITSでダウンロードするための一連の流れは次のようになります。

  1. HTTPサーバー上にダウンロード元となるファイルを用意します。
  2. Start-BitsTransferでBITSに新しいダウンロード要求を登録します。
  3. 定期的にGet-BitsTransferを呼び出しダウンロードの完了を待ちます。
  4. ダウンロード完了後にComplete-BitsTransferでファイルに書き出します。

上記をPowershell Scriptで記述したのが下記です。このスクリプトをダウンロードが完了するまで定周期で実行します。

$displayName = 'BITS_Sample'; # BITSにダウンロード要求を登録する時の表示名
$fromURL = 'http://www.example.co.jp/BITS_Sample.zip'; # ダウンロード元のURL
$destFile = 'C:\TEMP\BITS_Sample.zip'; # ダウンロード先のファイル名
$logFile = 'C:\TEMP\BITS_Sample.log' # ログ出力先のファイル名

$noBitsInstance = $true;
$completeDownload = $false;

Add-Content -Path $logFile -Value ('Start Script:' + (Get-Date));

# ダウンロード先フォルダが無ければ作成しておく
if ($false -eq (Test-Path 'C:\TEMP')){
    mkdir 'C:\TEMP';
}

# ダウンロードファイルが
if ($false -eq (Test-Path $destFile)){
    # BITSへのダウンロード要求を列挙する
    Get-BitsTransfer | Where-Object {
        Add-Content -Path $logFile -Value ('BITS Status:' + $_.DisplayName + '-' + $_.JobState);
        # 表示名の一致しているダウンロード要求が転送終了になるまで待機
        if ($_.DisplayName -eq $displayName){
            $noBitsInstance = $false;
            if ($_.JobState -eq "Transferred") {
         # ダウンロード完了した転送要求を完了させる
                Complete-BitsTransfer $_;
                $completeDownload = $true;
            }
        }
    }

    # BITSにダウンロード要求が登録されていなければ、新たに登録する。
    if ($noBitsInstance -eq $true){
        $delayMinute = Get-Random -Maximum 240;
        $kickDateTime = (Get-Date).AddMinutes($delayMinute);

        # 新規ダウンロード登録までランダムに待機する
        Add-Content -Path $logFile -Value ('Wait ' + $delayMinute + ' Minutes');
        While ($kickDateTime -ge (Get-Date)){
            Add-Content -Path $logFile -Value ('delay - ' + (Get-Date));
            sleep 60;
        }

        # 新規にダウンロードを登録する
        Add-Content -Path $logFile -Value ('Start BitsTransfer:' + $displayName + '-' + $destFile);
        Start-BitsTransfer -Source $fromURL -Destination $destFile -Asynchronous -Priority Normal -DisplayName $displayName
    }

    if ($completeDownload -eq $true){
        # ダウンロード完了後の処理
        Add-Content -Path $logFile -Value ('Complte Download:' + $displayName + '-' + $destFile);
    }
}
Add-Content -Path $logFile -Value ('End Script:' + (Get-Date));

私はActive Directoryのグループポリシーでログオンスクリプトとして登録しました。コントロールパネルのタスクで定周期に起動してもよいでしょう。

BITSで使用する帯域の制限などはレジストリに記述するか、ActiveDirectoryのグループポリシーで定義します。

コメントを残す

メールアドレスが公開されることはありません。