简体   繁体   中英

Importing variables from TXT files to a Word document

Long story, thanks for reading :)

I'm trying to automate analyzing an AD export. I send a customer PowerShell scripts to export AD data to CSV. They send me the CSV files, I import those into an analytic tool called WeGalvanice ACL (ACL for short). Within ACL I am able to filter/match/compare and whatever I need doing.

So far all good. Now I want to use those results and put them in a .docx file, and here comes trouble. ACL cant export to docx, only xlsx/txt/csv/html/json/del.

Ok well we can work around that (or so i thought), I made a template.docx within that template.docx I wrote the placeholders like %certainvariable% .

Within ACL I created a command to write all variables I need to files called %variablename%.txt and within the txt is the value I need.

For example:

ACL creates disabledusers.txt . If you open the txt it only shows 10, meaning we got 10 disabled users.

Then I tried to create a VBA macro to import the txt files and use the contained values to replace the according %...% text within the Word document.

This all looked to go smoothly until I noticed that after running the script I got 20 followed by that box that meanings "I have no clue how to display this char".

Prior to running the script:

运行脚本之前的图片

After running the script:

运行脚本后的图片

picture of .txt content that i import:

https://i.imgur.com/Aa90Ek4.png

And last but not least the VBS code im using from word Macro manager (for convenience I only uploaded 1 import-and-replace job, but in my script I just copied this 30 times for each file and variable):

Sub ACL()
    ' ACL Macro

    FilePath = "local folderpath\date.txt"
    TextFile = FreeFile
    Open FilePath For Input As TextFile
    new_date = Input(LOF(TextFile), TextFile)
    old_date = "%date%"
    Close TextFile

    With ActiveDocument.Content.Find
        .Forward = True
        .Wrap = wdFindStop
        .Execute findtext:=old_date, replacewith:=new_date, Replace:=wdReplaceAll
    End With    
End Sub

When I open the date.txt manualy and remove the second line then it all seems to work. But I want it automated. ;)

I tried

  • adding split textfile,/n and split new_date,/n both with \\n\\r and \\r to no avail.
  • Used sed commands to remove second line. no avail.
  • Found plenty of findstr methods to remove the so called carriage return (crlf) but either my txt files where suddenly empty, or I still got the boxes in my Word file.

I'm open for suggestions on any programming language, (im terrible at them all) ill just queue everything in the right order to make it work ;)

thanks in advance everyone! and of course ask away if you need more info

Update thanks to Tomalak i got the principle working:

    ' removes CR & LF from the end of a string (not pretty but gets the job done)
Function TrimRight(InputStr As String) As String
    While Right(InputStr, 1) = vbCr Or Right(InputStr, 1) = vbLf
        InputStr = Left(InputStr, Len(InputStr) - 1)
    Wend
    TrimRight = Trim(InputStr)
End Function

' reads any text file and returns the content as-is
Function ReadFile(FilePath As String) As String
    Dim filenum As Integer

  If Dir(FilePath) > "" Then
        filenum = FreeFile
        Open FilePath For Input As filenum
        ReadFile = Input(LOF(filenum), filenum)
        Close filenum
    Else
        Debug.Print "File not found: " & FilePath
    End If
End Function

' replaces all instances of a single word in the given document
Sub ReplaceAll(oldValue As String, newValue As String, doc As Document)
    With doc.Content.Find
        .Forward = True
        .Wrap = wdFindStop
        .Execute findtext:=oldValue, replacewith:=newValue, Replace:=wdReplaceAll
    End With
End Sub


Sub ReplaceAllVariables()
    Dim variables As Variant, variable As Variant
    Dim placeholder As String, realValue As String

    variables = Split("customer,c_adgroup,c_adgroup_Cannot_change_PW,c_adgroup_disabled,c_adgroup_enabled,c_adgroup_expire_and_disabled,c_adgroup_LockedOut,c_adgroup_Locked_and_disabled,c_adgroup_loginx,c_adgroup_loginx_disabled,c_adgroup_nolastpasswordset,c_adgroup_nologondate,c_adgroup_PWRQ_and_disabled,c_adgroup_PWx,c_adgroup_PWx_and_disabled,c_adgroup_PW_and_disabled,c_adgroup_PW_and_enabled,c_adgroup_PWRQ_and_enabled ,c_adgroup_PW_not_required,c_adgroup_PW_no_expire,c_adgroup_loginx_and_enabled,c_adusers_f_Cannot_change_PW,c_adusers_f_disabled,c_adusers_f_enabled,c_adusers_f_expire_and_disabled,c_adusers_f_LockedOut,c_adusers_f_Locked_and_disabled,c_adusers_f_loginx,c_adusers_f_loginx_disabled,c_adusers_f_nolastpasswordset,c_adusers_f_nologondate,c_adusers_f_PWRQ_and_disabled,c_adusers_f_PWx,c_adusers_f_PWx_and_disabled,c_adusers_f_PW_and_disabled,c_adusers_f_PW_not_required,c_adusers_f_PW_no_expire,c_adusers_f_loginx_and_enabled,date,c_adusers_f_PW_and_enabled,lastlogon", ",")

    For Each variable In variables
        placeholder = "%" & variable & "%"
        realValue = ReadFile("C:\Users\jerryw\Documents\Klanten\ACL\AD analyse\var\" & variable & ".txt")
        realValue = TrimRight(realValue)
        ReplaceAll placeholder, realValue, ActiveDocument
    Next
End Sub

The problem seems to be the newline (CRLF). You have to get rid of it.

And while we are at it, let's also get rid of the "I've copied that code 30 times" bit, that's a horrible way to solve this problem. Loops are better.

Helpers:

' removes CR & LF from the end of a string (not pretty but gets the job done)
Function TrimRight(InputStr As String) As String
    While Right(InputStr, 1) = vbCr Or Right(InputStr, 1) = vbLf
        InputStr = Left(InputStr, Len(InputStr) - 1)
    Wend
    TrimRight = Trim(InputStr)
End Function

' reads any text file and returns the content as-is
Function ReadFile(FilePath As String) As String
    Dim filenum As Integer

    If Dir(FilePath) > "" Then
        filenum = FreeFile
        Open FilePath For Input As filenum
        ReadFile = Input(LOF(filenum), filenum)
        Close filenum
    Else
        Debug.Print "File not found: " & FilePath
    End If
End Function

' replaces all instances of a single word in the given document
Sub ReplaceAll(oldValue As String, newValue As String, doc As Document)
    With doc.content.Find
        .Forward = True
        .Wrap = wdFindStop
        .Execute findtext:=oldValue, replacewith:=newValue, Replace:=wdReplaceAll
    End With
End Sub

Worker:

Sub ReplaceAllVariables()
    Dim variables As Variant, variable As Variant
    Dim placeholder As String, realValue As String

    variables = Split("date,disabledusers,and,any,other,variable,you,have", ",")

    For Each variable In variables
        placeholder = "%" & variable & "%"
        realValue = ReadFile("\local folderpath\" & variable & ".txt")
        realValue = TrimRight(realValue)
        ReplaceAll placeholder, realValue, ActiveDocument
    Next
End Sub

The TrimRight() function only strips the final line break from the given input string. Any line breaks that are in the middle of the content are retained. If this is a thing that can happen with your data, Word will create new paragraphs for every LF it finds. And it will draw boxes for every CR it finds.

If you do have multi-line txt files, but don't want new paragraphs, and don't want boxes, either, modify the content of the text file before you use it (get rid of CRs, replace the LFs with vertical tabs, which are Word's way to represent "soft breaks", ie the same thing you get with Shift+Enter):

realValue = ReadFile("\local folderpath\" & variable & ".txt")
realValue = TrimRight(realValue)
realValue = Replace(Replace(realValue, vbCr, ""), vbLf, vbVerticalTab)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM