Removing ~\r\n characters in a File [duplicate] - command-line

This question already has an answer here:
CScript and VBS to Remove Line Breaks from Text File
(1 answer)
Closed 1 year ago.
I have the following file, where each new line is created with the characters ~\r\n<CR><LF>.
Sample test file
I want to remove all occurrences of ~\r\n<CR><LF> and replace with "" (empty string) so that all the file data appears on a single line. To do this, I wrote a script in VBScript (replace.vbs) and I run it in the commandline with cscript replace.vbs "~\r\n<CR><LF>" "" - the first parameter is the original characters I want replace and the second parameter is the new text to write into the file.
My script can successfully replace regular text - for example, if I pass only <CR><LF> as the string to replace, it will work as expected. But my issue is when I pass the full ~\r\n<CR><LF>, it does not modify the file at all. I think it has something to do with the ~\r\n characters being incorrectly passed into the command.
The following is my script:
Const ForReading = 1
Const ForWriting = 2
strOldText = Wscript.Arguments(0)
strNewText = Wscript.Arguments(1)
Set objFSO = CreateObject("Scripting.FileSystemObject")
objStartFolder = "D:\FTP\Private\EDI\KleinschmidtTemp\"
Set objFolder = objFSO.GetFolder(objStartFolder)
Set colFiles = objFolder.Files
For Each objFile in colFiles
if instr(objFile.Name,"BRO") <> 0 and instr(objFile.Name,".edi") <> 0 then
Set objFileToRead = objFSO.OpenTextFile(objStartFolder + objFile.Name, ForReading)
strText = objFileToRead.ReadAll
objFileToRead.Close
strNewText = Replace(strText, strOldText, strNewText)
Set objFileToEdit = objFSO.OpenTextFile(objStartFolder + objFile.Name, ForWriting)
objFileToEdit.WriteLine strNewText
objFileToEdit.Close
objFSO.MoveFile objStartFolder + objFile.Name, "D:\FTP\Private\EDI\Kleinschmidt\Outgoing\" + objFile.Name
end if
Next
EDIT: So I found out that for our production files, <CR><LF> will not be plaintext - they are actually non printable ASCII control characters. So I made the following change to my script, I used the Chr() function to get these characters and properly replace them.
Const ForReading = 1
Const ForWriting = 2
'strOldText = Wscript.Arguments(0)
'strNewText = Wscript.Arguments(1)
Set objFSO = CreateObject("Scripting.FileSystemObject")
objStartFolder = "D:\FTP\Private\EDI\KleinschmidtTemp\"
Set objFolder = objFSO.GetFolder(objStartFolder)
Set colFiles = objFolder.Files
For Each objFile in colFiles
if instr(objFile.Name,"BRO") <> 0 and instr(objFile.Name,".edi") <> 0 then
Set objFileToRead = objFSO.OpenTextFile(objStartFolder + objFile.Name, ForReading)
strText = objFileToRead.ReadAll
objFileToRead.Close
'strNewText = Replace(strText, strOldText, strNewText)
strNewText = Replace(strText, Chr(10), "") ' 10 is ASCII code for LF, line feed
strNewText = Replace(strNewText, Chr(13), "") ' 13 is ASCII code for CR, carriage return
Set objFileToEdit = objFSO.OpenTextFile(objStartFolder + objFile.Name, ForWriting)
objFileToEdit.WriteLine strNewText
objFileToEdit.Close
'objFSO.MoveFile objStartFolder + objFile.Name, "D:\FTP\Private\EDI\Kleinschmidt\Outgoing\" + objFile.Name
end if
Next
I still have one issue though... When I open the resulting file, everything is on a single line which is what I want. But my script does not remove the <CR><LF> at the very end of the file, so there is an extra blank line. How can I fix this?
New resulting file

This is far easier to do from the command line or in a batch file. But since you are using VBScript, here's what you need to do.
First, do away with the script arguments. Passing control characters to a script argument would be a nightmare to get working correctly. Instead, we'll hardcode the search into the script. If you absolutely need to do this using arguments, comment and I'll update the script to do that but it gets a lot more confusing.
Const ForReading = 1
Const ForWriting = 2
' strOldText = Wscript.Arguments(0)
strOldText = "~" & vbCrLf & "<CR><LF>"
' strNewText = Wscript.Arguments(1)
strNewText = ""
Set objFSO = CreateObject("Scripting.FileSystemObject")
objStartFolder = "D:\FTP\Private\EDI\KleinschmidtTemp\"
Set objFolder = objFSO.GetFolder(objStartFolder)
Set colFiles = objFolder.Files
For Each objFile in colFiles
if instr(objFile.Name,"BRO") <> 0 and instr(objFile.Name,".edi") <> 0 then
Set objFileToRead = objFSO.OpenTextFile(objStartFolder + objFile.Name, ForReading)
strText = objFileToRead.ReadAll
objFileToRead.Close
strNewText = Replace(strText, strOldText, strNewText)
Set objFileToEdit = objFSO.OpenTextFile(objStartFolder + objFile.Name, ForWriting)
objFileToEdit.WriteLine strNewText
objFileToEdit.Close
objFSO.MoveFile objStartFolder + objFile.Name, "D:\FTP\Private\EDI\Kleinschmidt\Outgoing\" + objFile.Name
end if
Next
EDIT
In response to the edit, you are adding the extra line to the file when you write it back. You're using:
objFileToEdit.WriteLine
The WriteLine method appends a new line character to the end of your string. Just use Write instead.
objFileToEdit.Write strNewText

I would try "~" & vbCrLF & "" as the search. vbCrLf is the constant for the new line carriage return combo.

You can do this in Notepad++, by turning on the 'Extended' Search Mode on in the find in replace dialog box. replace \r\n with \n.
It also appears you are doing this from a Window's machine, and if you have Cygwin, or git bash on your system you can also use sed, for example:
sed -i sed 's/\r$//' input
If you don't want to edit the file in place, and test the results exclude the -i flag.

Related

How to add quotes around part of a string in VBScript that edits the registry services to include quotes around files paths

Const HKEY_LOCAL_MACHINE = &H80000002
Const REG_EXPAND_SZ = 2
strComputer = "." ' Use . for current machine
hDefKey = HKEY_LOCAL_MACHINE
strKeyPath = "SYSTEM\CurrentControlSet\Services"
On Error Resume Next
Set oReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\default:StdRegProv")
oReg.EnumKey hDefKey, strKeyPath, arrSubKeys
For Each strSubkey In arrSubKeys
strSubKeyPath = strKeyPath & "\" & strSubkey
oReg.EnumValues hDefKey, strSubKeyPath, arrValueNames, arrTypes
For i = LBound(arrValueNames) To UBound(arrValueNames)
strValueName = arrValueNames(i)
Select Case arrTypes(i)
Case REG_EXPAND_SZ
oReg.GetStringValue hDefKey, strSubKeyPath, strValueName, strValue
If InStr(1, strValue, Chr(34), 1) = 0 Then
strValueTemp = Chr(34) & strValue
wscript.echo " " & strValueName & " (REG_EXPAND_SZ) = " & strValueTemp
End IF
End Select
Next
Next
This code outputs these strings:
ImagePath (REG_EXPAND_SZ) = "C:\Windows\system32\svchost.exe -k
netsvcs -p
ImagePath (REG_EXPAND_SZ) = "C:\Windows\system32\svchost.exe -k
netsvcs -p
ImagePath (REG_EXPAND_SZ) = "\SystemRoot\System32\drivers\xboxgip.sys
How could I add another quote to each string at the point where the string has .exe or .sys providing this output.
ImagePath (REG_EXPAND_SZ) = "C:\Windows\system32\svchost.exe" -k
netsvcs -p
ImagePath (REG_EXPAND_SZ) = "C:\Windows\system32\svchost.exe" -k
netsvcs -p
ImagePath (REG_EXPAND_SZ) = "\SystemRoot\System32\drivers\xboxgip.sys"
This code is to apply fix to a Windows Security flaw.
If you are just trying to add another quote after the file extension, try this:
strValueTemp = replace(strValueTemp,".exe ",".exe" & Chr(34) & " ")
strValueTemp = replace(strValueTemp,".sys ",".sys" & Chr(34) & " ")
Note that Chr(34) corresponds to a double quote. It is also important to keep the text to be replaced as ".exe " with the space, as the space means that the quote is already missing in the string.

Email Signature - VBscript for Word, with tables

I'm trying to set a company signature and then implement it with GPO.
Here's what I'm trying to accomplish:
John Hancock | Paralegal | Company, PC
<Logo (to the left of text)> 60 Test Street | PO Box 1389 | Testing, PA 19820
Phone: 555.555.5555| Fax: 555.555.5555 | Email: testing#testing.com (need this hyperlinked)
EDIT: Additional information from comments.
I'm trying to have different attributes (font size, font type, bold, etc) for the text in each particular line within the second row of the table. For example: Test text (this is bold and Calibri) - Test Text 2 (this is not bold and Arial). When I run the script as it stands, I get the logo on the left, in the first column, and a line of text to the right of the logo, in the second column. What I can't figure out is how to add another line of text, on the right, directly underneath the first line, and have that line of text show with different font attributes and such.
Here's the code I have so far:
Set objSysInfo = CreateObject("ADSystemInfo")
Set WshShell = CreateObject("WScript.Shell")
strUser = objSysInfo.UserName
Set objUser = GetObject("LDAP://" & strUser)
strName = objUser.FullName
strFirst = objUser.FirstName
strLast = objUser.LastName
strInitials = objUser.Initials
strOffice = objUser.physicalDeliveryOfficeName
strPOBox = objUser.postOfficeBox
strTitle = objUser.Description
strCred = objUser.info
strStreet = objUser.StreetAddress
strLocation = objUser.l
strPostCode = objUser.PostalCode
strPhone = objUser.TelephoneNumber
strMobile = objUser.Mobile
strFax = objUser.FacsimileTelephoneNumber
strEmail = objUser.mail
strCompany = objUser.Company
Const NUMBER_OF_ROWS = 1
Const NUMBER_OF_COLUMNS = 2
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Add()
Set objSelection = objWord.Selection
Set objEmailOptions = objWord.EmailOptions
Set objSignatureObject = objEmailOptions.EmailSignature
Set objSignatureEntries = objSignatureObject.EmailSignatureEntries
Set objRange = objDoc.Range()
objDoc.Tables.Add objRange, NUMBER_OF_ROWS, NUMBER_OF_COLUMNS
Set objTable = objDoc.Tables(1)
Set objShape = objTable.Cell(1, 1).Range.Hyperlinks.Add(objSelection.InlineShapes.AddPicture("\\eg-fileserver\admin space\signature\logo.jpg"), "http://www.eastburngray.com",,,"")
objTable.Columns(1).Width = 20
objTable.Columns(2).Width = 320
objTable.Cell(1, 2).Range.Font.Bold = True
objTable.Cell(1, 2).Range.Font.Name = "Calibri"
objTable.Cell(1, 2).Range.Font.Size = 10
objTable.Range.ParagraphFormat.SpaceAfter = 0
objTable.Cell(1, 2).Range.Text = strFirst & strInitials & strLast & " | " & strOffice & " | " & strCompany
Set objSelection = objDoc.Range()
objSignatureEntries.Add "Full Signature", objSelection
objSignatureObject.NewMessageSignature = "Full Signature"
objDoc.Saved = True
objWord.Quit
The key to adding text with various formatting in Word is to work with a Range object. You can think of a Range like an invisible Selection, with the major difference that you can have as many Range objects as you need - there can be only one Selection. The trick to changing the formatting is to "collapse" the Range (think of it like pressing the Right- or Left-Arrow keys to a blinking "point", then continuing to type).
Edit Note: Based on bibadia's surmise that this is actually about VBScript and not VBA I've changed the tags in your question and am editing my Answer to fit VBScript. VBScript cannot use Word-specific object declarations and enumerations, so I've removed the "Dim As" and replaced all wdEnum with the Integer equivalent.
Using your code as a starting point, the approach could look something like this:
Dim rngCell
Set rngCell = objTable.Cell(1,2).Range
rngCell.ParagraphFormat.SpaceAfter = 0
rngCell.Text = strFirst & strInitials & strLast & " | " & _
strOffice & " | " & strCompany & vbCr
rngCell.Font.Bold = True
rngCell.Font.Name = "Calibri"
rngCell.Font.Size = 10
rngCell.Collapse 0 'wdCollapseEnd
rngCell.MoveEnd 1, -1 'wdCharacter, -1
rngCell.Text = strPhone & " | " & strFax & " | " & strEmail
rngCell.Font.Bold = False
rngCell.Font.Size = 8
Note 1: The order in which you do things is usually reversed from that when typing as a user: First populate the Range, then apply the formatting.
Note 2: When collapsing at the end of a cell, Word will move the Range position to the beginning of the following cell. Thus, the code moves the point back one character, putting it at the end of the previous (original) cell: rngCell.MoveEnd wdCharacter, -1
Note 3: I added a vbCr at the end of the first rngCell.Text to create the new paragraph within the table cell.

Query all objects in active directory using LDAP, vbScript or PowerShell

I'm hoping someone has already developed a script to do this.
I'm need to query all objects in AD (users, computers, containers (OU's), everything exceot for the forest root) and show which objects in AD do not have the "Include inheritable permissions from this object's parent" attribute checked.
Thanks much
If you show some initiative, I can help in VBS. I wrote a VBS a while ago to query everything in AD for below attributes via LDAP, and putting results in Excel and plain text file.
"objectCategory"
"objectClass"
"objectGUID"
"objectSid"
"sIDHistory"
"sAMAccountName"
"description"
"sAMAccountType"
"userAccountControl"
"whenCreated"
"whenChanged"
"givenName"
"sn"
"displayName"
"title"
"mail"
"physicalDeliveryOfficeName"
"memberOf"
"telephoneNumber"
"mobile"
"pager"
"company"
"lastLogon"
"badPwdCount"
"badPasswordTime"
"streetAddress"
"l"
"postalCode"
"st"
"co"
I will show you my first 50/360 lines of code:
Const ADS_SCOPE_SUBTREE = 2
Const PageSize = 2000
Const GAP = "——————————————————————————————————————————————————"
'=== Public Variables ===
Dim aADProp, sRootLDAP, oRecordSet, oFSO, oLogFile, oExcel, oWB, oWS
Dim lObjects, lComputersEnabled, lUsersEnabled, lComputersDisabled, lUsersDisabled, lOtherDisabled, lExcelRow
Dim aUAC ' AD's UserAccountControl flags array
Dim aSAT ' AD's sAMAccountType flags array
'==================================================
Main
'==================================================
Sub Main
Init
ConnectAD
If Err.Number = 0 Then ProcessRecords
CleanUp
End Sub
'--------------------------------------------------
Sub Init
Dim dNow
dNow = Now
Wscript.echo dNow & vbTab & "Init"
DefineADProp
DefineUACArray
DefineSATArray
Set oFSO = CreateObject("scripting.filesystemobject")
Set oLogFile = oFSO.CreateTextFile(WScript.ScriptFullName & "_" & Join(Array(Year(dNow),Month(dNow),Day(dNow)),".") & ".log")
sRootLDAP = "'LDAP://" & GetObject("LDAP://RootDSE").Get("defaultNamingContext") & "'"
LogT vbCrlf & Q(WScript.ScriptFullName) & " started."
Logg "RootLDAP: " & sRootLDAP
Logg "Listing AD Attributes: " & Join(aADProp,", ")
Logg GAP
lObjects = 0
lUsersEnabled = 0
lUsersDisabled = 0
lComputersEnabled = 0
lComputersDisabled = 0
lOtherDisabled = 0
If Err.Number = 0 Then
lExcelRow = 1
Set oExcel = CreateObject("Excel.Application")
oExcel.visible = True
Set oWB = oExcel.Workbooks.Add
Set oWS = oWB.Worksheets(1)
oWS.Cells(lExcelRow,1) = "distinguishedName"
oWS.Range(oWS.Cells(lExcelRow,2),oWS.Cells(lExcelRow,UBound(aADProp)+2)) = aADProp
End If
End Sub
Yes I made a mistake and didn't post the question initially. When I posted originally, I wasn't able to enumerate all AD objects and had a question about that, but it is since been resolved and the code below works (in case anyone else needs it - sharing is OK). No need to try and reinvent the wheel if the code already existed. And many thanks to Rems # Petri
'
'//----------------------------- Code below -----------------------------//
'
Const SE_DACL_PROTECTED = &H1000
Dim objRootDSE
With WScript.CreateObject("WScript.Network")
Set objRootDSE = GetObject ("LDAP://" & .UserDomain & "/RootDSE")
End With
strDomainDN = objRootDSE.Get("DefaultNamingContext")
Set objCommand = CreateObject("ADODB.Command")
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
objCommand.ActiveConnection = objConnection
objCommand.Properties("Searchscope") = 2 ' SUBTREE
objCommand.Properties("Page Size") = 250
objCommand.Properties("Timeout") = 30
objCommand.Properties("Cache Results") = False
objCommand.CommandText = "SELECT ADsPath FROM 'LDAP://" & strDomainDN & "'"
Set objRecordSet = objCommand.Execute
On Error Resume Next
If Not objRecordSet.eof Then
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
ModUser objRecordSet.Fields("ADsPath").Value
objRecordSet.MoveNext
Loop
End If
objRecordset.Close : objConnection.Close
wscript.echo vbCrLf & "-- All done --" : wscript.quit 0
Sub ModUser(strADsPath)
Dim objUser, objNtSecurityDescriptor, intNtSecurityDescriptorControl
Set objuser = GetObject(strADsPath)
Set objNtSecurityDescriptor = objUser.Get("ntSecurityDescriptor")
intNtSecurityDescriptorControl = objNtSecurityDescriptor.Control
If (intNtSecurityDescriptorControl And SE_DACL_PROTECTED) Then
Wscript.Echo objUser.sAMAccountName & " (" & objUser.distinguishedName & ") is NOT checked"
End If
End Sub

Compare 2 listboxes and show nonmatching values in 3rd listbox

I've been working on this for 2 days. Basically I have 2 ListBoxes and I want a command button to compare the values and show the non-matching values (those that appear in the first listbox but not in the 2nd) and list them in the 3rd listbox. I'm not sure if this is the best way to go about it but here's my code. It errors on the line with the message:
Wrong number of arguments or invalid property assignment
My listboxes are named CompList1, CompList2 and CompList3.
Dim BoolAdd As Boolean, I As Long, j As Long
'Set initial Flag
BoolAdd = True
'If CompList2 is empty then abort operation
If CompList2.ListCount = 0 Then
MsgBox "Nothing to compare"
Exit Sub
'If CompList1 is empty then copy entire CompList2 to CompList3
ElseIf CompList1.ListCount = 0 Then
For I = 0 To CompList2.ListCount
CompList3.AddItem CompList2.Value
Next I
Else
For I = CompList2.ListCount - 1 To 0 Step -1
For j = 0 To CompList1.ListCount
If CompList2.ListCount(I) = CompList1.ListCount(j) Then
'If match found then abort
BoolAdd = False
Exit For
End If
DoEvents
Next j
'If not found then add to CompList3
If BoolAdd = True Then CompList3.AddItem CompList2.Value
DoEvents
Next I
End If
Some notes:
Dim tdf1 As TableDef
Dim tdf2 As TableDef
Dim db As Database
Set db = CurrentDb
Set tdf1 = db.TableDefs(Me.CompList1.RowSource)
For Each fld In tdf1.Fields
sFields = sFields & ";" & fld.Name
Next
sFields = sFields & ";"
Set tdf2 = db.TableDefs(Me.CompList2.RowSource)
For Each fld In tdf2.Fields
sf = ";" & fld.Name & ";"
sFields = Replace(sFields, sf, ";")
Next
Me.CompList3.RowSource = Mid(sFields,2)
Edit:

Renaming a Word document and saving its filename with its first 10 letters

I have recovered some Word documents from a corrupted hard drive using a piece of software called photorec. The problem is that the documents' names can't be recovered; they are all renamed by a sequence of numbers. There are over 2000 documents to sort through and I was wondering if I could rename them using some automated process.
Is there a script I could use to find the first 10 letters in the document and rename it with that? It would have to be able to cope with multiple documents having the same first 10 letters and so not write over documents with the same name. Also, it would have to avoid renaming the document with illegal characters (such as '?', '*', '/', etc.)
I only have a little bit of experience with Python, C, and even less with bash programming in Linux, so bear with me if I don't know exactly what I'm doing if I have to write a new script.
How about VBScript? Here is a sketch:
FolderName = "C:\Docs\"
Set fs = CreateObject("Scripting.FileSystemObject")
Set fldr = fs.GetFolder(Foldername)
Set ws = CreateObject("Word.Application")
For Each f In fldr.Files
If Left(f.name,2)<>"~$" Then
If InStr(f.Type, "Microsoft Word") Then
MsgBox f.Name
Set doc = ws.Documents.Open(Foldername & f.Name)
s = vbNullString
i = 1
Do While Trim(s) = vbNullString And i <= doc.Paragraphs.Count
s = doc.Paragraphs(i)
s = CleanString(Left(s, 10))
i = i + 1
Loop
doc.Close False
If s = "" Then s = "NoParas"
s1 = s
i = 1
Do While fs.FileExists(s1)
s1 = s & i
i = i + 1
Loop
MsgBox "Name " & Foldername & f.Name & " As " & Foldername & s1 _
& Right(f.Name, InStrRev(f.Name, "."))
'' This uses copy, because it seems safer
f.Copy Foldername & s1 & Right(f.Name, InStrRev(f.Name, ".")), False
'' MoveFile will copy the file:
'' fs.MoveFile Foldername & f.Name, Foldername & s1 _
'' & Right(f.Name, InStrRev(f.Name, "."))
End If
End If
Next
msgbox "Done"
ws.Quit
Set ws = Nothing
Set fs = Nothing
Function CleanString(StringToClean)
''http://msdn.microsoft.com/en-us/library/ms974570.aspx
Dim objRegEx
Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.IgnoreCase = True
objRegEx.Global = True
''Find anything not a-z, 0-9
objRegEx.Pattern = "[^a-z0-9]"
CleanString = objRegEx.Replace(StringToClean, "")
End Function
Word documents are stored in a custom format which places a load of binary cruft on the beginning of the file.
The simplest thing would be to knock something up in Python that searched for the first line beginning with ASCII chars. Here you go:
#!/usr/bin/python
import glob
import os
for file in glob.glob("*.doc"):
f = open(file, "rb")
new_name = ""
chars = 0
char = f.read(1)
while char != "":
if 0 < ord(char) < 128:
if ord("a") <= ord(char) <= ord("z") or ord("A") <= ord(char) <= ord("Z") or ord("0") <= ord(char) <= ord("9"):
new_name += char
else:
new_name += "_"
chars += 1
if chars == 100:
new_name = new_name[:20] + ".doc"
print "renaming " + file + " to " + new_name
f.close()
break;
else:
new_name = ""
chars = 0
char = f.read(1)
if new_name != "":
os.rename(file, new_name)
NOTE: if you want to glob multiple directories you'll need to change the glob line accordingly. Also this takes no account of whether the file you're trying to rename to already exists, so if you have multiple docs with the same first few chars then you'll need to handle that.
I found the first chunk of 100 ASCII chars in a row (if you look for less than that you end up picking up doc keywords and such) and then used the first 20 of these to make the new name, replacing anything that's not a-z A-Z or 0-9 with underscores to avoid file name issues.