WMI and Directory Sizes

ok, i have been searching forever trying to find the wmi code that will successfully give me the directory sizes.  i found this code in ex A below, on this site.  It works.
The code in Sample B does not returns only nulls, but works otherwise.  example b code my have a few typos in it as i had made changes since i posted it.  but you'll get the drift.  i want to know why A works and B does not.  i'd pay 1000 points if i could to know this answer.

Public Shared Function GetDrives(ByVal RemotePc As String) As ArrayList
        Dim P As String = "\\" & RemotePc & "\root\cimv2:"
        Dim MyManagementClass As Management.ManagementClass = New Management.ManagementClass(P & "Win32_ComputerSystem")
        Dim MyManagementObjectCollection As System.Management.ManagementObjectCollection
        Dim MyDrives As New ArrayList
            MyManagementClass.Path.RelativePath = "Win32_LogicalDisk"
            MyManagementObjectCollection = MyManagementClass.GetInstances()
            For Each obj As Management.ManagementObject In MyManagementObjectCollection
                Dim MyDrive As New System.Text.StringBuilder
        Catch e As Exception
            If Not MyManagementObjectCollection Is Nothing Then
            End If
            If Not MyManagementClass Is Nothing Then
            End If
        End Try
        Return MyDrives
    End Function

EXAMPLE B - not all the code is here, but a snippet that should show the logic

       WMI related objects
        Dim ManScope As New Management.ManagementScope
        Dim ManScopePath As New Management.ManagementPath
        Dim ManOptions As New Management.ConnectionOptions
        Dim ManObject As New Management.ManagementObject
        Dim ManCollection As Management.ManagementObjectCollection
        Dim ManObjectSearcher As New Management.ManagementObjectSearcher
        'SQL related objects
        Dim SQLCommand As New SqlClient.SqlCommand
        Dim SQLDataAdapter As New SqlClient.SqlDataAdapter
        Dim SQLMonitoredServersDataSet As New DataSet
        Dim SQLMonitoredServersDataSetRecord As DataRow

        'declaring parameters needed to save records
        Dim ServerIDPar As New SqlClient.SqlParameter

        'Setting sql command properties
        SQLCommand.Connection = SQLConnection
        SQLCommand.CommandType = CommandType.StoredProcedure

        'Populating tables we will need for this procedure

        ServerIDPar.ParameterName = "@ServerID"
        ServerSizePar.ParameterName = "@Size"
        ServerIDPar.Value = ServerID
         SQLCommand.CommandText = "MonitoredServices_Query"
        SQLDataAdapter.SelectCommand = SQLCommand

        'Setup the WMI variables needed to collec the information we want to gather
        ManOptions.Authentication = AuthenticationLevel.Packet
        ManOptions.Impersonation = ImpersonationLevel.Impersonate
        ManScopePath.Path = "\\" & ServerName & "\root\CIMV2"
        ManScope.Path = ManScopePath
        ManObjectSearcher.Scope = ManScope
        If SQLMonitoredServersDataSet.Tables(0).Rows.Count <> 0 Then
            SubProgressBarIncrement = 100 / SQLMonitoredServersDataSet.Tables(0).Rows.Count
            For Each SQLMonitoredServersDataSetRecord In SQLMonitoredServersDataSet.Tables(0).Rows
                ManObjectSearcher.Query.QueryString = "Select * from Win32_Directory  where path = " & VBQuote & SQLMonitoredServersDataSetRecord.Item(0) & VBQuote  
                ManCollection = ManObjectSearcher.Get

                For Each ManObject In ManCollection
                   ServerIDPar.value = ServerID
                   ServiceSizePar.Value = ManObject.GetPropertyValue("Size")
                SQLCommand.CommandText = "Win32_Server_Insert"
                Me.StatusBar.Panels("SubProgressBar").ProgressBarInfo.Value = Me.StatusBar.Panels("SubProgressBar").ProgressBarInfo.Value + SubProgressBarIncrement
        End If

Who is Participating?
mpemberton5Connect With a Mentor Commented:
Well, I must be dreaming because I thought I had found a script that provided directory sizes using win32_logicaldrives, but it appears that it's only the drive sizes.

However, I have tried the FSO solution connecting to remote systems, but it does require the remote systems having admin shares (which is on by default).  If you have admin rights and the remote pc's still have the admin shares (i.e. C$, D$) then you should be good to go with this:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder("\\rmtPC\C$\DirName")
Wscript.Echo objFolder.Size

Other than this or the usage of "ASSOCIATORS" shown in a previous example, I'm not sure if there are many other options.  I'll continue to browse for some other options, but so far that's the best I can offer.
Example B looks pretty good, although somewhat bloated.  One thing that may be in question is the line:

ManObjectSearcher.Query.QueryString = "Select * from Win32_Directory  where path = " & VBQuote & SQLMonitoredServersDataSetRecord.Item(0) & VBQuote

- Make sure the path that is passed to the SELECT statement has double slashes.  It would return an error if it doesn't, so this may not be your problem area.

Other than that, I'd do some incremental debugging, watching each variable, etc.
beaconlightboyAuthor Commented:
the table actuall stores the path with double back slashes.  i did notice however that the code in A is actually using win32_logicaldisk and i am trying to use win32_directory.  so i am kinda comparing apples to oranges.  i am going to modify example A to use win32_directory.  i bet it wont work when i do that though.
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

I noticed that too, and did some research on Win32_Directory.  I saw an example using it to pull directory info, thus appeared they were relatively similar in functionality.  I'd be interested in your findings.

What is it that attracts you to using Example B?  Maybe we can tweak Example A to meet your needs.
beaconlightboyAuthor Commented:
I have never written code to use example A.  i have always used example B, as that is how microsoft examples are.  i can honestly say that i have no idea what the difference between the two is.  My B example, while "bloated", is easy to follow and is not any less effecient than A.  the trick now is to see if i can get win32_directory to return a value.  if i can't then the whole purpose behind it is in my mind, and to be politically incorrect.. retarded.
No problem.  I'm with you.  I did find this code that uses the same query call and does calculate the size of the folders (listed below).  I tested this and it actually returned the directory sizes.  However, it has to go and sum up the size of each file.  What this tells me (and also with some additional testing) is that win32_directory cannot tell us the size of the folder (unlike win32_logicaldisk).

Here's the script that I found and it did in fact return the directory sizes.  Again, I'm not in favor of this method since it does have to query each file object.

'This script accompanies the book Windows Management Instrumentation
'by Matthew Lavy and Ashley Meggitt (New Riders, 2001)
'The code is copyright 2001, Matthew Lavy & Ashley Meggitt
'You are free to use and modify the script at will
'provided you understand that all code here is made available AS IS, with
'problems that result from the use of this script or any part thereof

'dirsize.vbs - prints the size of all directories on a system
Option Explicit
Dim refWMIService
Dim strDirName
Dim refDirectory

'put the name of the directory you wish to find the size of here
strDirName="c:\program files"

'get reference to WMI. Also get a direct reference to the directory
'we want to know about
set refWMIService = GetObject("winMgmts:")
set refDirectory = GetObject("winMgmts:Win32_Directory='" & strDirName & "'")

'fire our recursive function and display results
WScript.echo "Size of " & strDirName & " is " & _
      getDirectorySize(refDirectory) & " bytes."

'clean up
set refDirectory = Nothing
set refWMIService = Nothing

'------- End of script --------

'This function returns the aggregated size
'of all files in a directory and its subdirectories
Function getDirectorySize(pCurrentDir)
Dim numFSize
Dim numDSize
Dim strQuery
Dim refItem
Dim colFiles
Dim colSubdirs
numFSize = 0
numDSize = 0

'first get a reference to all files in the directory
strQuery = "ASSOCIATORS OF {Win32_Directory='" & _
            pCurrentDir.Name & "'} WHERE " & _
            "AssocClass=CIM_DirectoryContainsFile " & _
            "Role=GroupComponent ResultRole=PartComponent"
set colFiles = refWMIService.ExecQuery(strQuery)

'loop through each file and add the size of each to numFSize
For Each refItem In colFiles
      numFSize = numFSize + refItem.FileSize
set colFiles = Nothing

'now get a reference to all the subdirectories
strQuery = "ASSOCIATORS OF {Win32_Directory='" & _
            pCurrentDir.Name & "'} WHERE " & _
            "AssocClass=Win32_SubDirectory " & _
set colSubDirs = refWMIService.ExecQuery(strQuery)

'loop through each subdirectory, and add its
'size to numDSize by recursively calling this function
For Each refItem in colSubDirs
      numDSize = numDSize + getDirectorySize(refItem)
set colSubdirs = Nothing

'finally, print stats and return the total size
WScript.echo pCurrentDir.Name & ": " & numFSize & _
            " bytes in files - " & numDSize & _
            " bytes in subdirs"
getDirectorySize = numFSize + numDSize

End Function


I also tried this code to see if in fact the win32_directory object can return the size:
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colFolders = objWMIService. _
    ExecQuery("Select * From Win32_Directory Where Name = 'C:\\MyFolder'")

For Each objFolder in colFolders
    Wscript.Echo "Size: " & objFolder.Size

But it returned an error, validating that the win32_directory object in fact cannot return the size.

I'm hoping some of this helps, but I'll continue to look for things.
On a totally different wavelength, you can use the FSO and specify a UNC path name.

Dim fso, F

Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.GetFolder(path)
MsgBox (f.Size)

Just trying to find ideas for you.
beaconlightboyAuthor Commented:
the problem with the FSO solution is that it does not work for remote servers.  At least i have not found code to do that.  it doesnt have a readily available authentication method.

also, how do you get the folder size with logicaldisk?  i didnt see that as a property to read? only the disk sizes.

did i miss something.
beaconlightboyAuthor Commented:
interesting.. i will try that fso code.  i had tried some fso code that i found for vb.net but it gave me permission errors, which is odd because i the administrator.  i can't believe that gathering this information is not easier.  everything else i want to get out of WMI i can.  sometimes i just don't understand how developers can take something good, and screw it up.  lol.  your help is greatly appreciated.
All Courses

From novice to tech pro — start learning today.