Update URL's link Inside Office (docx, xlsx) documents
-
08-02-2021 - |
Question
We need to change the root of our SharePoint 2013 Document Management site collection due to a company ownership change from Sharepoint.acb.net
to Sharepoint.xyz.net
. I configured everything using the "alternate access mappings" and SharePoint now work perfectly with both address.
Before decommissioning the Sharepoint.acb.net
DNS, we need to update literally thousands of documents that have links to others SharePoint documents. Those documents are mostly Word document (.docx), but we also have some Excel (.xlsx).
I'm hoping I could batch update the URLs inside of those Office Documents without manually opening them to change all the links, maybe something with powershell?
Bonus point for batch updating the corporate logo's URL in the 300 content type document templates.
Solution
I found a way of doing this by accessing the library files in file explorer.
The idea is to connect to the SharePoint server via the \\MYSERVERNAME\DavWWWRoot\
Documents were easy to update via the .Hyperlinks
collection, but the corporate logo was in a linkedImage
buried in the header. The path to reach it is Document.Sections(i).headers(j).Range.InlineShapes(k).SourceFullName
All our document come from document types, so template are in Template are in the \MYSERVERNAME\DavWWWRoot\Library\Forms\DocumentTypes
We will do this Site by site because we have to re-approve all documents manually via the official workflow, but must of the job is done.
The script must be run by a site admin on a computer where Word and Excel is installed.
Here my power-shell script, if it could help someone :
[String]$SharePointPath = "\\MYSERVERNAME\DavWWWRoot\Library"
[String[]]$OldsDomains = "Sharepoint.acb.net","Sharepoint.acb.com"
[String]$NewDomain = "Sharepoint.xyz.net"
[String[]]$NotALibrary = "Documents","Documents partages","images","Lists","m","Pages","PublishingImages","SiteAssets","SitePages","Workflows","WorkflowTasks"
function UpdateExcelFileLinks($File, [String[]]$OldsDomains, [String]$NewDomain){
$Excel = New-Object -ComObject excel.application
$Excel.Visible = $false
#"Opening Excel file: {0}" -f $File.FullName
$ExcelWorkbook = $Excel.Workbooks.open($File.FullName)
#"Processing file: {0}" -f $ExcelWorkbook.FullName
$somethingChanged = $FALSE;
#"Processing Hyperlinks of : {0}" -f $ExcelWorkbook.FullName
foreach ($Worksheet in $ExcelWorkbook.Worksheets){
foreach ($Link in $Worksheet.Hyperlinks){
#"link {0}" -f $Link.Address
foreach ($OldDomain in $OldsDomains){
if ($Link.Address -like "http://$OldDomain/*") {
$NewAddress = $Link.Address -Replace $OldDomain,$NewDomain
"Updating {0}" -f $Link.Address
" to {0}" -f $NewAddress
$Link.Address = $NewAddress
$somethingChanged = $TRUE
}
}
}
}
if ($somethingChanged -eq $TRUE) {
"Saving changes to {0}" -f $ExcelWorkbook.Fullname
$ExcelWorkbook.Save()
}
#"Completed processing of {0} `r`n" -f $ExcelWorkbook.Fullname
$ExcelWorkbook.Close($FALSE)
$Excel.Quit()
}
function UpdateWordFileLinks($File, [String[]]$OldsDomains, [String]$NewDomain){
$Word = New-Object -ComObject word.application
$Word.Visible = $false
#"Opening WORD file: {0}" -f $File.FullName
$WordDocument = $Word.documents.open($File.FullName)
#"Processing file: {0}" -f $WordDocument.FullName
$somethingChanged = $FALSE;
#"Processing headers of : {0}" -f $WordDocument.FullName
foreach ($section in $WordDocument.Sections) {
#"section.headers.count: {0}" -f $section.headers.count
foreach ($header in $section.headers) {
#"header.Range.InlineShapes: {0}" -f $header.Range.InlineShapes.count
foreach ($inlineShape in $header.Range.InlineShapes) {
# 4 = wdInlineShapeLinkedPicture 4 Linked picture.
#"image.Type: {0}" -f $image.Type
if ($inlineShape.Type -eq 4){
foreach ($OldDomain in $OldsDomains){
if ($inlineShape.LinkFormat.SourceFullName -like "http://$OldDomain/*") {
$NewAddress = $inlineShape.LinkFormat.SourceFullName -Replace $OldDomain,$NewDomain
"Updating {0}" -f $inlineShape.LinkFormat.SourceFullName
" to {0}" -f $NewAddress
$inlineShape.LinkFormat.SourceFullName = $NewAddress
$inlineShape.AlternativeText = $NewAddress
$somethingChanged = $TRUE
}
}
}
}
}
}
#"Processing Hyperlinks of : {0}" -f $WordDocument.FullName
foreach ($Link in $WordDocument.Hyperlinks){
foreach ($OldDomain in $OldsDomains){
if ($Link.Address -like "http://$OldDomain/*") {
$NewAddress = $Link.Address -Replace $OldDomain,$NewDomain
"Updating {0}" -f $Link.Address
" to {0}" -f $NewAddress
$Link.Address = $NewAddress
$somethingChanged = $TRUE
}
}
}
if ($somethingChanged -eq $TRUE) {
"Saving changes to {0}" -f $WordDocument.Fullname
$WordDocument.Save()
}
#"Completed processing of {0} `r`n" -f $WordDocument.Fullname
$WordDocument.Close($FALSE)
$Word.Quit()
}
function UpdateFileLinks($File, [String[]]$OldsDomains, [String]$NewDomain){
$FileExt = $File.Name.Split(".")[-1]
switch ($FileExt)
{
docx {
UpdateWordFileLinks -File $File -OldsDomains $OldsDomains -NewDomain $NewDomain
}
dotx {
UpdateWordFileLinks -File $File -OldsDomains $OldsDomains -NewDomain $NewDomain
}
xlsx {
UpdateExcelFileLinks -File $File -OldsDomains $OldsDomains -NewDomain $NewDomain
}
xltx {
UpdateExcelFileLinks -File $File -OldsDomains $OldsDomains -NewDomain $NewDomain
}
default {
#"unsuported file extention {0} `r`n" -f $FileExt
}
}
}
function UpdateLibraryLinks([String]$LibraryPath, [String[]]$OldsDomains, [String]$NewDomain){
"Processing Library '{0}' `r`n" -f $LibraryPath
$Files = Get-ChildItem -Path $LibraryPath -File
foreach ($File in $Files){
UpdateFileLinks -File $File -OldsDomains $OldsDomains -NewDomain $NewDomain
}
$DocumentTypesPath = $LibraryPath + "/Forms"
$DocumentTypes = Get-ChildItem -Path $DocumentTypesPath -Directory
foreach ($DocumentType in $DocumentTypes){
$Templates = Get-ChildItem -Path $DocumentType.Fullname -File
foreach ($Template in $Templates){
#"Template '{0}' `r`n" -f $Template.Fullname
UpdateFileLinks -File $Template -OldsDomains $OldsDomains -NewDomain $NewDomain
}
}
}
function UpdateLibrariesLinks([String]$SitePath, [String[]]$OldsDomains, [String]$NewDomain){
[String[]] $LibrariesPath
"Processing Site '{0}'" -f $SitePath
$Libraries = Get-ChildItem -Path $SitePath -Directory
foreach ($Library in $Libraries){
if ($NotALibrary -notcontains $Library.name) {
UpdateLibraryLinks -LibraryPath $Library.Fullname -OldsDomains $OldsDomains -NewDomain $NewDomain
}
}
}
#Sites = Get-ChildItem -Path $SharePointPath -Directory
UpdateLibrariesLinks -SitePath $SharePointPath -OldsDomains $OldsDomains -NewDomain $NewDomain