|
|
|
|
@@ -2823,6 +2823,11 @@ $script:LangDefault = @{
|
|
|
|
|
"ph.xfer.site" = "https://tenant.sharepoint.com/sites/xxx"
|
|
|
|
|
"ph.xfer.library" = "Shared Documents/subfolder"
|
|
|
|
|
"xfer.note" = "Only the current version of each file is transferred (no version history)."
|
|
|
|
|
"chk.xfer.create.folders" = "Create missing folders"
|
|
|
|
|
"btn.xfer.csv" = "Import CSV..."
|
|
|
|
|
"btn.xfer.csv.clear" = "Clear"
|
|
|
|
|
"lbl.xfer.csv.info" = "{0} transfer(s) loaded"
|
|
|
|
|
"lbl.xfer.report.fmt" = "Report:"
|
|
|
|
|
"tab.bulk" = " Bulk Create "
|
|
|
|
|
"grp.bulk.list" = "Sites to create"
|
|
|
|
|
"btn.bulk.add" = "Add Site..."
|
|
|
|
|
@@ -3546,27 +3551,56 @@ $txtXferDstLib.PlaceholderText = T "ph.xfer.library"
|
|
|
|
|
|
|
|
|
|
$grpXferDst.Controls.AddRange(@($lblXferDstSite, $txtXferDstSite, $lblXferDstLib, $txtXferDstLib))
|
|
|
|
|
|
|
|
|
|
# ── GroupBox: Options (y=160, h=58) ──────────────────────────────────────────
|
|
|
|
|
$grpXferOpts = New-Group (T "grp.xfer.options") 10 160 620 58
|
|
|
|
|
# ── GroupBox: Options (y=160, h=96) ──────────────────────────────────────────
|
|
|
|
|
$grpXferOpts = New-Group (T "grp.xfer.options") 10 160 620 96
|
|
|
|
|
|
|
|
|
|
$chkXferRecursive = New-Check (T "chk.xfer.recursive") 10 18 260 $true
|
|
|
|
|
$chkXferOverwrite = New-Check (T "chk.xfer.overwrite") 280 18 230
|
|
|
|
|
$chkXferRecursive = New-Check (T "chk.xfer.recursive") 10 18 250 $true
|
|
|
|
|
$chkXferOverwrite = New-Check (T "chk.xfer.overwrite") 270 18 180
|
|
|
|
|
$chkXferCreateFolders = New-Check (T "chk.xfer.create.folders") 460 18 155 $true
|
|
|
|
|
|
|
|
|
|
$lblXferFmt = New-Object System.Windows.Forms.Label
|
|
|
|
|
$lblXferFmt.Text = T "lbl.xfer.report.fmt"
|
|
|
|
|
$lblXferFmt.Location = New-Object System.Drawing.Point(10, 42)
|
|
|
|
|
$lblXferFmt.Size = New-Object System.Drawing.Size(55, 20)
|
|
|
|
|
|
|
|
|
|
$radXferCsv = New-Radio "CSV" 68 42 55 $true
|
|
|
|
|
$radXferHtml = New-Radio "HTML" 125 42 60 $false
|
|
|
|
|
|
|
|
|
|
$btnXferCsvImport = New-Object System.Windows.Forms.Button
|
|
|
|
|
$btnXferCsvImport.Text = T "btn.xfer.csv"
|
|
|
|
|
$btnXferCsvImport.Location = New-Object System.Drawing.Point(250, 40)
|
|
|
|
|
$btnXferCsvImport.Size = New-Object System.Drawing.Size(118, 24)
|
|
|
|
|
|
|
|
|
|
$lblXferCsvInfo = New-Object System.Windows.Forms.Label
|
|
|
|
|
$lblXferCsvInfo.Text = ""
|
|
|
|
|
$lblXferCsvInfo.Location = New-Object System.Drawing.Point(374, 43)
|
|
|
|
|
$lblXferCsvInfo.Size = New-Object System.Drawing.Size(175, 18)
|
|
|
|
|
$lblXferCsvInfo.ForeColor = [System.Drawing.Color]::FromArgb(0, 120, 212)
|
|
|
|
|
|
|
|
|
|
$btnXferCsvClear = New-Object System.Windows.Forms.Button
|
|
|
|
|
$btnXferCsvClear.Text = T "btn.xfer.csv.clear"
|
|
|
|
|
$btnXferCsvClear.Location = New-Object System.Drawing.Point(554, 40)
|
|
|
|
|
$btnXferCsvClear.Size = New-Object System.Drawing.Size(55, 24)
|
|
|
|
|
$btnXferCsvClear.Visible = $false
|
|
|
|
|
|
|
|
|
|
$lblXferNote = New-Object System.Windows.Forms.Label
|
|
|
|
|
$lblXferNote.Text = T "xfer.note"
|
|
|
|
|
$lblXferNote.Location = New-Object System.Drawing.Point(10, 40)
|
|
|
|
|
$lblXferNote.Location = New-Object System.Drawing.Point(10, 72)
|
|
|
|
|
$lblXferNote.Size = New-Object System.Drawing.Size(600, 16)
|
|
|
|
|
$lblXferNote.Font = New-Object System.Drawing.Font("Segoe UI", 8, [System.Drawing.FontStyle]::Italic)
|
|
|
|
|
$lblXferNote.ForeColor = [System.Drawing.Color]::DimGray
|
|
|
|
|
|
|
|
|
|
$grpXferOpts.Controls.AddRange(@($chkXferRecursive, $chkXferOverwrite, $lblXferNote))
|
|
|
|
|
$grpXferOpts.Controls.AddRange(@($chkXferRecursive, $chkXferOverwrite, $chkXferCreateFolders,
|
|
|
|
|
$lblXferFmt, $radXferCsv, $radXferHtml,
|
|
|
|
|
$btnXferCsvImport, $lblXferCsvInfo, $btnXferCsvClear,
|
|
|
|
|
$lblXferNote))
|
|
|
|
|
|
|
|
|
|
# ── Buttons (y=224) ──────────────────────────────────────────────────────────
|
|
|
|
|
$btnXferStart = New-ActionBtn (T "btn.xfer.start") 10 224 ([System.Drawing.Color]::FromArgb(0, 120, 60))
|
|
|
|
|
# ── Buttons (y=260) ──────────────────────────────────────────────────────────
|
|
|
|
|
$btnXferStart = New-ActionBtn (T "btn.xfer.start") 10 260 ([System.Drawing.Color]::FromArgb(0, 120, 60))
|
|
|
|
|
|
|
|
|
|
$btnXferVerify = New-Object System.Windows.Forms.Button
|
|
|
|
|
$btnXferVerify.Text = T "btn.xfer.verify"
|
|
|
|
|
$btnXferVerify.Location = New-Object System.Drawing.Point(175, 224)
|
|
|
|
|
$btnXferVerify.Location = New-Object System.Drawing.Point(175, 260)
|
|
|
|
|
$btnXferVerify.Size = New-Object System.Drawing.Size(130, 34)
|
|
|
|
|
$btnXferVerify.BackColor = [System.Drawing.Color]::FromArgb(0, 120, 212)
|
|
|
|
|
$btnXferVerify.ForeColor = [System.Drawing.Color]::White
|
|
|
|
|
@@ -3575,7 +3609,7 @@ $btnXferVerify.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Dr
|
|
|
|
|
|
|
|
|
|
$btnXferOpen = New-Object System.Windows.Forms.Button
|
|
|
|
|
$btnXferOpen.Text = T "btn.xfer.open"
|
|
|
|
|
$btnXferOpen.Location = New-Object System.Drawing.Point(315, 224)
|
|
|
|
|
$btnXferOpen.Location = New-Object System.Drawing.Point(315, 260)
|
|
|
|
|
$btnXferOpen.Size = New-Object System.Drawing.Size(130, 34)
|
|
|
|
|
$btnXferOpen.Enabled = $false
|
|
|
|
|
|
|
|
|
|
@@ -3936,11 +3970,15 @@ $_reg = {
|
|
|
|
|
& $_reg $script:i18nMap $lblXferDstLib "lbl.xfer.library"
|
|
|
|
|
& $_reg $script:i18nMap $grpXferOpts "grp.xfer.options"
|
|
|
|
|
& $_reg $script:i18nMap $chkXferRecursive "chk.xfer.recursive"
|
|
|
|
|
& $_reg $script:i18nMap $chkXferOverwrite "chk.xfer.overwrite"
|
|
|
|
|
& $_reg $script:i18nMap $lblXferNote "xfer.note"
|
|
|
|
|
& $_reg $script:i18nMap $btnXferStart "btn.xfer.start"
|
|
|
|
|
& $_reg $script:i18nMap $btnXferVerify "btn.xfer.verify"
|
|
|
|
|
& $_reg $script:i18nMap $btnXferOpen "btn.xfer.open"
|
|
|
|
|
& $_reg $script:i18nMap $chkXferOverwrite "chk.xfer.overwrite"
|
|
|
|
|
& $_reg $script:i18nMap $chkXferCreateFolders "chk.xfer.create.folders"
|
|
|
|
|
& $_reg $script:i18nMap $lblXferFmt "lbl.xfer.report.fmt"
|
|
|
|
|
& $_reg $script:i18nMap $btnXferCsvImport "btn.xfer.csv"
|
|
|
|
|
& $_reg $script:i18nMap $btnXferCsvClear "btn.xfer.csv.clear"
|
|
|
|
|
& $_reg $script:i18nMap $lblXferNote "xfer.note"
|
|
|
|
|
& $_reg $script:i18nMap $btnXferStart "btn.xfer.start"
|
|
|
|
|
& $_reg $script:i18nMap $btnXferVerify "btn.xfer.verify"
|
|
|
|
|
& $_reg $script:i18nMap $btnXferOpen "btn.xfer.open"
|
|
|
|
|
|
|
|
|
|
# Bulk Create tab controls
|
|
|
|
|
& $_reg $script:i18nMap $grpBulkList "grp.bulk.list"
|
|
|
|
|
@@ -4965,30 +5003,156 @@ $btnOpenDupes.Add_Click({
|
|
|
|
|
|
|
|
|
|
# ── Transfer ──────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
$btnXferStart.Add_Click({
|
|
|
|
|
$clientId = $txtClientId.Text.Trim()
|
|
|
|
|
$srcSite = $txtXferSrcSite.Text.Trim()
|
|
|
|
|
$dstSite = $txtXferDstSite.Text.Trim()
|
|
|
|
|
$srcLib = $txtXferSrcLib.Text.Trim()
|
|
|
|
|
$dstLib = $txtXferDstLib.Text.Trim()
|
|
|
|
|
# ── CSV Import for bulk transfers ─────────────────────────────────────────────
|
|
|
|
|
$script:_XferCsvEntries = [System.Collections.Generic.List[object]]::new()
|
|
|
|
|
|
|
|
|
|
if (-not $clientId) { Write-Log "Client ID requis." "Red"; return }
|
|
|
|
|
if (-not $srcSite) { Write-Log "URL du site source requis." "Red"; return }
|
|
|
|
|
if (-not $dstSite) { Write-Log "URL du site destination requis." "Red"; return }
|
|
|
|
|
if (-not $srcLib) { Write-Log "Bibliotheque source requise." "Red"; return }
|
|
|
|
|
if (-not $dstLib) { $dstLib = $srcLib }
|
|
|
|
|
$btnXferCsvImport.Add_Click({
|
|
|
|
|
$ofd = New-Object System.Windows.Forms.OpenFileDialog
|
|
|
|
|
$ofd.Filter = "CSV Files (*.csv)|*.csv"
|
|
|
|
|
$ofd.Title = "Import Transfer CSV"
|
|
|
|
|
if ($ofd.ShowDialog() -ne "OK") { return }
|
|
|
|
|
|
|
|
|
|
$script:_XferCsvEntries.Clear()
|
|
|
|
|
try {
|
|
|
|
|
$rows = Import-Csv -Path $ofd.FileName -Delimiter ';' -Encoding UTF8
|
|
|
|
|
foreach ($r in $rows) {
|
|
|
|
|
$src = ($r.PSObject.Properties | Where-Object { $_.Name -match '^SourceSite$' }).Value
|
|
|
|
|
$dst = ($r.PSObject.Properties | Where-Object { $_.Name -match '^DestSite$' }).Value
|
|
|
|
|
$sl = ($r.PSObject.Properties | Where-Object { $_.Name -match '^SourceLibrary$' }).Value
|
|
|
|
|
$dl = ($r.PSObject.Properties | Where-Object { $_.Name -match '^DestLibrary$' }).Value
|
|
|
|
|
if ($src -and $sl) {
|
|
|
|
|
$script:_XferCsvEntries.Add(@{
|
|
|
|
|
SrcSite = $src.Trim()
|
|
|
|
|
DstSite = if ($dst) { $dst.Trim() } else { $src.Trim() }
|
|
|
|
|
SrcLib = $sl.Trim()
|
|
|
|
|
DstLib = if ($dl) { $dl.Trim() } else { $sl.Trim() }
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$n = $script:_XferCsvEntries.Count
|
|
|
|
|
$lblXferCsvInfo.Text = (T "lbl.xfer.csv.info") -f $n
|
|
|
|
|
$btnXferCsvClear.Visible = $true
|
|
|
|
|
$txtXferSrcSite.Enabled = $false; $txtXferSrcLib.Enabled = $false
|
|
|
|
|
$txtXferDstSite.Enabled = $false; $txtXferDstLib.Enabled = $false
|
|
|
|
|
Write-Log "CSV loaded: $n transfer(s)" "White"
|
|
|
|
|
} catch {
|
|
|
|
|
Write-Log "CSV import error: $($_.Exception.Message)" "Red"
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
$btnXferCsvClear.Add_Click({
|
|
|
|
|
$script:_XferCsvEntries.Clear()
|
|
|
|
|
$lblXferCsvInfo.Text = ""
|
|
|
|
|
$btnXferCsvClear.Visible = $false
|
|
|
|
|
$txtXferSrcSite.Enabled = $true; $txtXferSrcLib.Enabled = $true
|
|
|
|
|
$txtXferDstSite.Enabled = $true; $txtXferDstLib.Enabled = $true
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
# ── Helper: build transfer jobs list (from CSV or manual fields) ──────────────
|
|
|
|
|
function Get-XferJobs {
|
|
|
|
|
if ($script:_XferCsvEntries.Count -gt 0) {
|
|
|
|
|
return @($script:_XferCsvEntries)
|
|
|
|
|
}
|
|
|
|
|
$srcSite = $txtXferSrcSite.Text.Trim()
|
|
|
|
|
$dstSite = $txtXferDstSite.Text.Trim()
|
|
|
|
|
$srcLib = $txtXferSrcLib.Text.Trim()
|
|
|
|
|
$dstLib = $txtXferDstLib.Text.Trim()
|
|
|
|
|
if (-not $srcSite) { Write-Log "URL du site source requis." "Red"; return @() }
|
|
|
|
|
if (-not $dstSite) { Write-Log "URL du site destination requis." "Red"; return @() }
|
|
|
|
|
if (-not $srcLib) { Write-Log "Bibliotheque source requise." "Red"; return @() }
|
|
|
|
|
if (-not $dstLib) { $dstLib = $srcLib }
|
|
|
|
|
if ($srcSite -eq $dstSite -and $srcLib -eq $dstLib) {
|
|
|
|
|
Write-Log "Source et destination identiques." "Red"; return
|
|
|
|
|
Write-Log "Source et destination identiques." "Red"; return @()
|
|
|
|
|
}
|
|
|
|
|
return @(@{ SrcSite = $srcSite; DstSite = $dstSite; SrcLib = $srcLib; DstLib = $dstLib })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ── Helper: export transfer report ────────────────────────────────────────────
|
|
|
|
|
function Export-XferReport([System.Collections.Generic.List[object]]$Results, [string]$OutDir, [string]$Prefix, [bool]$AsHtml) {
|
|
|
|
|
if ($Results.Count -eq 0) { return $null }
|
|
|
|
|
if (-not (Test-Path $OutDir)) { New-Item -ItemType Directory -Path $OutDir | Out-Null }
|
|
|
|
|
$stamp = Get-Date -Format "yyyyMMdd_HHmmss"
|
|
|
|
|
|
|
|
|
|
if (-not $AsHtml) {
|
|
|
|
|
$f = Join-Path $OutDir "${Prefix}_$stamp.csv"
|
|
|
|
|
$Results | Export-Csv -Path $f -NoTypeInformation -Encoding UTF8
|
|
|
|
|
return $f
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# HTML report
|
|
|
|
|
$f = Join-Path $OutDir "${Prefix}_$stamp.html"
|
|
|
|
|
$okN = @($Results | Where-Object { $_.Status -eq "OK" }).Count
|
|
|
|
|
$errN = @($Results | Where-Object { $_.Status -eq "ERROR" }).Count
|
|
|
|
|
$skipN = @($Results | Where-Object { $_.Status -eq "SKIPPED" }).Count
|
|
|
|
|
$missN = @($Results | Where-Object { $_.Status -eq "MISSING" }).Count
|
|
|
|
|
$mmN = @($Results | Where-Object { $_.Status -eq "SIZE_MISMATCH" }).Count
|
|
|
|
|
$exN = @($Results | Where-Object { $_.Status -eq "EXTRA" }).Count
|
|
|
|
|
|
|
|
|
|
$rows = ""
|
|
|
|
|
foreach ($r in $Results) {
|
|
|
|
|
$color = switch ($r.Status) {
|
|
|
|
|
"OK" { "#e6f4ea" }
|
|
|
|
|
"ERROR" { "#fce8e6" }
|
|
|
|
|
"SKIPPED" { "#fff3cd" }
|
|
|
|
|
"MISSING" { "#fce8e6" }
|
|
|
|
|
"SIZE_MISMATCH" { "#fff3cd" }
|
|
|
|
|
"EXTRA" { "#e8f0fe" }
|
|
|
|
|
default { "#ffffff" }
|
|
|
|
|
}
|
|
|
|
|
$srcSz = if ($null -ne $r.SourceSize) { '{0:N0}' -f $r.SourceSize } else { "-" }
|
|
|
|
|
$dstSz = if ($null -ne $r.DestSize) { '{0:N0}' -f $r.DestSize } else { "-" }
|
|
|
|
|
$msg = if ($r.Message) { [System.Web.HttpUtility]::HtmlEncode($r.Message) } else { "" }
|
|
|
|
|
$rows += "<tr style='background:$color'><td>$([System.Web.HttpUtility]::HtmlEncode($r.SourceSite))</td><td>$([System.Web.HttpUtility]::HtmlEncode($r.File))</td><td><b>$($r.Status)</b></td><td style='text-align:right'>$srcSz</td><td style='text-align:right'>$dstSz</td><td>$msg</td></tr>`n"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$html = @"
|
|
|
|
|
<!DOCTYPE html><html><head><meta charset='utf-8'><title>Transfer Report</title>
|
|
|
|
|
<style>body{font-family:'Segoe UI',sans-serif;margin:20px;background:#f5f5f5}
|
|
|
|
|
h1{color:#1e3a5f}table{border-collapse:collapse;width:100%}th,td{border:1px solid #ddd;padding:6px 10px;font-size:13px}
|
|
|
|
|
th{background:#1e3a5f;color:#fff;position:sticky;top:0}.summary{display:flex;gap:15px;margin:12px 0}
|
|
|
|
|
.badge{padding:4px 12px;border-radius:4px;font-weight:bold;font-size:13px}
|
|
|
|
|
.ok{background:#e6f4ea;color:#1e7e34}.err{background:#fce8e6;color:#c62828}
|
|
|
|
|
.warn{background:#fff3cd;color:#856404}.info{background:#e8f0fe;color:#1565c0}
|
|
|
|
|
input[type=text]{padding:6px;margin:8px 0;width:300px;border:1px solid #ccc;border-radius:4px}</style>
|
|
|
|
|
<script>function filterTable(){var v=document.getElementById('q').value.toLowerCase();var rows=document.querySelectorAll('tbody tr');
|
|
|
|
|
rows.forEach(function(r){r.style.display=r.textContent.toLowerCase().indexOf(v)>-1?'':'none'})}</script>
|
|
|
|
|
</head><body><h1>Transfer Report</h1>
|
|
|
|
|
<div class='summary'>
|
|
|
|
|
<span class='badge ok'>OK: $okN</span><span class='badge err'>Error: $errN</span>
|
|
|
|
|
<span class='badge warn'>Skipped: $skipN / Mismatch: $mmN</span><span class='badge err'>Missing: $missN</span>
|
|
|
|
|
<span class='badge info'>Extra: $exN</span></div>
|
|
|
|
|
<input type='text' id='q' onkeyup='filterTable()' placeholder='Filter...'>
|
|
|
|
|
<table><thead><tr><th>Site</th><th>File</th><th>Status</th><th>Source Size</th><th>Dest Size</th><th>Message</th></tr></thead>
|
|
|
|
|
<tbody>$rows</tbody></table></body></html>
|
|
|
|
|
"@
|
|
|
|
|
$html | Set-Content -Path $f -Encoding UTF8
|
|
|
|
|
return $f
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ── Transfer Start ────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
$btnXferStart.Add_Click({
|
|
|
|
|
$clientId = $txtClientId.Text.Trim()
|
|
|
|
|
if (-not $clientId) { Write-Log "Client ID requis." "Red"; return }
|
|
|
|
|
|
|
|
|
|
$jobs = Get-XferJobs
|
|
|
|
|
if ($jobs.Count -eq 0) { return }
|
|
|
|
|
|
|
|
|
|
$recursive = $chkXferRecursive.Checked
|
|
|
|
|
$overwrite = $chkXferOverwrite.Checked
|
|
|
|
|
$createFolder = $chkXferCreateFolders.Checked
|
|
|
|
|
$outDir = $txtOutput.Text.Trim()
|
|
|
|
|
if (-not $outDir) { $outDir = if ($PSScriptRoot) { $PSScriptRoot } else { $PWD.Path } }
|
|
|
|
|
$asHtml = $radXferHtml.Checked
|
|
|
|
|
|
|
|
|
|
$params = @{
|
|
|
|
|
ClientId = $clientId
|
|
|
|
|
SrcSite = $srcSite
|
|
|
|
|
DstSite = $dstSite
|
|
|
|
|
SrcLib = $srcLib
|
|
|
|
|
DstLib = $dstLib
|
|
|
|
|
Recursive = $chkXferRecursive.Checked
|
|
|
|
|
Overwrite = $chkXferOverwrite.Checked
|
|
|
|
|
ClientId = $clientId
|
|
|
|
|
Jobs = @($jobs)
|
|
|
|
|
Recursive = $recursive
|
|
|
|
|
Overwrite = $overwrite
|
|
|
|
|
CreateFolders = $createFolder
|
|
|
|
|
OutFolder = $outDir
|
|
|
|
|
AsHtml = $asHtml
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$btnXferStart.Enabled = $false
|
|
|
|
|
@@ -4996,10 +5160,11 @@ $btnXferStart.Add_Click({
|
|
|
|
|
$btnXferOpen.Enabled = $false
|
|
|
|
|
$txtLog.Clear()
|
|
|
|
|
Start-ProgressAnim
|
|
|
|
|
Write-Log "=== TRANSFER ===" "White"
|
|
|
|
|
Write-Log "Source : $srcSite / $srcLib" "Gray"
|
|
|
|
|
Write-Log "Destination : $dstSite / $dstLib" "Gray"
|
|
|
|
|
Write-Log "Recursive : $($params.Recursive) Overwrite: $($params.Overwrite)" "Gray"
|
|
|
|
|
Write-Log "=== TRANSFER ($($jobs.Count) job(s)) ===" "White"
|
|
|
|
|
foreach ($j in $jobs) {
|
|
|
|
|
Write-Log " $($j.SrcSite)/$($j.SrcLib) -> $($j.DstSite)/$($j.DstLib)" "Gray"
|
|
|
|
|
}
|
|
|
|
|
Write-Log "Recursive: $recursive Overwrite: $overwrite Create folders: $createFolder" "Gray"
|
|
|
|
|
Write-Log ("-" * 52) "DarkGray"
|
|
|
|
|
|
|
|
|
|
$bgTransfer = {
|
|
|
|
|
@@ -5008,7 +5173,7 @@ $btnXferStart.Add_Click({
|
|
|
|
|
$Sync.Queue.Enqueue(@{ Text = $m; Color = $c })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Get-AllSPFiles([string]$BasePath, [string]$Rel = "") {
|
|
|
|
|
function Get-AllSPFiles([string]$BasePath, [bool]$Recurse, [string]$Rel = "") {
|
|
|
|
|
$files = @(Get-PnPFolderItem -FolderSiteRelativeUrl $BasePath -ItemType File -ErrorAction SilentlyContinue)
|
|
|
|
|
foreach ($f in $files) {
|
|
|
|
|
if ($f.ServerRelativeUrl -match '/_vti_history/') { continue }
|
|
|
|
|
@@ -5020,83 +5185,128 @@ $btnXferStart.Add_Click({
|
|
|
|
|
RelativeFolder = $Rel
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ($Params.Recursive) {
|
|
|
|
|
if ($Recurse) {
|
|
|
|
|
$folders = @(Get-PnPFolderItem -FolderSiteRelativeUrl $BasePath -ItemType Folder -ErrorAction SilentlyContinue)
|
|
|
|
|
foreach ($d in $folders) {
|
|
|
|
|
if ($d.Name -in @("Forms", "_vti_cnf", "_vti_history")) { continue }
|
|
|
|
|
Get-AllSPFiles "$BasePath/$($d.Name)" "$Rel$($d.Name)/"
|
|
|
|
|
Get-AllSPFiles "$BasePath/$($d.Name)" $Recurse "$Rel$($d.Name)/"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
Import-Module PnP.PowerShell -ErrorAction Stop
|
|
|
|
|
$report = [System.Collections.Generic.List[object]]::new()
|
|
|
|
|
$totalOk = 0; $totalErr = 0; $totalSkip = 0
|
|
|
|
|
|
|
|
|
|
# ── Enumerate source ──
|
|
|
|
|
BgLog "Connexion au site source..." "Cyan"
|
|
|
|
|
Connect-PnPOnline -Url $Params.SrcSite -Interactive -ClientId $Params.ClientId
|
|
|
|
|
BgLog "Enumeration des fichiers source ($($Params.SrcLib))..." "Cyan"
|
|
|
|
|
$srcFiles = @(Get-AllSPFiles $Params.SrcLib)
|
|
|
|
|
BgLog " $($srcFiles.Count) fichier(s) trouves" "LightGreen"
|
|
|
|
|
foreach ($job in $Params.Jobs) {
|
|
|
|
|
BgLog "--- $($job.SrcSite) / $($job.SrcLib) -> $($job.DstSite) / $($job.DstLib) ---" "White"
|
|
|
|
|
|
|
|
|
|
if ($srcFiles.Count -eq 0) {
|
|
|
|
|
BgLog "Aucun fichier a transferer." "Orange"
|
|
|
|
|
$Sync.TransferCount = 0
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
# Enumerate source
|
|
|
|
|
BgLog "Connecting to source..." "Cyan"
|
|
|
|
|
Connect-PnPOnline -Url $job.SrcSite -Interactive -ClientId $Params.ClientId
|
|
|
|
|
$srcFiles = @(Get-AllSPFiles $job.SrcLib $Params.Recursive)
|
|
|
|
|
BgLog " $($srcFiles.Count) file(s) found" "LightGreen"
|
|
|
|
|
|
|
|
|
|
# ── Download to temp ──
|
|
|
|
|
$tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) "SPToolbox_Transfer_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
|
|
|
|
New-Item -ItemType Directory -Path $tempRoot -Force | Out-Null
|
|
|
|
|
BgLog "Dossier temporaire : $tempRoot" "DarkGray"
|
|
|
|
|
|
|
|
|
|
$idx = 0
|
|
|
|
|
foreach ($f in $srcFiles) {
|
|
|
|
|
$idx++
|
|
|
|
|
$localDir = Join-Path $tempRoot $f.RelativeFolder
|
|
|
|
|
if (-not (Test-Path $localDir)) {
|
|
|
|
|
New-Item -ItemType Directory -Path $localDir -Force | Out-Null
|
|
|
|
|
if ($srcFiles.Count -eq 0) {
|
|
|
|
|
BgLog " No files to transfer." "DarkOrange"
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
Get-PnPFile -Url $f.ServerRelativeUrl -Path $localDir -FileName $f.Name -AsFile -Force
|
|
|
|
|
BgLog " [$idx/$($srcFiles.Count)] Downloaded: $($f.RelativePath) ($('{0:N0}' -f $f.Length) bytes)" "LightGreen"
|
|
|
|
|
}
|
|
|
|
|
BgLog "Download termine." "White"
|
|
|
|
|
|
|
|
|
|
# ── Upload to destination ──
|
|
|
|
|
BgLog "Connexion au site destination..." "Cyan"
|
|
|
|
|
Connect-PnPOnline -Url $Params.DstSite -Interactive -ClientId $Params.ClientId
|
|
|
|
|
# Download to temp
|
|
|
|
|
$tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) "SPToolbox_Xfer_$(Get-Date -Format 'yyyyMMdd_HHmmss')_$([guid]::NewGuid().ToString('N').Substring(0,6))"
|
|
|
|
|
New-Item -ItemType Directory -Path $tempRoot -Force | Out-Null
|
|
|
|
|
|
|
|
|
|
$idx = 0
|
|
|
|
|
foreach ($f in $srcFiles) {
|
|
|
|
|
$idx++
|
|
|
|
|
$dstFolder = if ($f.RelativeFolder) {
|
|
|
|
|
"$($Params.DstLib.TrimEnd('/'))/$($f.RelativeFolder.TrimEnd('/'))"
|
|
|
|
|
} else { $Params.DstLib }
|
|
|
|
|
Resolve-PnPFolder -SiteRelativePath $dstFolder -ErrorAction SilentlyContinue | Out-Null
|
|
|
|
|
$localFile = Join-Path (Join-Path $tempRoot $f.RelativeFolder) $f.Name
|
|
|
|
|
Add-PnPFile -Path $localFile -Folder $dstFolder -ErrorAction Stop | Out-Null
|
|
|
|
|
BgLog " [$idx/$($srcFiles.Count)] Uploaded: $($f.RelativePath)" "LightGreen"
|
|
|
|
|
$idx = 0
|
|
|
|
|
foreach ($f in $srcFiles) {
|
|
|
|
|
$idx++
|
|
|
|
|
$localDir = Join-Path $tempRoot $f.RelativeFolder
|
|
|
|
|
if (-not (Test-Path $localDir)) { New-Item -ItemType Directory -Path $localDir -Force | Out-Null }
|
|
|
|
|
try {
|
|
|
|
|
Get-PnPFile -Url $f.ServerRelativeUrl -Path $localDir -FileName $f.Name -AsFile -Force
|
|
|
|
|
} catch {
|
|
|
|
|
BgLog " ERROR downloading $($f.RelativePath): $($_.Exception.Message)" "Red"
|
|
|
|
|
$report.Add([PSCustomObject]@{ SourceSite=$job.SrcSite; DestSite=$job.DstSite; File=$f.RelativePath; Status="ERROR"; SourceSize=$f.Length; DestSize=$null; Message="Download: $($_.Exception.Message)" })
|
|
|
|
|
$totalErr++
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Upload to destination
|
|
|
|
|
BgLog "Connecting to destination..." "Cyan"
|
|
|
|
|
Connect-PnPOnline -Url $job.DstSite -Interactive -ClientId $Params.ClientId
|
|
|
|
|
|
|
|
|
|
$idx = 0
|
|
|
|
|
foreach ($f in $srcFiles) {
|
|
|
|
|
$idx++
|
|
|
|
|
$dstFolder = if ($f.RelativeFolder) {
|
|
|
|
|
"$($job.DstLib.TrimEnd('/'))/$($f.RelativeFolder.TrimEnd('/'))"
|
|
|
|
|
} else { $job.DstLib }
|
|
|
|
|
|
|
|
|
|
# Check if dest folder exists / create if needed
|
|
|
|
|
if ($Params.CreateFolders) {
|
|
|
|
|
try { Resolve-PnPFolder -SiteRelativePath $dstFolder -ErrorAction Stop | Out-Null } catch {
|
|
|
|
|
BgLog " ERROR creating folder $dstFolder : $($_.Exception.Message)" "Red"
|
|
|
|
|
$report.Add([PSCustomObject]@{ SourceSite=$job.SrcSite; DestSite=$job.DstSite; File=$f.RelativePath; Status="ERROR"; SourceSize=$f.Length; DestSize=$null; Message="Folder creation: $($_.Exception.Message)" })
|
|
|
|
|
$totalErr++
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$localFile = Join-Path (Join-Path $tempRoot $f.RelativeFolder) $f.Name
|
|
|
|
|
if (-not (Test-Path $localFile)) { continue }
|
|
|
|
|
|
|
|
|
|
# Check for existing file if not overwriting
|
|
|
|
|
if (-not $Params.Overwrite) {
|
|
|
|
|
try {
|
|
|
|
|
$existing = Get-PnPFile -Url "$dstFolder/$($f.Name)" -ErrorAction SilentlyContinue
|
|
|
|
|
if ($existing) {
|
|
|
|
|
BgLog " [$idx/$($srcFiles.Count)] SKIPPED (exists): $($f.RelativePath)" "DarkOrange"
|
|
|
|
|
$report.Add([PSCustomObject]@{ SourceSite=$job.SrcSite; DestSite=$job.DstSite; File=$f.RelativePath; Status="SKIPPED"; SourceSize=$f.Length; DestSize=$null; Message="File already exists" })
|
|
|
|
|
$totalSkip++
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
} catch {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
Add-PnPFile -Path $localFile -Folder $dstFolder -ErrorAction Stop | Out-Null
|
|
|
|
|
BgLog " [$idx/$($srcFiles.Count)] OK: $($f.RelativePath)" "LightGreen"
|
|
|
|
|
$report.Add([PSCustomObject]@{ SourceSite=$job.SrcSite; DestSite=$job.DstSite; File=$f.RelativePath; Status="OK"; SourceSize=$f.Length; DestSize=$f.Length; Message="" })
|
|
|
|
|
$totalOk++
|
|
|
|
|
} catch {
|
|
|
|
|
BgLog " [$idx/$($srcFiles.Count)] ERROR: $($f.RelativePath) - $($_.Exception.Message)" "Red"
|
|
|
|
|
$report.Add([PSCustomObject]@{ SourceSite=$job.SrcSite; DestSite=$job.DstSite; File=$f.RelativePath; Status="ERROR"; SourceSize=$f.Length; DestSize=$null; Message=$_.Exception.Message })
|
|
|
|
|
$totalErr++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Cleanup temp
|
|
|
|
|
if ($tempRoot -and (Test-Path $tempRoot)) {
|
|
|
|
|
Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BgLog "Upload termine." "White"
|
|
|
|
|
$Sync.TransferCount = $srcFiles.Count
|
|
|
|
|
|
|
|
|
|
$Sync.Report = @($report)
|
|
|
|
|
$Sync.TotalOk = $totalOk
|
|
|
|
|
$Sync.TotalErr = $totalErr
|
|
|
|
|
$Sync.TotalSkip = $totalSkip
|
|
|
|
|
} catch {
|
|
|
|
|
$Sync.Error = $_.Exception.Message
|
|
|
|
|
BgLog "Erreur : $($_.Exception.Message)" "Red"
|
|
|
|
|
} finally {
|
|
|
|
|
# Cleanup temp
|
|
|
|
|
if ($tempRoot -and (Test-Path $tempRoot)) {
|
|
|
|
|
Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue
|
|
|
|
|
BgLog "Fichiers temporaires nettoyes." "DarkGray"
|
|
|
|
|
}
|
|
|
|
|
$Sync.Done = $true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$sync = [hashtable]::Synchronized(@{
|
|
|
|
|
Queue = [System.Collections.Generic.Queue[object]]::new()
|
|
|
|
|
Done = $false
|
|
|
|
|
Error = $null
|
|
|
|
|
TransferCount = 0
|
|
|
|
|
Queue = [System.Collections.Generic.Queue[object]]::new()
|
|
|
|
|
Done = $false
|
|
|
|
|
Error = $null
|
|
|
|
|
Report = $null
|
|
|
|
|
TotalOk = 0
|
|
|
|
|
TotalErr = 0
|
|
|
|
|
TotalSkip = 0
|
|
|
|
|
})
|
|
|
|
|
$script:_XferSync = $sync
|
|
|
|
|
$script:_XferParams = $params
|
|
|
|
|
@@ -5136,8 +5346,20 @@ $btnXferStart.Add_Click({
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$cnt = $script:_XferSync.TransferCount
|
|
|
|
|
Write-Log "=== TRANSFERT TERMINE : $cnt fichier(s) ===" "White"
|
|
|
|
|
$ok = $script:_XferSync.TotalOk; $er = $script:_XferSync.TotalErr; $sk = $script:_XferSync.TotalSkip
|
|
|
|
|
Write-Log "=== TRANSFER COMPLETE: $ok OK, $er error(s), $sk skipped ===" "White"
|
|
|
|
|
|
|
|
|
|
# Generate report
|
|
|
|
|
$report = $script:_XferSync.Report
|
|
|
|
|
if ($report -and $report.Count -gt 0) {
|
|
|
|
|
$p = $script:_XferParams
|
|
|
|
|
$rptFile = Export-XferReport ([System.Collections.Generic.List[object]]$report) $p.OutFolder "Transfer" $p.AsHtml
|
|
|
|
|
if ($rptFile) {
|
|
|
|
|
Write-Log "Report: $rptFile" "White"
|
|
|
|
|
$script:_XferLastReport = $rptFile
|
|
|
|
|
$btnXferOpen.Enabled = $true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
$tmr.Start()
|
|
|
|
|
@@ -5147,27 +5369,22 @@ $btnXferStart.Add_Click({
|
|
|
|
|
|
|
|
|
|
$btnXferVerify.Add_Click({
|
|
|
|
|
$clientId = $txtClientId.Text.Trim()
|
|
|
|
|
$srcSite = $txtXferSrcSite.Text.Trim()
|
|
|
|
|
$dstSite = $txtXferDstSite.Text.Trim()
|
|
|
|
|
$srcLib = $txtXferSrcLib.Text.Trim()
|
|
|
|
|
$dstLib = $txtXferDstLib.Text.Trim()
|
|
|
|
|
$outDir = $txtOutput.Text.Trim()
|
|
|
|
|
|
|
|
|
|
if (-not $clientId) { Write-Log "Client ID requis." "Red"; return }
|
|
|
|
|
if (-not $srcSite) { Write-Log "URL du site source requis." "Red"; return }
|
|
|
|
|
if (-not $dstSite) { Write-Log "URL du site destination requis." "Red"; return }
|
|
|
|
|
if (-not $srcLib) { Write-Log "Bibliotheque source requise." "Red"; return }
|
|
|
|
|
if (-not $dstLib) { $dstLib = $srcLib }
|
|
|
|
|
if (-not $outDir) { $outDir = if ($PSScriptRoot) { $PSScriptRoot } else { $PWD.Path } }
|
|
|
|
|
|
|
|
|
|
$jobs = Get-XferJobs
|
|
|
|
|
if ($jobs.Count -eq 0) { return }
|
|
|
|
|
|
|
|
|
|
$recursive = $chkXferRecursive.Checked
|
|
|
|
|
$outDir = $txtOutput.Text.Trim()
|
|
|
|
|
if (-not $outDir) { $outDir = if ($PSScriptRoot) { $PSScriptRoot } else { $PWD.Path } }
|
|
|
|
|
$asHtml = $radXferHtml.Checked
|
|
|
|
|
|
|
|
|
|
$params = @{
|
|
|
|
|
ClientId = $clientId
|
|
|
|
|
SrcSite = $srcSite
|
|
|
|
|
DstSite = $dstSite
|
|
|
|
|
SrcLib = $srcLib
|
|
|
|
|
DstLib = $dstLib
|
|
|
|
|
Recursive = $chkXferRecursive.Checked
|
|
|
|
|
Jobs = @($jobs)
|
|
|
|
|
Recursive = $recursive
|
|
|
|
|
OutFolder = $outDir
|
|
|
|
|
AsHtml = $asHtml
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$btnXferStart.Enabled = $false
|
|
|
|
|
@@ -5175,9 +5392,7 @@ $btnXferVerify.Add_Click({
|
|
|
|
|
$btnXferOpen.Enabled = $false
|
|
|
|
|
$txtLog.Clear()
|
|
|
|
|
Start-ProgressAnim
|
|
|
|
|
Write-Log "=== VERIFICATION ===" "White"
|
|
|
|
|
Write-Log "Source : $srcSite / $srcLib" "Gray"
|
|
|
|
|
Write-Log "Destination : $dstSite / $dstLib" "Gray"
|
|
|
|
|
Write-Log "=== VERIFICATION ($($jobs.Count) job(s)) ===" "White"
|
|
|
|
|
Write-Log ("-" * 52) "DarkGray"
|
|
|
|
|
|
|
|
|
|
$bgVerify = {
|
|
|
|
|
@@ -5186,7 +5401,7 @@ $btnXferVerify.Add_Click({
|
|
|
|
|
$Sync.Queue.Enqueue(@{ Text = $m; Color = $c })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function Get-AllSPFiles([string]$BasePath, [string]$Rel = "") {
|
|
|
|
|
function Get-AllSPFiles([string]$BasePath, [bool]$Recurse, [string]$Rel = "") {
|
|
|
|
|
$files = @(Get-PnPFolderItem -FolderSiteRelativeUrl $BasePath -ItemType File -ErrorAction SilentlyContinue)
|
|
|
|
|
foreach ($f in $files) {
|
|
|
|
|
if ($f.ServerRelativeUrl -match '/_vti_history/') { continue }
|
|
|
|
|
@@ -5196,94 +5411,59 @@ $btnXferVerify.Add_Click({
|
|
|
|
|
RelativePath = "$Rel$($f.Name)"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ($Params.Recursive) {
|
|
|
|
|
if ($Recurse) {
|
|
|
|
|
$folders = @(Get-PnPFolderItem -FolderSiteRelativeUrl $BasePath -ItemType Folder -ErrorAction SilentlyContinue)
|
|
|
|
|
foreach ($d in $folders) {
|
|
|
|
|
if ($d.Name -in @("Forms", "_vti_cnf", "_vti_history")) { continue }
|
|
|
|
|
Get-AllSPFiles "$BasePath/$($d.Name)" "$Rel$($d.Name)/"
|
|
|
|
|
Get-AllSPFiles "$BasePath/$($d.Name)" $Recurse "$Rel$($d.Name)/"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
Import-Module PnP.PowerShell -ErrorAction Stop
|
|
|
|
|
$allResults = [System.Collections.Generic.List[object]]::new()
|
|
|
|
|
|
|
|
|
|
# Enumerate source
|
|
|
|
|
BgLog "Connexion au site source..." "Cyan"
|
|
|
|
|
Connect-PnPOnline -Url $Params.SrcSite -Interactive -ClientId $Params.ClientId
|
|
|
|
|
BgLog "Enumeration des fichiers source..." "Cyan"
|
|
|
|
|
$srcFiles = @(Get-AllSPFiles $Params.SrcLib)
|
|
|
|
|
BgLog " $($srcFiles.Count) fichier(s) source" "LightGreen"
|
|
|
|
|
foreach ($job in $Params.Jobs) {
|
|
|
|
|
BgLog "--- Verifying $($job.SrcSite)/$($job.SrcLib) vs $($job.DstSite)/$($job.DstLib) ---" "White"
|
|
|
|
|
|
|
|
|
|
$srcMap = @{}
|
|
|
|
|
foreach ($f in $srcFiles) { $srcMap[$f.RelativePath] = $f }
|
|
|
|
|
BgLog "Connecting to source..." "Cyan"
|
|
|
|
|
Connect-PnPOnline -Url $job.SrcSite -Interactive -ClientId $Params.ClientId
|
|
|
|
|
$srcFiles = @(Get-AllSPFiles $job.SrcLib $Params.Recursive)
|
|
|
|
|
BgLog " $($srcFiles.Count) source file(s)" "LightGreen"
|
|
|
|
|
$srcMap = @{}; foreach ($f in $srcFiles) { $srcMap[$f.RelativePath] = $f }
|
|
|
|
|
|
|
|
|
|
# Enumerate destination
|
|
|
|
|
BgLog "Connexion au site destination..." "Cyan"
|
|
|
|
|
Connect-PnPOnline -Url $Params.DstSite -Interactive -ClientId $Params.ClientId
|
|
|
|
|
BgLog "Enumeration des fichiers destination..." "Cyan"
|
|
|
|
|
$dstFiles = @(Get-AllSPFiles $Params.DstLib)
|
|
|
|
|
BgLog " $($dstFiles.Count) fichier(s) destination" "LightGreen"
|
|
|
|
|
BgLog "Connecting to destination..." "Cyan"
|
|
|
|
|
Connect-PnPOnline -Url $job.DstSite -Interactive -ClientId $Params.ClientId
|
|
|
|
|
$dstFiles = @(Get-AllSPFiles $job.DstLib $Params.Recursive)
|
|
|
|
|
BgLog " $($dstFiles.Count) destination file(s)" "LightGreen"
|
|
|
|
|
$dstMap = @{}; foreach ($f in $dstFiles) { $dstMap[$f.RelativePath] = $f }
|
|
|
|
|
|
|
|
|
|
$dstMap = @{}
|
|
|
|
|
foreach ($f in $dstFiles) { $dstMap[$f.RelativePath] = $f }
|
|
|
|
|
|
|
|
|
|
# Compare
|
|
|
|
|
BgLog "Comparaison en cours..." "Cyan"
|
|
|
|
|
$results = [System.Collections.Generic.List[object]]::new()
|
|
|
|
|
|
|
|
|
|
foreach ($key in $srcMap.Keys) {
|
|
|
|
|
$src = $srcMap[$key]
|
|
|
|
|
if ($dstMap.ContainsKey($key)) {
|
|
|
|
|
$dst = $dstMap[$key]
|
|
|
|
|
if ([long]$src.Length -eq [long]$dst.Length) {
|
|
|
|
|
$results.Add([PSCustomObject]@{
|
|
|
|
|
Name = $src.Name
|
|
|
|
|
RelativePath = $key
|
|
|
|
|
Status = "OK"
|
|
|
|
|
SourceSize = [long]$src.Length
|
|
|
|
|
DestSize = [long]$dst.Length
|
|
|
|
|
})
|
|
|
|
|
foreach ($key in $srcMap.Keys) {
|
|
|
|
|
$src = $srcMap[$key]
|
|
|
|
|
if ($dstMap.ContainsKey($key)) {
|
|
|
|
|
$dst = $dstMap[$key]
|
|
|
|
|
$st = if ([long]$src.Length -eq [long]$dst.Length) { "OK" } else { "SIZE_MISMATCH" }
|
|
|
|
|
$allResults.Add([PSCustomObject]@{ SourceSite=$job.SrcSite; DestSite=$job.DstSite; File=$key; Status=$st; SourceSize=[long]$src.Length; DestSize=[long]$dst.Length; Message="" })
|
|
|
|
|
} else {
|
|
|
|
|
$results.Add([PSCustomObject]@{
|
|
|
|
|
Name = $src.Name
|
|
|
|
|
RelativePath = $key
|
|
|
|
|
Status = "SIZE_MISMATCH"
|
|
|
|
|
SourceSize = [long]$src.Length
|
|
|
|
|
DestSize = [long]$dst.Length
|
|
|
|
|
})
|
|
|
|
|
$allResults.Add([PSCustomObject]@{ SourceSite=$job.SrcSite; DestSite=$job.DstSite; File=$key; Status="MISSING"; SourceSize=[long]$src.Length; DestSize=$null; Message="" })
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$results.Add([PSCustomObject]@{
|
|
|
|
|
Name = $src.Name
|
|
|
|
|
RelativePath = $key
|
|
|
|
|
Status = "MISSING"
|
|
|
|
|
SourceSize = [long]$src.Length
|
|
|
|
|
DestSize = $null
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
foreach ($key in $dstMap.Keys) {
|
|
|
|
|
if (-not $srcMap.ContainsKey($key)) {
|
|
|
|
|
$dst = $dstMap[$key]
|
|
|
|
|
$allResults.Add([PSCustomObject]@{ SourceSite=$job.SrcSite; DestSite=$job.DstSite; File=$key; Status="EXTRA"; SourceSize=$null; DestSize=[long]$dst.Length; Message="" })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$okN = @($allResults | Where-Object { $_.Status -eq "OK" }).Count
|
|
|
|
|
$missN = @($allResults | Where-Object { $_.Status -eq "MISSING" }).Count
|
|
|
|
|
$mmN = @($allResults | Where-Object { $_.Status -eq "SIZE_MISMATCH" }).Count
|
|
|
|
|
$exN = @($allResults | Where-Object { $_.Status -eq "EXTRA" }).Count
|
|
|
|
|
BgLog " Results: $okN OK, $missN missing, $mmN size mismatch, $exN extra" "White"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ($key in $dstMap.Keys) {
|
|
|
|
|
if (-not $srcMap.ContainsKey($key)) {
|
|
|
|
|
$dst = $dstMap[$key]
|
|
|
|
|
$results.Add([PSCustomObject]@{
|
|
|
|
|
Name = $dst.Name
|
|
|
|
|
RelativePath = $key
|
|
|
|
|
Status = "EXTRA"
|
|
|
|
|
SourceSize = $null
|
|
|
|
|
DestSize = [long]$dst.Length
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$okN = @($results | Where-Object { $_.Status -eq "OK" }).Count
|
|
|
|
|
$missN = @($results | Where-Object { $_.Status -eq "MISSING" }).Count
|
|
|
|
|
$mmN = @($results | Where-Object { $_.Status -eq "SIZE_MISMATCH" }).Count
|
|
|
|
|
$exN = @($results | Where-Object { $_.Status -eq "EXTRA" }).Count
|
|
|
|
|
BgLog "Resultats : $okN OK, $missN manquant(s), $mmN taille(s) differente(s), $exN extra" "White"
|
|
|
|
|
|
|
|
|
|
$Sync.VerifyResults = @($results)
|
|
|
|
|
$Sync.VerifyResults = @($allResults)
|
|
|
|
|
} catch {
|
|
|
|
|
$Sync.Error = $_.Exception.Message
|
|
|
|
|
BgLog "Erreur : $($_.Exception.Message)" "Red"
|
|
|
|
|
@@ -5342,20 +5522,13 @@ $btnXferVerify.Add_Click({
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$p = $script:_VerParams
|
|
|
|
|
$stamp = Get-Date -Format "yyyyMMdd_HHmmss"
|
|
|
|
|
$outDir = $p.OutFolder
|
|
|
|
|
if (-not (Test-Path $outDir)) { New-Item -ItemType Directory -Path $outDir | Out-Null }
|
|
|
|
|
|
|
|
|
|
$outFile = Join-Path $outDir "TransferVerify_$stamp.html"
|
|
|
|
|
$html = Export-TransferVerifyToHTML -Results $results `
|
|
|
|
|
-SrcSite $p.SrcSite -SrcLib $p.SrcLib `
|
|
|
|
|
-DstSite $p.DstSite -DstLib $p.DstLib
|
|
|
|
|
$html | Set-Content -Path $outFile -Encoding UTF8
|
|
|
|
|
|
|
|
|
|
Write-Log "Rapport : $outFile" "White"
|
|
|
|
|
$script:_XferLastReport = $outFile
|
|
|
|
|
$btnXferOpen.Enabled = $true
|
|
|
|
|
$p = $script:_VerParams
|
|
|
|
|
$rptFile = Export-XferReport ([System.Collections.Generic.List[object]]$results) $p.OutFolder "TransferVerify" $p.AsHtml
|
|
|
|
|
if ($rptFile) {
|
|
|
|
|
Write-Log "Report: $rptFile" "White"
|
|
|
|
|
$script:_XferLastReport = $rptFile
|
|
|
|
|
$btnXferOpen.Enabled = $true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
$tmr.Start()
|
|
|
|
|
|