BITSはMicrosoftがWindowsに標準機能として載せている分散ダウンロード機能です。WindowsUpdateもバックグラウンドでBITSを利用しており、LAN内の複数のPCからWindowsUpdateをダウンロードする場合には、他のパソコンが自動的にキャッシュサーバーとなることで、インターネットとの通信負荷を押させてくれます。このBITSはWindowsUpdate専用の機能というわけではなく、簡単なプログラムを用意すれば、大容量ファイルを配布するときに自由に活用することができます。
昨今、プログラムやセキュリティパッチのフットプリント(ファイルサイズ)が大きく鳴り続ける、パッチ配布のネットワーク負荷が原因でインターネットが輻輳するなんて事件もありましたね。社内ネットワーク(WAN)はその構造上、どうしても一か所に負荷が集中しやすく、分散ダウンロードができると随分と助かりますね。
BITSでダウンロードするための一連の流れは次のようになります。
- HTTPサーバー上にダウンロード元となるファイルを用意します。
- Start-BitsTransferでBITSに新しいダウンロード要求を登録します。
- 定期的にGet-BitsTransferを呼び出しダウンロードの完了を待ちます。
- ダウンロード完了後に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のグループポリシーで定義します。

