VBS script to query server storage

Soldato
Joined
9 Oct 2006
Posts
3,761
Location
here
We use a VBS script at work to query various servers and report back the capacities and names of the attached drives. So far the script works fine when the admin account of all servers remains the same, and this is obviously something we cannot allow. So far I have this:

Function TryLocalAdminConnect
On Error Resume Next
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
Set objSWbemServices = objSWbemLocator.ConnectServer (Computer, "root\cimv2" ,"Admnistrator", "password")
If err Then
ofile.writeline Computer & ",CONNECTION ERROR : Host not found or Access Denied"
err = 0
Else

As specified this uses one set of log on details for the local admin account, but how would I specify a number of different accounts for it to use? For example if account 1 does not work, use account 2 etc etc?

Regards,

Schnippzle
 
Write a similar function and call it with the different credentials.

Code:
 Function TryAdminConnect(sComputer, sAccount, sPassword)
On Error Resume Next
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
Set objSWbemServices = objSWbemLocator.ConnectServer (sComputer, "root\cimv2" sAccount, sPassword)
If err Then
TryAdminConnect = False ' We've failed this time
Exit Function
Else
' Do something useful
TryAdminConnect = True
 
End If
 
End Function

Then just call it with the different accounts until it returns True.

EDIT: Also you do not need to provide credentials when you're connecting locally. You'll get an error if you try to.
 
Last edited:
Cheers for the tips. We don't run this locally on any servers, they are all queried over the network.

Sorry for my n00bishness but I am really clueless when it comes to VBS: so where would I add the additional accounts? Is there a possibility of using a function to use the same account name but with a different password?
 
Cheers for the tips. We don't run this locally on any servers, they are all queried over the network.

Cool, that's OK. I read the function name and thought you were running it locally on one of the comps.

Sorry for my n00bishness but I am really clueless when it comes to VBS: so where would I add the additional accounts?

How you call them is up to you. You could simply hard code the passwords at the top of the script, though, anybody with access to the script would be able to read the passwords.


Is there a possibility of using a function to use the same account name but with a different password?

Sure. If you're simply going to be testing servers with different passwords then the below would probably be best.

Code:
Function TryAdminConnect(sComputer)
On Error Resume Next
arrayPasswords = Array("test", "cheese", "moo17", "admin") ' Array of passwords to try
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
For i = 0 To UBound(arrayPasswords)
Set objSWbemServices = objSWbemLocator.ConnectServer(sComputer, "root\cimv2", "Administrator", arrayPasswords(i))
 If Err Then
    ' Output error if need be...
 
 Else
    ' Do what you need
 
    TryAdminConnect = True ' Success
    Exit Function
 End If
 
Next i
 
End Function

Then you can simply:

TryAdminConnect("server1")
TryAdminConnect("server2")
 
Sorry to sound dim, but when I try to run this I get the error Error at line 99 char 6, expected end of statement. Is this the "Next i" line?
 
The function will only attempt to use the next password if this previous one failed.

Can you post your code? Also add some sort of logging to it so I can see what exactly is going wrong something like below should do the trick

Code:
Function TryAdminConnect(sComputer)
On Error Resume Next
' Create log file objects
Set objFso = CreateObject("Scripting.FileSystemObject")
Set objLogFile = objFso.CreateTextFile("C:\ConnectLog.txt", True)
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
arrayPasswords = Array("test", "cheese", "moo17", "admin") ' Array of passwords to try
objLogFile.WriteLine "Maximum Passwords to try: " & UBound(arrayPasswords) + 1
For i = 0 To UBound(arrayPasswords)
    Set objSWbemServices = objSWbemLocator.ConnectServer(sComputer, "root\cimv2", "Administrator", arrayPasswords(i))
 
    objLogFile.WriteLine "Connection Attempt: " & i + 1
 
    If Err Then
        ' Output error if need be...
        objLogFile.WriteLine "Connection to: " & sComputer & " Using Password: " & arrayPasswords(i) & " Failed."
        objLogFile.WriteLine "Reason: " & Err.Description
        objLogFile.WriteLine "----------------------------------------------------------------------------"
 
    Else
        ' Do what you need
        objLogFile.WriteLine "Connection to: " & sComputer & " Using Password: " & arrayPasswords(i) & " Succeeded."
        objLogFile.WriteLine "Reason: N/A"
        objLogFile.WriteLine "----------------------------------------------------------------------------"
 
    TryAdminConnect = True ' Success
    Exit Function
 End If
 
Next
 
End Function
 
Last edited:
Alright man,
So far it doesnt seem to want to work. The spreadsheet that was previously generated with a few missing servers is now completely blank bar the headings. Please see attached code:
Code:
' SDSpace.vbs 
' Server Disk Space checker written by ******** 10/04/09
'
' Usage
' Requires input file containing list of computers to be checked, first connect uses logged on user credentials, if fail 
' will try local admin account.
' 
' Change Parameters below to suit
'

localdate = Date()
' wscript.echo localdate


' ************************************************************
' Parameters, Change to Suit.
' ************************************************************

InputFile="C:\Capacity Monitoring\Server list.txt" 
Outputfile="C:\Capacity Monitoring\Freespacelist_"+cstr(Year(now()))+"_"+cstr(Month(now()))+"_"+cstr(day(now()))+".csv" 


' ************************************************************

Const CONVERT_GB = 1073741824
Const HARD_DISK = 3
On Error Resume Next
Set iFSO = CreateObject("Scripting.FilesyStemObject") 
Set oFSO = CreateObject("Scripting.FilesyStemObject") 
Set ofile = ofso.createTextFile(OutputFile, True) 
Set ifile = iFSO.OpenTextFile(inputfile) 


' Open Output file and write headings
ofile.writeline "Computer,Drive,Label,Disk Size (GB),Used (GB),FreeSpace (GB),% Available" 

' Read Input file and process
Do until ifile.AtEndOfLine 
 Computer = ifile.ReadLine 
 Set objWMIService = GetObject("winmgmts:" & "{impersonationlevel=impersonate}!\\" & Computer & "\root\cimv2")
  If err Then
    ' Error Encountered using current credentials, try local Admin connect
    err = 0
    TryLocalAdminConnect
  Else
    Set colLogicalDisk = objWMIService.ExecQuery ("SELECT * FROM Win32_LogicalDisk WHERE DriveType = " & HARD_DISK & "")

     For Each objLogicalDisk In colLogicalDisk 
      If objLogicalDisk.Size <> "" Then

       WriteOutput

      End if
    Next
  End If
Loop

' **************************************************************************************************************************
'Email out resulting csv to the whole world - well at least TS team.
' **************************************************************************************************************************

ofile.Close
ExecuteShellProgram "C:\Program Files\febooti Command line email\febootimail.exe -SERVER Exchange4 -FROM ******** -TO ********* -SUBJECT Server Disk Space Report for "+cstr(Date())+" -MSG See attached for details of server disk space usage as of today -ENTER -ENTER -MSG System list located at WS010898\C:\Capacity Monitoring\Server list.txt -ATTACH "+Outputfile



Function WriteOutput

Free = FormatNumber(objLogicalDisk.FreeSpace/CONVERT_GB,2,,,0) 
Total = FormatNumber(objLogicalDisk.Size/CONVERT_GB,2,,,0)
Used = FormatNumber (Total - Free,2,,,0)
Percent = FormatNumber((Free/Total) * 100,1)
VolName = objLogicalDisk.VolumeName

ofile.writeline Computer & "," & objLogicalDisk.DeviceID & "," & VolName & "," & Total & "," & Used & "," & Free & "," & Percent
' wscript.echo Computer & "," & objLogicalDisk.DeviceID & "," & Total & "," & Used & "," & Free & "," & Percent

End Function



Function TryLocalAdminConnect
On Error Resume Next
' Create log file objects
Set objFso = CreateObject("Scripting.FileSystemObject")
Set objLogFile = objFso.CreateTextFile("C:\ConnectLog.txt", True)
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
arrayPasswords = Array("*******", "*******", "*********")
objLogFile.WriteLine "Maximum Passwords to try: " & UBound(arrayPasswords) + 2
For i = 0 To UBound(arrayPasswords)
    Set objSWbemServices = objSWbemLocator.ConnectServer(sComputer, "root\cimv2", "Administrator", arrayPasswords(i))
 
    objLogFile.WriteLine "Connection Attempt: " & i + 1
 
    If Err Then
        ' Output error if need be...
        objLogFile.WriteLine "Connection to: " & sComputer & " Using Password: " & arrayPasswords(i) & " Failed."
        objLogFile.WriteLine "Reason: " & Err.Description
        objLogFile.WriteLine "----------------------------------------------------------------------------"
 
    Else
        ' Do what you need
        objLogFile.WriteLine "Connection to: " & sComputer & " Using Password: " & arrayPasswords(i) & " Succeeded."
        objLogFile.WriteLine "Reason: N/A"
        objLogFile.WriteLine "----------------------------------------------------------------------------"
 
    TryAdminConnect = True ' Success
    Exit Function
 End If
 
Next 
 
End Function


Function ExecuteShellProgram(ByVal sFileName)

Dim poShell 
Dim poProcess
Dim iStatus

Set poShell = CreateObject("WScript.Shell")
Set poProcess = poShell.Exec(sFileName)

'Check to see if we started the process without error

if ((poProcess.ProcessID=0) and (poProcess.Status=1)) then
Err.Raise vbObjectError,,"Failed executing process"
end if

'Now loop until the process has terminated, and pull out
'any console output

Do
'Get current state of the process
iStatus = poProcess.Status

'Forward console output from launched process
'to ours
WScript.StdOut.Write poProcess.StdOut.ReadAll()
WScript.StdErr.Write poProcess.StdErr.ReadAll()

'Did the process terminate?
if (iStatus <> 0) then
Exit Do
end if
Loop 

'Return the exit code
ExecuteShellProgram = poProcess.ExitCode

End Function

Cheers for all the time and effort mate.
 
Code:
 Set iFSO = CreateObject("Scripting.FilesyStemObject") 
Set oFSO = CreateObject("Scripting.FilesyStemObject")

You only need one fso object. You'll be amending or reading files using their respective objects iFile and oFile.


Code:
 Do until ifile.AtEndOfLine 
 Computer = ifile.ReadLine 
 Set objWMIService = GetObject("winmgmts:" & "{impersonationlevel=impersonate}!\\" & Computer & "\root\cimv2")
  If err Then
    ' Error Encountered using current credentials, try local Admin connect
    err = 0
    TryLocalAdminConnect
  Else
    Set colLogicalDisk = objWMIService.ExecQuery ("SELECT * FROM Win32_LogicalDisk WHERE DriveType = " & HARD_DISK & "")
 
     For Each objLogicalDisk In colLogicalDisk 
      If objLogicalDisk.Size <> "" Then
 
       WriteOutput
 
      End if
    Next
  End If
Loop

You're calling TryLocalAdminConnect, which uses a string called sComputer to try and connect. Either set this before you call it or pass it to the Function.

You have

Computer = iFile.ReadLine

Either change it to sComputer or have the function accept arguments.

TryLocalAdminConnect (sComputer)

Then call TryLocalAdminConnect(Computer)

You also need to consider the flow of the script. Currently you try connecting using the current account, if it doesn't work you call TryLocalAdminConnect. This function doesn't return an object for you to use later on so if you look at the below


Set colLogicalDisk = objWMIService.ExecQuery ("SELECT * FROM Win32_LogicalDisk WHERE DriveType = " & HARD_DISK & "")

objWMIServer is only Set when

Set objWMIService = GetObject("winmgmts:" & "{impersonationlevel=impersonate}!\\" & Computer & "\root\cimv2")

Succeeds, if it doesn't objWMIServer is going to be Nothing and you won't be able to use it for anything that follows.

It might be helpful for you to remove On Error Resume Next that way you'll have to deal with errors as they happen.
 
To give you an idea....


Code:
' SDSpace.vbs
' Server Disk Space checker written by ******** 10/04/09
'
' Usage
' Requires input file containing list of computers to be checked, first connect uses logged on user credentials, if fail
' will try local admin account.

Dim objWMIService, objLogicalDisk ' Needs to be accessible 
Const CONVERT_GB = 1073741824
Const HARD_DISK = 3
Dim oFile, iFile
Dim Computer ' Also needs to be accessible

'
' Change Parameters below to suit

localdate = Date


' ************************************************************
' Parameters, Change to Suit.
' ************************************************************

inputfile = "C:\Server list.txt"
Outputfile = "C:\Freespacelist_" + CStr(Year(Now())) + "_" + CStr(Month(Now())) + "_" + CStr(Day(Now())) + ".csv"

' ************************************************************


Set objFSO = CreateObject("Scripting.FileSystemObject")
Set oFile = objFSO.CreateTextFile(Outputfile, True)
Set iFile = objFSO.OpenTextFile(inputfile)


Do Until iFile.AtEndOfLine
    Computer = iFile.ReadLine
    
    ' Lets use our new function to connect
    If ConnectToServer(Computer) = True Then
        'Hurray we've succeeded and we now know we can use objWMIService
        Set colLogicalDisk = objWMIService.ExecQuery("SELECT * FROM Win32_LogicalDisk WHERE DriveType = " & HARD_DISK & "")
        
        For Each objLogicalDisk In colLogicalDisk
            If objLogicalDisk.Size <> "" Then
                WriteOutput
            End If
        Next
    Else
        ' We've not been able to connect so we can't do anything else. Put it in the output file and move on
        oFile.WriteLine "Connection to " & Computer & "Failed."
    
    End If
Loop

' **************************************************************************************************************************
'Email out resulting csv to the whole world - well at least TS team.
' **************************************************************************************************************************
oFile.Close

Sub WriteOutput() ' I changed this to a Sub as it doesn't return anything.

Free = FormatNumber(objLogicalDisk.FreeSpace / CONVERT_GB, 2, , , 0)
Total = FormatNumber(objLogicalDisk.Size / CONVERT_GB, 2, , , 0)
Used = FormatNumber(Total - Free, 2, , , 0)
Percent = FormatNumber((Free / Total) * 100, 1)
VolName = objLogicalDisk.VolumeName

oFile.WriteLine Computer & "," & objLogicalDisk.DeviceID & "," & VolName & "," & Total & "," & Used & "," & Free & "," & Percent
' wscript.echo Computer & "," & objLogicalDisk.DeviceID & "," & Total & "," & Used & "," & Free & "," & Percent

End Sub



Function ConnectToServer(sComputer)
' I have modified your TryLocalAdminConnect function into ConnectToServer
' it will try and connect using the current details first. If it fails it will
' move onto the other passwords. Doing it like this means that when we return to
' the main script we'll always be sure of whether our connection attempt succeeded.

On Error Resume Next
' Create log file objects
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objLogFile = objFSO.CreateTextFile("C:\ConnectLog.txt", True)
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")

arrayPasswords = Array("*******", "*******", "*********")

Set objWMIService = GetObject("winmgmts:\\" & sComputer & "\root\cimv2")
  If Err Then
    
    Err = 0
    objLogFile.WriteLine "Maximum Passwords to try: " & UBound(arrayPasswords) + 2
    ' We've encountered an error let's try out list of passwords instead.
    For i = 0 To UBound(arrayPasswords)
        Set objWMIService = objSWbemLocator.ConnectServer(sComputer, "root\cimv2", "Administrator", arrayPasswords(i))
        objLogFile.WriteLine "Connection Attempt: " & i + 1
 
        If Err Then
            ' Output error if need be...
            objLogFile.WriteLine "Connection to: " & sComputer & " Using Password: " & arrayPasswords(i) & " Failed."
            objLogFile.WriteLine "Reason: " & Err.Description
            objLogFile.WriteLine "----------------------------------------------------------------------------"
        Else
            ' Do what you need
            objLogFile.WriteLine "Connection to: " & sComputer & " Using Password: " & arrayPasswords(i) & " Succeeded."
            objLogFile.WriteLine "Reason: N/A"
            objLogFile.WriteLine "----------------------------------------------------------------------------"
 
            ConnectToServer = True ' Success
            Exit Function
        End If
 
    Next
    Else
    ConnectToServer = True
    Exit Function
    End If
' We've tried using current credentials and have exhausted the list of passwords.
ConnectToServer = False

End Function


Function ExecuteShellProgram(ByVal sFileName)

Dim poShell
Dim poProcess
Dim iStatus

Set poShell = CreateObject("WScript.Shell")
Set poProcess = poShell.Exec(sFileName)

'Check to see if we started the process without error

If ((poProcess.ProcessID = 0) And (poProcess.Status = 1)) Then
    Err.Raise vbObjectError, , "Failed executing process"
End If

'Now loop until the process has terminated, and pull out
'any console output

Do
    'Get current state of the process
    iStatus = poProcess.Status

    'Forward console output from launched process
    'to ours
    WScript.StdOut.Write poProcess.StdOut.ReadAll()
    WScript.StdErr.Write poProcess.StdErr.ReadAll()

    'Did the process terminate?
    If (iStatus <> 0) Then
        Exit Do
    End If
Loop

'Return the exit code
ExecuteShellProgram = poProcess.ExitCode

End Function
 
Afraid to say this hasnt worked either. We have decided that we are going to go with a single account that will have minimal access rights that will run the script and check the hard drive space. This might simplify things considerably as we will eliminate the possibility of getting a password wrong. Sorry about all this dude, really appreciate all the work you put in for this but would you please show me how to just use one single domain log on for this instead of the password array?
 
Back
Top Bottom