WMI and Directory Sizes

Posted on 2006-03-24
Last Modified: 2012-06-27
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

Question by:beaconlightboy
    LVL 3

    Expert Comment

    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.
    LVL 3

    Author Comment

    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.
    LVL 3

    Expert Comment

    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.
    LVL 3

    Author Comment

    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.
    LVL 3

    Expert Comment

    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.
    LVL 3

    Expert Comment

    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.
    LVL 3

    Expert Comment

    LVL 3

    Author Comment

    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.
    LVL 3

    Accepted Solution

    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.
    LVL 3

    Author Comment

    interesting.. i will try that fso code.  i had tried some fso code that i found for 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.

    Featured Post

    Better Security Awareness With Threat Intelligence

    See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

    Join & Write a Comment

    Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
    If you’re thinking to yourself “That description sounds a lot like two people doing the work that one could accomplish,” you’re not alone.
    In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…
    In this fifth video of the Xpdf series, we discuss and demonstrate the PDFdetach utility, which is able to list and, more importantly, extract attachments that are embedded in PDF files. It does this via a command line interface, making it suitable …

    733 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    23 Experts available now in Live!

    Get 1:1 Help Now