# ===== Settings =====$clientId="c9b5eaab-40cf-4e97-98ba-822241c2088c"$dateTime=Get-Date-Format"yyyy-MM-dd-HH-mm-ss"$CertPath=Read-Host"Please enter Certificate (.PFX) Path"$CertPassword=Read-Host"Please enter Certificate Password"-AsSecureString$Org="bankofenglandcouk.onmicrosoft.com"$invocation=Get-Variable-NameMyInvocation-ValueOnly$directoryPath=Split-Path$invocation.MyCommand.Path# Log file path$logFile=Join-Path$directoryPath"Log-$dateTime.csv"# Create log header"Timestamp,Message,Status"|Out-File-FilePath$logFile-Encodingutf8# ===== Logging Function =====functionLog-Message{param([string]$Message,[string]$Status="Info")switch($Status){"Success"{$color="Green"}"Info"{$color="Blue"}"Error"{$color="Red"}default{$color="White"}}Write-Host-ForegroundColor$color"$Status => $Message"$logEntry=[PSCustomObject]@{Timestamp=(Get-Date).ToString("yyyy-MM-dd HH:mm:ss")Message=$MessageStatus=$Status}$logEntry|Export-Csv-Path$logFile-Append-NoTypeInformation}functionGet-LibraryNameFromFileUrl{param([string]$fileUrl,[string]$siteUrl)# Remove base site URL$relative=$fileUrl.Replace($siteUrl,"")# Trim leading "/"if($relative.StartsWith("/")){$relative=$relative.Substring(1)}# First path segment = library name$libraryName=$relative.Split("/")[0]return$libraryName}# ===== Import CSV =====$csvPath=Read-Host"Enter path to CSV file"$rows=Import-Csv-Path$csvPathLog-Message"Loaded CSV: $csvPath""Info"# Stores connections by site URL$connectionCache=@{}foreach($rowin$rows){$fileUrl=$row.fileUrl$newEditor=$row.Editor$newAuthor=$row.Authorif(-not$fileUrl){Log-Message"Missing fileUrl in CSV row.""Error"continue}# -------- Extract site URL --------try{# Example:# https://tenant.sharepoint.com/sites/SiteA/Shared Documents/File.docx$uri=[Uri]$fileUrl# Keep: https://tenant.sharepoint.com$base="$($uri.Scheme)://$($uri.Host)"# Extract the first two segments: /sites/SiteA or /teams/TeamA$segments=$uri.AbsolutePath.Split("/")|Where-Object{$_-ne""}if($segments[0]-eq"sites"-or$segments[0]-eq"teams"){$siteUrl="$base/$($segments[0])/$($segments[1])"}else{Log-Message"Unable to determine siteUrl from $fileUrl""Error"continue}Log-Message"Derived siteUrl: $siteUrl""Info"}catch{Log-Message"Failed to parse URL: $fileUrl""Error"continue}# -------- Connect to the site (cached) --------if(-not$connectionCache.ContainsKey($siteUrl)){try{Connect-PnPOnline-ClientId$clientId`-Url$siteUrl`-CertificatePath$CertPath`-CertificatePassword$CertPassword`-Tenant$Org$connectionCache[$siteUrl]=$trueLog-Message"Connected to $siteUrl""Success"}catch{Log-Message"Connection failed for $siteUrl : $_""Error"continue}}# -------- Retrieve list item --------try{$item=Get-PnPFile-Url$fileUrl-AsListItem-ErrorActionStopLog-Message"Retrieved file: $fileUrl""Success"}catch{Log-Message"Failed to retrieve $fileUrl : $_""Error"continue}$list=Get-LibraryNameFromFileUrl-fileUrl$fileUrl-siteUrl$siteUrl# -------- Update metadata --------try{Set-PnPListItem-List$list`-Identity$item.Id`-Values@{"Author"=$newAuthor"Editor"=$newEditor"Modified"=$item.FieldValues["Modified"]}`-UpdateTypeUpdateOverwriteVersionLog-Message"Updated Author/Editor for: $fileUrl""Success"}catch{Log-Message"Failed to update $fileUrl : $_""Error"}}Log-Message"Processing complete.""Success"