none
adding hyperlinks to AutoCorrect RRS feed

  • Question

  • Hello,

    I hope my couple of questions are ok to be asked here:

    I am trying to add some hyperlinks to AutoCorrect via PowerShell, and I based my script on this one:

    https://superuser.com/questions/515748/add-formatted-text-to-word-autocorrect-via-powershell

    and got the following error:

    System.ArgumentException: Exception setting "AddRichText": Cannot convert the "test" value of type "string" to type "Object".

    So I tried to add some AutoCorrect entries manually via Word (replacing random words with plain text and hyperlinks) to see how they are saved in .AutoCorrect.Entries, but was not able to find the ones with hyperlinks.

    So my questions would be:

    Do you know how hyperlinks are saved in AutoCorrect / how to add hyperlinks to AutoCorrect via PowerShell?

    And how to check/access the AutoCorrect entries of the other languages than the default one (MSO*.acl or default.acl) in PowerShell?

    Thank you,


    • Moved by Bill_Stewart Thursday, September 12, 2019 1:56 PM Move to more appropriate forum
    • Edited by shoeeei Thursday, September 12, 2019 2:17 PM
    Thursday, September 12, 2019 11:28 AM

Answers

  • Since you haven't posted your code it's difficult to know what exactly has gone wrong.

    However, there is at least one problem with the script you reference from StackOverflow. For some reason it uses 2 instances of Word ($objWord and $word) - perhaps the author thought it was necessary. But it causes an exception here. I am not completely sure why because the entries.Add works OK. It could be because the call to AddRichText is being made to an *object* in $word but the Range object is in $objWord

    Doing everything via one instance appears to fix that problem.

    It may also be necessary to fix the $withRange (and possibly the $with) so that it does not include the table cell marker.

    So, making those changes, I end up with the following which works OK here:

    $objWord = New-Object -Com Word.Application $filename = 'c:\Codes.docx' $objDocument = $objWord.Documents.Open($filename) $LETable = $objDocument.Tables.Item(1) $LETableCols = $LETable.Columns.Count $LETableRows = $LETable.Rows.Count $entries = $objWord.AutoCorrect.entries Write-output "Starting to write... "

    for($r=1; $r -le $LETableRows; $r++) { $replace = $LETable.Cell($r,1).Range.Text $replace = $replace.Substring(0,$replace.Length-2) $withRange = $LETable.Cell($r,2).Range $withRange.End = $withRange.End -1 $with = $withRange.Text $format = $LETable.Cell($r,3).Range.Text $format = $format.Substring(0,$format.Length-2) Try { if($format -eq "X") { $entries.AddRichText($replace, $withRange) | out-null } else { $entries.add($replace,$with) | out-null } } Catch [system.exception] { Write-Host $_.Exception.ToString() } } $objDocument.Close() $objWord.Quit() [gc]::collect() [gc]::WaitForPendingFinalizers() $rc = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objWord)

    The rich text entries are saved correctly here. If yours are not being saved as rich text, the most likely problem is that $format is never actually "X" - perhaps it's "x", an emptry string, or a longer string.

    You can find the Rich Text entries by iterating $word.Autocorrect.Entries and looking for the entries where .RichText is True. For example, something along the following lines (I'm not very familiar with PowerShell so I leave you to improve the code).

    $objWord = New-Object -Com Word.Application
    $objWord.Visible = $true
    $objDocument = $objWord.Documents.Add()
    
    $LETable = $objDocument.Tables.Add($objDocument.Range(0,0),1,3)
    $LETable.Cell(1,1).Range.Text = 'Name'
    $LETable.Cell(1,2).Range.Text = 'Value'
    $LETable.Cell(1,3).Range.Text = 'Rich Text?'
    
    
    $entries = $objWord.AutoCorrect.Entries
    
    Write-output "Starting to write... "
    
    for($r=1; $r -le $entries.Count; $r++) {
        $entry = $entries.Item($r)
        $row = $LETable.Rows.Add()
        $row.Cells(1).Range.Text = $entry.Name
        $cellRange = $row.Cells(2).Range
        $cellRange.Collapse(1) # wdCollapseSTart
        $entry.Apply($cellRange)
        if($entry.RichText -eq $true) {
            $row.Cells(3).Range.Text = 'X'
        }
    
    }
    $objDocument.SaveAs("g:\test\autos.docx")
    $objDocument.Close()
    
    $objWord.Quit()
    
     [gc]::collect()
    
     [gc]::WaitForPendingFinalizers()
    
    # Stop Winword Process
    $rc = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objWord)

    As for the thing about accessing the ACLs for other languages, I can only provide a few hints.

    First, *formatted* autocorrects are actually stored in the normal.dot/normal.dotm template and should be accessible no matter which language is current.

    Within Word, you can access the autocorrect entries for each language by ensuring that the insertion point is in a piece of text whose proofing language is set to that language.

    When you create a new *formatted* autocorrect, it is stored in normal.dotm,a and is available no matter which proofing language is "current." So if you want exactly the same entries with exactly the same values to be available at all times, I assume you could create all your entries as rich txt ones. I haven't looked at what problems that might cause, but I suppose the obvious difficulty is that if the user ever has to delete their normal.dotm, they wiil have to reinsert all their rich text autocorrects.

    If you don't want to use rich text autocorrects or need different values in different languages, I think you would have to create a document containing both the table of autocorrect entries that you want to add, and then get the script to select a piece of text in each language that you want to add your entries to, then add the plain text entries for that language. Setting the proofing language is unfortunately not necessarily that easy, as Word seems to re-recognise languages using quite a weird algorithm, even when you uncheck the Detect Language Automatically box. I actually don't believe it has ever worked how it should. Just as an experiment, I even tried to export the text from a document in Office Open XML format then use a text editor to change a paragraph which Word had marked as Catalan to Korean (ko-KO). When I re-opened the file, Word had changed the language of that text to Afar (Djibouti)! As far as I can tell, the only way to ensure that Word won't change the language is to ensure that the relevent text is in fact in the specified language.

    If you need all plain text entries to be available for all possible proofing languages, I think you might end up creating an ACL for every proofing language. If you only want to add entries for the ACLs that already exist, the difficulty is that there does not seem to be a method within the Word object to determine which ACLs exist. So you'd have to find them in the file system, then use the language IDs in their file names to select a suitable piece of language text in the document.

    Suzanne Barnhill has a useful page about AutoCorrect lists here: http://wordfaqs.ssbarnhill.com/AutoCorrect.htm

    I had also forgotten that I'd had a look at the internal structure of .acl files a while back. Not recommended, but if you need to work with them directly, you could start at https://social.technet.microsoft.com/Forums/office/en-US/ccaf284b-2352-4be9-a34d-f227c4565c0f/what-is-the-structure-of-the-acl-files-that-are-used-in-the-autocorrect-function-of-microsoft-word


    Peter Jamieson



    • Marked as answer by shoeeei Wednesday, September 18, 2019 8:32 AM
    • Edited by Peter Jamieson Wednesday, September 18, 2019 11:08 AM
    Friday, September 13, 2019 3:12 PM

All replies

  • Since you haven't posted your code it's difficult to know what exactly has gone wrong.

    However, there is at least one problem with the script you reference from StackOverflow. For some reason it uses 2 instances of Word ($objWord and $word) - perhaps the author thought it was necessary. But it causes an exception here. I am not completely sure why because the entries.Add works OK. It could be because the call to AddRichText is being made to an *object* in $word but the Range object is in $objWord

    Doing everything via one instance appears to fix that problem.

    It may also be necessary to fix the $withRange (and possibly the $with) so that it does not include the table cell marker.

    So, making those changes, I end up with the following which works OK here:

    $objWord = New-Object -Com Word.Application $filename = 'c:\Codes.docx' $objDocument = $objWord.Documents.Open($filename) $LETable = $objDocument.Tables.Item(1) $LETableCols = $LETable.Columns.Count $LETableRows = $LETable.Rows.Count $entries = $objWord.AutoCorrect.entries Write-output "Starting to write... "

    for($r=1; $r -le $LETableRows; $r++) { $replace = $LETable.Cell($r,1).Range.Text $replace = $replace.Substring(0,$replace.Length-2) $withRange = $LETable.Cell($r,2).Range $withRange.End = $withRange.End -1 $with = $withRange.Text $format = $LETable.Cell($r,3).Range.Text $format = $format.Substring(0,$format.Length-2) Try { if($format -eq "X") { $entries.AddRichText($replace, $withRange) | out-null } else { $entries.add($replace,$with) | out-null } } Catch [system.exception] { Write-Host $_.Exception.ToString() } } $objDocument.Close() $objWord.Quit() [gc]::collect() [gc]::WaitForPendingFinalizers() $rc = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objWord)

    The rich text entries are saved correctly here. If yours are not being saved as rich text, the most likely problem is that $format is never actually "X" - perhaps it's "x", an emptry string, or a longer string.

    You can find the Rich Text entries by iterating $word.Autocorrect.Entries and looking for the entries where .RichText is True. For example, something along the following lines (I'm not very familiar with PowerShell so I leave you to improve the code).

    $objWord = New-Object -Com Word.Application
    $objWord.Visible = $true
    $objDocument = $objWord.Documents.Add()
    
    $LETable = $objDocument.Tables.Add($objDocument.Range(0,0),1,3)
    $LETable.Cell(1,1).Range.Text = 'Name'
    $LETable.Cell(1,2).Range.Text = 'Value'
    $LETable.Cell(1,3).Range.Text = 'Rich Text?'
    
    
    $entries = $objWord.AutoCorrect.Entries
    
    Write-output "Starting to write... "
    
    for($r=1; $r -le $entries.Count; $r++) {
        $entry = $entries.Item($r)
        $row = $LETable.Rows.Add()
        $row.Cells(1).Range.Text = $entry.Name
        $cellRange = $row.Cells(2).Range
        $cellRange.Collapse(1) # wdCollapseSTart
        $entry.Apply($cellRange)
        if($entry.RichText -eq $true) {
            $row.Cells(3).Range.Text = 'X'
        }
    
    }
    $objDocument.SaveAs("g:\test\autos.docx")
    $objDocument.Close()
    
    $objWord.Quit()
    
     [gc]::collect()
    
     [gc]::WaitForPendingFinalizers()
    
    # Stop Winword Process
    $rc = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objWord)

    As for the thing about accessing the ACLs for other languages, I can only provide a few hints.

    First, *formatted* autocorrects are actually stored in the normal.dot/normal.dotm template and should be accessible no matter which language is current.

    Within Word, you can access the autocorrect entries for each language by ensuring that the insertion point is in a piece of text whose proofing language is set to that language.

    When you create a new *formatted* autocorrect, it is stored in normal.dotm,a and is available no matter which proofing language is "current." So if you want exactly the same entries with exactly the same values to be available at all times, I assume you could create all your entries as rich txt ones. I haven't looked at what problems that might cause, but I suppose the obvious difficulty is that if the user ever has to delete their normal.dotm, they wiil have to reinsert all their rich text autocorrects.

    If you don't want to use rich text autocorrects or need different values in different languages, I think you would have to create a document containing both the table of autocorrect entries that you want to add, and then get the script to select a piece of text in each language that you want to add your entries to, then add the plain text entries for that language. Setting the proofing language is unfortunately not necessarily that easy, as Word seems to re-recognise languages using quite a weird algorithm, even when you uncheck the Detect Language Automatically box. I actually don't believe it has ever worked how it should. Just as an experiment, I even tried to export the text from a document in Office Open XML format then use a text editor to change a paragraph which Word had marked as Catalan to Korean (ko-KO). When I re-opened the file, Word had changed the language of that text to Afar (Djibouti)! As far as I can tell, the only way to ensure that Word won't change the language is to ensure that the relevent text is in fact in the specified language.

    If you need all plain text entries to be available for all possible proofing languages, I think you might end up creating an ACL for every proofing language. If you only want to add entries for the ACLs that already exist, the difficulty is that there does not seem to be a method within the Word object to determine which ACLs exist. So you'd have to find them in the file system, then use the language IDs in their file names to select a suitable piece of language text in the document.

    Suzanne Barnhill has a useful page about AutoCorrect lists here: http://wordfaqs.ssbarnhill.com/AutoCorrect.htm

    I had also forgotten that I'd had a look at the internal structure of .acl files a while back. Not recommended, but if you need to work with them directly, you could start at https://social.technet.microsoft.com/Forums/office/en-US/ccaf284b-2352-4be9-a34d-f227c4565c0f/what-is-the-structure-of-the-acl-files-that-are-used-in-the-autocorrect-function-of-microsoft-word


    Peter Jamieson



    • Marked as answer by shoeeei Wednesday, September 18, 2019 8:32 AM
    • Edited by Peter Jamieson Wednesday, September 18, 2019 11:08 AM
    Friday, September 13, 2019 3:12 PM
  • Thank you very much for your super complete answer you saved my life!!!

    Wednesday, September 18, 2019 11:06 AM