Robocopy でスキップされたファイルを判別するための補助コード

### ◇§ 概要 ◇
　スキップされたファイルを含むログから、スキップされたファイルを含まないログを引くことで、スキップされたファイル群を炙り出すことを目指したコードです。このコードではスキップされたフォルダは無視されます。また、フォルダにファイルリストの作成許可がない場合はエラーが記録されます。（取得可：ファイル・シンボリックリンク・ハードリンク・ジャンクション等）

### ◇§ 通常コピー用（接合ポイント除外）◇
#### # 準備
```PowerShell:PowerShell
#〈文字コードを UTF-8 に変更〉
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
#〈コピー元のディレクトリ〉
$src = "<source directory>"
#〈コピー先のディレクトリ〉
$dest = "<destination directory>"
#〈ログの保存先〉
$Temp = [Environment]::GetEnvironmentVariable('Temp', 'Machine').TrimEnd("\")
$diff_3 = "${Temp}\diff_3.rc.log"
$diff_4 = "${Temp}\diff_4.rc.log"
#〈変数の確認〉
$src,$dest,$diff_3,$diff_4
#〈ログファイルの作成〉
[void](New-Item -Path $diff_3, $diff_4 -Force -Type File -Value "`r`n")
```

#### # ドライランもどき
```PowerShell:PowerShell
#〈スキップされたファイルをログに記録する〉
robocopy "$src" "$dest" /L /E /COPY:DAT /DCOPY:DAT /IT /IM /XO /XJ /R:0 /W:0 /TS /FP /NP /NS /NC /NJH /UNILOG:nul /TEE /NJS /V | Tee-Object -Variable diff_1

#〈スキップされたファイルをログに記録しない〉
robocopy "$src" "$dest" /L /E /COPY:DAT /DCOPY:DAT /IT /IM /XO /XJ /R:0 /W:0 /TS /FP /NP /NS /NC /NJH /UNILOG:nul /TEE | Tee-Object -Variable diff_2

#〈diff で比較〉
Compare-Object -Refere:$diff_2 -Differe:$diff_1 | Select-Object -Property InputObject | ForEach-Object -Begin {
    ""; ""
    "Skipped or Extras(destfile etc.)"
    "--------------------------------"
    $Pattern = "^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} ERROR"
    $SkipReason = $false
    $ExecFlag = $true
    $Summary = @()
    $i = 0
  } -Process {
    $Line = $_.InputObject
    if ($SkipReason) {
      $SkipReason = $false
    } elseif ([String]::IsNullOrWhiteSpace($Line)) {
    } elseif ($Line -match $Pattern) {
      $SkipReason = $true
    } elseif ($Line -match "^-----+$") {
      $ExecFlag = $false
    } elseif ($ExecFlag) {
      Write-Output $Line.Trim()
    } else {
      $Summary += $_ | Select-Object @{Name="Summary"; Expression={$_.InputObject}}
    }
  } -End {
  ""; ""
  "Failed"
  "------"
  $ErrorLines = @()
  $ErrorLines += $diff_2 | Select-String -Pattern $Pattern
  $ErrorLines.Line; ""
  $Summary
}
```

#### # 実際に実行
```PowerShell:PowerShell
#〈ドライランもどきを使ってスキップされたファイルをログに記録する〉
robocopy "$src" "$dest" /L /E /COPY:DAT /DCOPY:DAT /IT /IM /XO /XJ /XF "$diff_3" /R:0 /W:0 /TS /FP /NP /NS /NC /NJH /UNILOG:nul /TEE /NJS /V | Add-Content $diff_3 -Enc:UTF8 -Pass

#〈実際のコピー（スキップされたファイルをログに記録しない）〉
robocopy "$src" "$dest"    /E /COPY:DAT /DCOPY:DAT /IT /IM /XO /XJ /XF "$diff_4" /R:0 /W:0 /TS /FP /NP /NS /NC /NJH /UNILOG:nul /TEE | Add-Content $diff_4 -Enc:UTF8 -Pass

#〈diff で比較〉
Compare-Object -Refere(GC $diff_4 -Enc:UTF8) -Differe(GC $diff_3 -Enc:UTF8) | Select-Object -Property InputObject | ForEach-Object -Begin {
    $Pattern = "^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} ERROR"
    $SkippedOrExtras = @()
    $SkipReason = $false
    $ExecFlag = $true
    $ErrorLines = @()
    $Summary = @()
    $i = 0
  } -Process {
    $Line = $_.InputObject
    if ($SkipReason) {
      $SkipReason = $false
      # $ErrorLines += $Line
    } elseif ([String]::IsNullOrWhiteSpace($Line)) {
    } elseif ($Line -match $Pattern) {
      $SkipReason = $true
      $ErrorLines += $Line
    } elseif ($Line -match "^-----+$") {
      $ExecFlag = $false
    } elseif ($ExecFlag) {
      $SkippedOrExtras += $Line.Trim()
    } else {
      $Summary += $_ | Select-Object @{Name="Summary"; Expression={$_.InputObject}}
    }
  } -End {
  ""; ""
  "Skipped or Extras(destfile etc.)"
  "--------------------------------"
  $SkippedOrExtras
  ""; ""
  "Failed"
  "------"
  $ErrorLines
  "";
  $Summary
}
```

#### # 後処理
```PowerShell:PowerShell
Remove-Item $diff_3, $diff_4
# attrib /d -s -h "$dest"    # 管理者
```

### ◇§ オプション紹介 ◇
:::note warn
注意
除外オプション`/X~`を付けると `diff` での出力に除外対象`Extras`が追加されます。
:::

<dl>
<dt>つけておいたほうが良いオプション:</dt>
      <dfn><b><code>/B</code></b></dfn>（管理者権限必須）<br>
  <dfn><b><code>/J</code></b></dfn>（単一のファイルサイズが SSD のキャッシュより大きい場合）<br>
  <dfn><b><code>/XJ</code></b></dfn><br>
  <dfn><b><code>/XX</code></b></dfn>（<code>/MIR</code> or <code>/PURGE</code> を使う場合）<br>
  <dfn><b><code>/R:0</code></b></dfn><br>
  <dfn><b><code>/W:0</code></b></dfn><br>
  <dfn><b><code>/NP</code></b></dfn>（ログをファイルに出力する場合）<br>
  <dfn><b><code>[Console]::OutputEncoding = [System.Text.Encoding]::UTF8</code> ＋ <code>/UNILOG:nul /TEE</code></b></dfn><br>
</dl>

<dl>
  <dfn>　※英語句は引数から予想した非略語</dfn>
    <dd></dd>
<dt>基本オプション:</dt>
  <dfn><b><code>/L</code></b> ListOnly</dfn>
    <dd>コピー対象をリストアップするのみ。ドライランに近い。ログには出力する。エラーの内容は表示しない。</dd>
  <dfn><b><code>/B</code></b> BackupMode</dfn>
    <dd>SeBackupPrivilege・SeRestorePrivilege を付与</dd>
  <dfn><b><code>/S</code></b> SubDirectory</dfn>
    <dd>サブディレクトリをコピー（空のディレクトリは含まない）</dd>
  <dfn><b><code>/E</code></b> Empty | SubDirectory</dfn>
    <dd>空のディレクトリを含むサブディレクトリをコピー</dd>
  <dfn><b><code>/J</code></b> Jumbo</dfn>
    <dd>I/Oバッファリングを解除（/CREATE時にはいらない）</dd>
  <dfn><b><code>/CREATE</code></b> </dfn>
    <dd>ディレクトリツリーと０サイズのファイルを作成</dd>
<dt>コピーオプション:</dt>
  <dfn><b><code>/COPY:DATSOUX</code></b> Date・Attributes・Time Stamp・Security・Owner・aUditing・eXtra</dfn>
    <dd></dd>
  <dfn><b><code>/DCOPY:DATEX</code></b> Date・Attributes・Time Stamp・Extended・eXtra</dfn>
    <dd> &nbsp;D=データ、A=属性、T=タイムスタンプ <br>
	     &nbsp;S=セキュリティ(NTFS ACL)、O=所有者情報、U=監査情報 <br>
	     &nbsp;E=拡張属性、X=代替データストリームをスキップ <br>
        指定したものをコピーに含める</dd>
  <dfn><b><code>/IT</code></b> Includes Tweaked</dfn>
    <dd>ファイル属性のみの変更を含む</dd>
  <dfn><b><code>/IM</code></b> Includes Modified</dfn>
    <dd>変更日時が異なる場合を含む(新旧問わない) <br>
        <a href="https://n-archives.net/software/robosync/articles/robocopy-security-information/#i-4-2">/IMについて１</a> <br>
        <a href="https://n-archives.net/software/robosync/articles/robocopy-security-information/#i-6-3">/IMについて２</a></dd>
  <dfn><b><code>/IS</code></b> Includes Same</dfn>
    <dd>同じファイル（名前、サイズ、時刻、すべての属性が同じ）を含める</dd>
  <dfn><b><code>/SJ</code></b> SoftLinks (Junctions)</dfn>
    <dd>ジャンクション配下のファイルやフォルダを追跡コピーするのではなく、ジャンクション自体を作成</dd>
  <dfn><b><code>/SL</code></b> Symbolic Links</dfn>
    <dd>シンボリックリンクのリンク先の対象をコピーするのではなく、シンボリックリンクを作成</dd>
<dt>除外オプション:</dt>
  <dfn><b><code>/XO</code></b> eXcludes Older</dfn>
    <dd>src:Old、dest:New の場合は上書きしない</dd>
  <dfn><b><code>/XJ</code></b> eXcludes Junction</dfn>
    <dd>ファイルとディレクトリのシンボリックリンクと接合ポイントを除外</dd>
  <dfn><b><code>/XX</code></b> eXcludes eXtra</dfn>
    <dd>コピー先(dest)にだけ存在するファイルとディレクトリを削除しない</dd>
<dt>再試行オプション:</dt>
  <dfn><b><code>/R:0</code></b> Retries</dfn>
    <dd>失敗したコピーに対する再試行数（既定値は 1,000,000）</dd>
  <dfn><b><code>/W:0</code></b> WaitTime</dfn>
    <dd>再試行と再試行の間の待機時間（既定値は 30 秒）</dd>
<dt>ログオプション:</dt>
  <dt>　表示:</dt>
  <dfn><b><code>/V</code></b> Verbose</dfn>
    <dd>CLI 出力にスキップされたファイルを含める（ディレクトリは含まれない・ジャンクションは含まれる）</dd>
  <dfn><b><code>/TS</code></b> Time Stamp</dfn>
    <dd>コピー元(src)ファイルのタイムスタンプを表示する</dd>
  <dfn><b><code>/FP</code></b> Full Path</dfn>
    <dd>ファイルの完全なパスを表示する</dd>
  <dfn><b><code>/UNILOG:nul</code></b> Unicode Log > Null</dfn>
    <dd>UTF-8 に対応させる（nul = /dev/null）<br>
        <a href="https://n-archives.net/software/robosync/articles/robocopy-unicode-unilog-log/#i-1-3">参考１</a> <br>
        <a href="https://qiita.com/Q11Q/items/dd9e3da4e6d7f7af7e94#テクニックユニコード環境依存文字を使用しているファイルやフォルダのログ">参考２</a></dd>
  <dfn><b><code>/TEE</code></b> T</dfn>
    <dd>ファイルに出力する場合でも CLI にも表示する</dd>
  <dt>　除外:</dt>
  <dfn><b><code>/NP</code></b> No Progress</dfn>
    <dd>コピーの完了率を表示しない</dd>
  <dfn><b><code>/NS</code></b> No Size</dfn>
    <dd>ファイルサイズを出力しない</dd>
  <dfn><b><code>/NC</code></b> No Class</dfn>
    <dd>ファイルクラスを出力しない</dd>
  <dfn><b><code>/NJH</code></b> No Job Header</dfn>
    <dd>日時と引数の出力を抑制する</dd>
  <dfn><b><code>/NJS</code></b> No Job Summary</dfn>
    <dd>統計情報（結果の概要）非表示</dd>
</dl>