Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 119 additions & 2 deletions scripts/spo-compare-files/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@

## Summary

This script first connects to the first tenant using the Connect-PnPOnline cmdlet, then uses the Get-PnPFile cmdlet to retrieve the file in question. It then connects to the second tenant and retrieves the same file. The script then uses the Get-FileHash cmdlet to retrieve the hash of the file in both tenants. Finally, it compares the hashes of the two files and outputs the results to the console.
This script compares files from two different SharePoint tenants by calculating and comparing their hash values. This is useful for verifying file integrity after migrations or ensuring files are identical across tenants. This sample is available in both PnP PowerShell and CLI for Microsoft 365.

Example of script output of the CLI for Microsoft 365 version:

![preview CLI for Microsoft 365 output](assets/preview.png)

# [PnP PowerShell](#tab/pnpps)

Expand All @@ -32,13 +35,127 @@ if ($hash1 -eq $hash2) {

```
[!INCLUDE [More about PnP PowerShell](../../docfx/includes/MORE-PNPPS.md)]

# [CLI for Microsoft 365](#tab/cli-m365-ps)

```powershell
[CmdletBinding()]
param(
[Parameter(Mandatory, HelpMessage = "URL of the site in first tenant")]
[string]$WebUrl1,

[Parameter(Mandatory, HelpMessage = "Server-relative URL of the file in first tenant")]
[string]$FileUrl1,

[Parameter(Mandatory, HelpMessage = "URL of the site in second tenant")]
[string]$WebUrl2,

[Parameter(HelpMessage = "Server-relative URL of the file in second tenant (defaults to same as FileUrl1)")]
[string]$FileUrl2,

[Parameter(HelpMessage = "Name for the first tenant connection (defaults to 'tenant1')")]
[string]$Connection1Name = "tenant1",

[Parameter(HelpMessage = "Name for the second tenant connection (defaults to 'tenant2')")]
[string]$Connection2Name = "tenant2"
)

begin {
if ([string]::IsNullOrEmpty($FileUrl2)) {
$FileUrl2 = $FileUrl1
}

Write-Host "Setting up connections to both tenants..." -ForegroundColor Cyan

Write-Host "Logging in to first tenant ($WebUrl1)..." -ForegroundColor Cyan
m365 login --connectionName $Connection1Name
if ($LASTEXITCODE -ne 0) {
throw "Failed to login to first tenant"
}

Write-Host "Logging in to second tenant ($WebUrl2)..." -ForegroundColor Cyan
m365 login --connectionName $Connection2Name
if ($LASTEXITCODE -ne 0) {
throw "Failed to login to second tenant"
}

$tempDir = Join-Path $env:TEMP "CompareFiles-$(Get-Date -Format 'yyyyMMddHHmmss')"
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
$tempFile1 = Join-Path $tempDir "file1.tmp"
$tempFile2 = Join-Path $tempDir "file2.tmp"
}

process {
try {
Write-Host "`nSwitching to first tenant connection..." -ForegroundColor Cyan
m365 connection use --name $Connection1Name | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "Failed to switch to first tenant connection"
}

Write-Host "Downloading file from first tenant: $FileUrl1" -ForegroundColor Cyan
$result1 = m365 spo file get --webUrl $WebUrl1 --url $FileUrl1 --asFile --path $tempFile1 2>&1
if ($LASTEXITCODE -ne 0) {
throw "Failed to download file from first tenant: $result1"
}

Write-Host "`nSwitching to second tenant connection..." -ForegroundColor Cyan
m365 connection use --name $Connection2Name | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "Failed to switch to second tenant connection"
}

Write-Host "Downloading file from second tenant: $FileUrl2" -ForegroundColor Cyan
$result2 = m365 spo file get --webUrl $WebUrl2 --url $FileUrl2 --asFile --path $tempFile2 2>&1
if ($LASTEXITCODE -ne 0) {
throw "Failed to download file from second tenant: $result2"
}

Write-Host "`nCalculating file hashes..." -ForegroundColor Cyan
$hash1 = (Get-FileHash -Path $tempFile1 -Algorithm SHA256).Hash
$hash2 = (Get-FileHash -Path $tempFile2 -Algorithm SHA256).Hash

Write-Host "`nComparison Results:" -ForegroundColor White
Write-Host "==================" -ForegroundColor White
Write-Host "File 1 ($Connection1Name): $FileUrl1" -ForegroundColor Gray
Write-Host "Hash 1: $hash1" -ForegroundColor Gray
Write-Host "`nFile 2 ($Connection2Name): $FileUrl2" -ForegroundColor Gray
Write-Host "Hash 2: $hash2" -ForegroundColor Gray

Write-Host "`nResult: " -NoNewline
if ($hash1 -eq $hash2) {
Write-Host "Files are IDENTICAL" -ForegroundColor Green
} else {
Write-Host "Files are DIFFERENT" -ForegroundColor Red
}
} finally {
if (Test-Path $tempDir) {
Remove-Item -Path $tempDir -Recurse -Force
}
}
}

# Example 1: Compare same file across two tenants
# .\Compare-Files.ps1 -WebUrl1 "https://contoso.sharepoint.com/sites/Site1" -FileUrl1 "/Shared Documents/document.docx" -WebUrl2 "https://fabrikam.sharepoint.com/sites/Site2" -Connection1Name "contoso" -Connection2Name "fabrikam"

# Example 2: Compare different file paths
# .\Compare-Files.ps1 -WebUrl1 "https://contoso.sharepoint.com/sites/Site1" -FileUrl1 "/Shared Documents/doc1.pdf" -WebUrl2 "https://fabrikam.sharepoint.com/sites/Site2" -FileUrl2 "/Documents/doc2.pdf"

# Example 3: Compare with default connection names (tenant1, tenant2)
# .\Compare-Files.ps1 -WebUrl1 "https://contoso.sharepoint.com/sites/Site1" -FileUrl1 "/Shared Documents/report.xlsx" -WebUrl2 "https://fabrikam.sharepoint.com/sites/Site2"

```

[!INCLUDE [More about CLI for Microsoft 365](../../docfx/includes/MORE-CLIM365.md)]

***

## Contributors

| Author(s) |
|-----------|
| [Valeras Narbutas](https://github.com/ValerasNarbutas)|
| Adam Wójcik [@Adam-it](https://github.com/Adam-it)|

[!INCLUDE [DISCLAIMER](../../docfx/includes/DISCLAIMER.md)]
<img src="https://m365-visitor-stats.azurewebsites.net/script-samples/scripts/spo-compare-files" aria-hidden="true" />
<img src="https://m365-visitor-stats.azurewebsites.net/script-samples/scripts/spo-compare-files" aria-hidden="true" />
Binary file modified scripts/spo-compare-files/assets/preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 19 additions & 2 deletions scripts/spo-compare-files/assets/sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@
""
],
"creationDateTime": "2023-01-27",
"updateDateTime": "2023-01-27",
"updateDateTime": "2026-01-10",
"products": [
"SharePoint"
],
"metadata": [
{
"key": "PNP-POWERSHELL",
"value": "1.5.0"
},
{
"key": "CLI-FOR-MICROSOFT365",
"value": "11.3.0"
}
],
"categories": [
Expand All @@ -26,7 +30,10 @@
"hash",
"Connect-PnPOnline",
"Get-PnPFile",
"Get-FileHash"
"Get-FileHash",
"m365 login",
"m365 spo file get",
"m365 connection use"
],
"thumbnails": [
{
Expand All @@ -42,13 +49,23 @@
"company": "Macaw",
"pictureUrl": "https://avatars.githubusercontent.com/u/16476453?v=4",
"name": "Valeras Narbutas"
},
{
"gitHubAccount": "Adam-it",
"pictureUrl": "https://avatars.githubusercontent.com/u/58668583?v=4",
"name": "Adam Wójcik"
}
],
"references": [
{
"name": "Want to learn more about PnP PowerShell and the cmdlets",
"description": "Check out the PnP PowerShell site to get started and for the reference to the cmdlets.",
"url": "https://aka.ms/pnp/powershell"
},
{
"name": "Want to learn more about CLI for Microsoft 365 and the commands",
"description": "Check out the CLI for Microsoft 365 site to get started and for the reference to the commands.",
"url": "https://aka.ms/cli-m365"
}
]
}
Expand Down