Rare Duplicate Text Issue in File Loop String Replacer Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Mark_m
Posts: 3
Joined: 26 May 2017, 13:18

Rare Duplicate Text Issue in File Loop String Replacer

26 May 2017, 13:58

For my work, we have a drive housing hundreds and hundreds of vbs scripts used for various reporting tasks. For the program we use them to interact with (SAP), we have to change the password stored in these vbs files every 90 days. Before I worked here, people would do that by hand for each one. I realized that was a pain that needed to be automated, so I wrote the following script in which you could designate a string to replace another string in a file extension of the user's choosing (vbs for this purpose) in all relevant files in the directory and subdirectories from which the script is run. Come to think of it, I really should just have them all reference a central txt file with the password or something... but for future potential uses, I'd like to get this script working properly.

Now, it does work and all vbs files are changed according to the input. The only problem is, maybe once every few hundred files, one file might either end up blank or with its contents copied twice into the same file. The one blank I've ever seen in its many uses was likely user error in stopping the script prematurely, as it has a very small window in which the file is deleted but not replaced with the adjusted text yet. Most of the time it's been issue with the contents of the file appended twice into the same one. I don't think this is due to files being in use, as I've seen this behavior in files that definitely weren't being run at the time. Fortunately for this usage, if something breaks it gets noticed and we can fix the damage pretty easily. I'd just like to get the part between the lines below more reliable, if anyone has suggestions.

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

; Place script in the directory containing the files intended to be changed
; Be careful! Script will replace words embedded in larger words. For instance,
; Changing the string 'cat' to 'dog' will change the word concatenate to condogenate, etc.

; toggles case sensitivity
StringCaseSense, On

; Accepts input for file extension to edit, string to replace and what to replace it with. Exits script if cancel is pressed at any point. Does not accept blank input
Loop
{
	Inputbox, FileExt, File Extension, Please enter the file extension you would like to affect.        (Input * to affect any and all file extensions)
	If ErrorLevel
	 ExitApp
	If FileExt !=
	 Break
}
	
Loop
{
	Inputbox, OldPass, Old String, Please enter the string to be replaced
	If ErrorLevel
	 ExitApp
	If OldPass !=
	 Break
}

Loop
{
	Inputbox, NewPass, New String, Please enter the new string
	If ErrorLevel
	 ExitApp
	If NewPass = 
	{
	 MsgBox, 3,, You have chosen to replace the string with nothing, deleting all instances of that string. Are you sure you wish to do this?
	 IfmsgBox Cancel
	  ExitApp
	 Else ifmsgBox Yes
	  Break
	} else {
	 Break
	}
}

; Remove period from the start of file extension if it exists
StringLen, StrLen, FileExt
StringTrimRight, TestStr, FileExt, (StrLen-1)
If TestStr = .
{
	StringTrimLeft, FileExt, FileExt, 1
}
;----------------------------------------------------------------------------------------------------------------------------------------------------------

;***THIS code between the lines is the bit that does all the work, for which I am having the issue****

; Loops looking through all files and subfolders in script's directory, replaces string based on input
Loop, Files, %A_WorkingDir%\*.%FileExt%, R
{
	FullName=%A_LoopFileLongPath%
	FileRead, OldFile, %FullName%
	StringReplace, NewFile, OldFile, %OldPass%, %NewPass%, All
	FileDelete, %FullName%
	FileAppend, %NewFile%, %FullName%
}

;-----------------------------------------------------------------------------------------------------------------------------------------------------------
ExitApp
User avatar
Exaskryz
Posts: 2882
Joined: 17 Oct 2015, 20:28

Re: Rare Duplicate Text Issue in File Loop String Replacer  Topic is solved

26 May 2017, 21:48

So my guess is that the FileDelete isn't taking hold for some reason. You can try checking ErrorLevel set by that command to be sure. Logging what files gave you problems in response to ErrorLevel may allow you to identify why, or at the very least allow you to change the password manually after running this script.

One concern I'd have to your approach is what if the password is something within one of these files for another purpose? If your password is some gibberish where the concern of it matching anywhere unintended in the file would be slim, probably nothing to worry about.
Mark_m
Posts: 3
Joined: 26 May 2017, 13:18

Re: Rare Duplicate Text Issue in File Loop String Replacer

26 May 2017, 23:19

You know, you're absolutely right. And I didn't even think about using FileDelete's ErrorLevel. I'll set an ErrorLevel in the morning to try again, and if it still fails call a log function for manual changing. And thankfully the passwords we choose are sufficiently complex that they wouldn't be an unintended change. There's a comment in the code for users not to change anything as simple as cat. (And a coded in warning if you try to replace a phrase with nothing). Thank you for your help!
Mark_m
Posts: 3
Joined: 26 May 2017, 13:18

Re: Rare Duplicate Text Issue in File Loop String Replacer

08 Jun 2017, 08:45

Oh, I updated the code a few days ago, but in case it's useful to anyone here's the error handling I threw in to try again if it fails, and write an error log/back up the errored file if it still fails, then alert the user of the error. I also threw in a 'please wait' gui while the script is processing files. Also, it does a check to see if the string it's replacing is even in the file before deleting and recreating it, so it only replaces the files it needs to rather than EVERY file of the chosen extension like it used to.

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

; Place script in the directory containing the files intended to be changed
; Be careful! Script will replace words embedded in larger words. For instance,
; Changing the string 'cat' to 'dog' will change the word concatenate to condogenate, etc.

; toggles case sensitivity
StringCaseSense, On

; Accepts input for file extension to edit, string to replace and what to replace it with. Exits script if cancel is pressed at any point. Does not accept blank input
Loop
{
	Inputbox, FileExt, File Extension, Please enter the file extension you would like to affect.        (Input * to affect any and all file extensions)
	If ErrorLevel
	 ExitApp
	If FileExt !=
	 Break
}
	
Loop
{
	Inputbox, OldPass, Old String, Please enter the string to be replaced
	If ErrorLevel
	 ExitApp
	If OldPass !=
	 Break
}

Loop
{
	Inputbox, NewPass, New String, Please enter the new string
	If ErrorLevel
	 ExitApp
	If NewPass = 
	{
	 MsgBox, 3,, You have chosen to replace the string with nothing, deleting all instances of that string. Are you sure you wish to do this?
	 IfmsgBox Cancel
	  ExitApp
	 Else ifmsgBox Yes
	  Break
	} else {
	 Break
	}
}

; Remove period from the start of file extension if it exists
StringLen, StrLen, FileExt
StringTrimRight, TestStr, FileExt, (StrLen-1)
If TestStr = .
{
	StringTrimLeft, FileExt, FileExt, 1
}

;---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
;below this line is the error handling code

; Create 'Please wait' GUI while running, has time stamp to not overwrite old error logs
FormatTime, errTime, , yyyy.MM.dd.hh.mm.ss

Gui, +AlwaysOnTop +Toolwindow +Disabled

Gui, Add, Text,, The script is working. Please be patient.

Gui, Show,, Please Wait...

; Loops looking through all files and subfolders in script's directory, replaces string based on input
; Checks for errors on FileDelete and FileAppend. Tries again, and if that errors as well, writes an error log in the directory the script is being run from
; Error log contains file location for manual adjustment if needed. Auto generates a backup of each errored files in a new backup folder in the errored file directory
Loop, Files, %A_WorkingDir%\*.%FileExt%, R
{
	FullName=%A_LoopFileLongPath%
	FileRead, OldFile, %FullName%
	If ErrorLevel
	{
	 FileRead, OldFile, %FullName%
	 If ErrorLevel
	 {
	  FileAppend, Read ERROR -- %FullName%`n, %A_WorkingDir%\ErrorLog%errTime%.txt
	  continue
	 }
	}
	IfinString, OldFile, %OldPass%
	{
	 StringReplace, NewFile, OldFile, %OldPass%, %NewPass%, All
	 FileDelete, %FullName%
	 If ErrorLevel 
	 {
	  FileDelete, %FullName%
	  If ErrorLevel
	  {
	   FileAppend, Deletion ERROR -- %FullName%`n, %A_WorkingDir%\ErrorLog%errTime%.txt
	  } else {
	   FileAppend, %NewFile%, %FullName%
	   If ErrorLevel
	   {
	    FileAppend, %NewFile%, %FullName%
	    If ErrorLevel
	    {
	     FileAppend, Append ERROR -- %FullName%`n, %A_WorkingDir%\ErrorLog%errTime%.txt
	     FileAppend, %NewFile%, %A_LoopFileDir%\backup\%A_LoopFileName%
	    }
	   }
	  }
	 } else {
	  FileAppend, %NewFile%, %FullName%
	  If ErrorLevel
	  {
	   FileAppend, %NewFile%, %FullName%
	   If ErrorLevel
	   {
	    FileAppend, Append ERROR -- %FullName%`n, %A_WorkingDir%\ErrorLog%errTime%.txt
	    FileAppend, %NewFile%, %A_LoopFileDir%\backup\%A_LoopFileName%
	   }
	  }
	 }
	}
}

Gui, Destroy
; If error log exists, tell user about error log. If not, tell user of successful operation.
FilePath = %A_WorkingDir%\ErrorLog%errTime%.txt
If FileExist(FilePath)
{
	MsgBox,,Error, Not all files were converted successfully. Please manually check all files listed in the error log generated in the directory from which you ran this script. If an error in editing a file was detected, a backup folder containing a copy of the file was created at the file error's location.
} else {
	MsgBox,,Conversion Complete, All files converted successfully! No errors detected.
}
ExitApp

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: doanmvu, RSable and 378 guests