views:

276

answers:

1

I got the following code to capture information for files on a specified drive, I ran the script againts a 600 GB hard drive on one of our servers and after a while I get the error

Out of String space; "Join". Line 34, Char 2

For this code, file script.vbs:

Option Explicit 
Dim objFS, objFld 
Dim objArgs 
Dim strFolder, strDestFile, blnRecursiveSearch 
''Dim strLines 
Dim strCsv 
''Dim i 

''    i = 0 

'   'Get the commandline parameters 
'   Set objArgs = WScript.Arguments  
'   strFolder = objArgs(0) 
'   strDestFile = objArgs(1) 
'   blnRecursiveSearch = objArgs(2) 

    '######################################## 
    'SPECIFY THE DRIVE YOU WANT TO SCAN BELOW 
    '######################################## 
    strFolder = "C:\"  
    strDestFile = "C:\InformationOutput.csv"  
    blnRecursiveSearch = True 

    'Create the FileSystemObject 
    Set objFS=CreateObject("Scripting.FileSystemObject") 
    'Get the directory you are working in  
    Set objFld = objFS.GetFolder(strFolder) 

    'Open the csv file 
    Set strCsv = objFS.CreateTextFile(strDestFile, True)  

''    'Write the csv file 
''    Set strCsv = objFS.CreateTextFile(strDestFile, True) 
    strCsv.WriteLine "File Path,File Size,Date Created,Date Last Modified,Date Last Accessed" 
''    strCsv.Write Join(strLines, vbCrLf) 

    'Now get the file details  
    GetFileDetails objFld, blnRecursiveSearch

''    'Close and cleanup objects 
''  strCsv.Close 

''    'Write the csv file 
''    Set strCsv = objFS.CreateTextFile(strDestFile, True) 
''    For i = 0 to UBound(strLines)  
''    strCsv.WriteLine strLines(i)  
''    Next  

    'Close and cleanup objects 
    strCsv.Close 
    Set strCsv = Nothing 
    Set objFld = Nothing 
    Set strFolder = Nothing 
    Set objArgs = Nothing 


'---------------------------SCAN SPECIFIED LOCATION------------------------------- 
Private Sub GetFileDetails(fold, blnRecursive)
Dim fld, fil
dim strLine(4)

on error resume next
    If InStr(fold.Path, "System Volume Information") < 1 Then
        If blnRecursive Then
            'Work through all the folders and subfolders
            For Each fld In fold.SubFolders
                GetFileDetails fld, True 
                If err.number <> 0 then
                    LogError err.Description & vbcrlf & "Folder - " & fold.Path
                    err.Clear 
                End If
            Next
        End If

        'Now work on the files
        For Each fil in fold.Files
            strLine(0) = fil.Path
            strLine(1) = fil.Size
            strLine(2) = fil.DateCreated
            strLine(3) = fil.DateLastModified
            strLine(4) = fil.DateLastAccessed

        strCsv.WriteLine Join(strLine, ",")


            if err.number <> 0 then
                LogError err.Description & vbcrlf & "Folder - " & fold.Path & vbcrlf & "File - " & fil.Name
                err.Clear 
            End If
        Next
    End If
end sub

Private sub LogError(strError)
dim strErr
    'Write the csv file
    Set strErr = objFS.CreateTextFile("C:\test\err.log", false)
    strErr.WriteLine strError
    strErr.Close

    Set strErr = nothing

End Sub

RunMe.cmd

wscript.exe "C:\temp\script\script.vbs"

How can I avoid getting this error? The server drives are quite a bit <????> and I would imagine that the CSV file would be at least 40 MB.

Edit by Guffa:
I commented out some lines in the code, using double ticks ('') so you can see where.

+2  A: 

This line joins all the lines into a huge string and writes to the file:

strCsv.Write Join(strLines, vbCrLf)

Instead, write the lines one by one:

For i = 0 to UBound(strLines)
   strCsv.WriteLine strLines(i)
Next

Edit:
To write directly to the file without storing the lines in an array first, you open the file before calling GetFileDetails, and write the string to the file instead of adding it to the array:

...
'Open the csv file
Set strCsv = objFS.CreateTextFile(strDestFile, True)

'Now get the file details
GetFileDetails objFld, blnRecursiveSearch 

'Close and cleanup objects
strCsv.Close
...

In the loop in the subroutine you write to the file

...
For Each fil in fold.Files
  strLine(0) = fil.Path
  strLine(1) = fil.Size
  strLine(2) = fil.DateCreated
  strLine(3) = fil.DateLastModified
  strLine(4) = fil.DateLastAccessed

  strCsv.Write Join(strLine, ",")
Next
...
Guffa
Thanks for the quick reply. I will modify my script and run it again. I will let you know of the outcome. Cheers
MalsiaPro
I am still having this issue error encountered "Invalid Procedure call or argument (Line 36, Char 5), your solution increases the size of the the data space within the string but is there a way to write directly to the output csv file instead of writing to array/string and then generating csv output. thanks
MalsiaPro
Yes, instead of storing the lines in an array, you can write them directly to the file. See my edit above.
Guffa
damn your good, can tell by your experience, there seems to be a glitch to this now though as I get a "Permission denied" for (Line 37, Chat2)Check the code at the top of the page as I have updated it with your code recommendation.cheers
MalsiaPro
You have code left from several different versions, you open the file twice and you write the contents to it three times. The error message is probably from when you try to use strLines as an array, but it's never assigned a value as it's not used any more.
Guffa
ok so how can I aviod this error, I have tried not using the array strLines but then when its writing to the csv the output is not correct, its wring all records on one row line.confusing to me as I havent got any experience with such scripting language.Please help if possible.Thank you
MalsiaPro
Simply use WriteLine instead of Write in the GetFileDetails subroutine. I didn't think of the line breaks when I wrote that code.
Guffa
that works but now the headers are not being written, im trying to figure out how to fix it but no luck, i will need to start learning this language from scratch, I need this code due to a job role change at work and have been given a project to create such a script if I could, but I would like to do it as it could be very helpful to get me started.Anyway cheers, appreciate your time and feedback cheers (b)
MalsiaPro
Put the line that writes the header right after the line that opens the file.
Guffa
i tried that today but i get permission denied error on (Line 33, Char 5) code (Set strCsv = objFS.CreateTextFile(strDestFile, True):)
MalsiaPro
works now, all that excess code removed, thanks man, life saver.I ran the script last night on a 600GB drive with 500GB used space and it generated a CSV file at 300MB, but I am loosing records as there is more rows then the limit that Excel can handle per spreadsheet which is 1.3Million I believe. Is it possible to save to another Excel spreadsheet when the size of the CSV reaches 180MB or the number of lines reaches 1 Million.sounds complicated, if possible it would make things alot easier if not we'll have to do it manually through notepad.Thanks for all your help
MalsiaPro
Yes, it would be possible to write to several files, but then the code gets a little more complicated. You can have a counter to keep track of how many items there are in the file, and if the counter reaches a specific value you can close the file, open a new one, and reset the counter. The check would have to be inside the GetFileDetails subroutine.
Guffa
sounds tough, but yeah it will get too complicated, what I am finding annoying is that each time I have to run the code on a different drive, i need to manually modify the drive and the output name to match the drive letter. can you setup some sort of gui or something that asks what drive to scan and what to name the output file. I have sorted out the issue with the number of rows and records by renaming the extension to txt and then importing it to Access, makes processing easier there as I can run queries. Thanks for you support cheers
MalsiaPro
There is commented code to pick up command line parameters. That could be used to accept strFolder and strDestFile from the command line. By rewriting runme.cmd to pass the parameters on to the script, you could specify the drive and file name when you run it.
Guffa
would I have to modify the runme.cmd file or would it ask the user for the input when runme.cmd is ran?I want something that would ask the user to input the drive letter and also give a name for the output.Thanks for all your replies mate
MalsiaPro
Thanks for all your help Guffa.Much appreciated, take careClosing Question
MalsiaPro