Collecting disk usage data from UNC paths


If you’re not using windows or linux devices to present your CIF shares then collecting usage data can be quite tricky. We ran up against this recently while using EMC Celerra devices to present our shares.

The solution we came up with was to mount the UNC on the WhatsUp box, query the drive mount, then disconnect. As you can imagine this is quite costly and if you’re collecting from multiple CIFS shares the monitors can clash and try and use the same drive letter. To get around this we added some randomization and checking to see if a letter is free:

function random_driveletter()
	strReturn="T:"
	Randomize
	intRandom=(int(Rnd()*19))
	strReturn=CHR(70+intRandom)
	'context.logmessage "CHAR=" & strReturn
	random_driveletter=strReturn
end function

function driveexists(strtmpDrive)
	boolReturn=0
	Set objtmpFileSys = CreateObject("Scripting.FileSystemObject")
	If objtmpFileSys.DriveExists(strtmpDrive) Then
		boolReturn=1
		'context.logmessage "Drive is already in use."
	End If
	driveexists=boolReturn
end function

Drives in this case are chose from between E (ASCII character number 70) and Y (ASCII character 89). We can then cycle until we get a free letter. We’ve added in some extra checking if we cycle through too many times that will try and clear up all the drive letters so the script shouldn’t cycle through until the script times out:

numAttempts=0
do
	strDrive=random_driveletter() & ":"
	context.logmessage strDrive
	numAttempts = numAttempts+1
	if numAttempts > intCleanupThreshold then
		cleanupdriveletters()
	end if
loop while driveexists(strDrive)

The script uses the “DisplayName” field in the WhatsUp device to get the UNC path so you’ll need to setup a new device per share (or at least filesystem). To get the DisplayName field we query the WhatsUp database:

function getDisplayNamefromID(strtmpDeviceID)
	dim strReturn
	' Get the DB instance used by WhatsUp
	set objDatabase = Context.GetDB
	' Check it worked OK
	if "" = objDatabase then
		Context.SetResult  1, "Problem connecting to database"
	else
		' We need to find the reference used for this device in the PivotStatisticalMonitorTypeToDevice table first
		strQuery = "SELECT sDisplayName FROM  [WhatsUp].[dbo].[Device] where nDeviceID=" & strtmpDeviceID
		objResultSet =  objDatabase.Execute(strQuery)
		strReturn = objResultSet(0)
	end if
	getDisplayNamefromID=strReturn
end function

Then use

UNCpath=getDisplayNamefromID(Context.GetProperty("DeviceID"))

to get the path to use to map. This way we can create a single performance monitor script that is used on many shares. The advantage of this is that we can use it in Alert Center to create a single threshold configuration that includes all our CIFS shares.

Here’s the full script:

intCleanupThreshold=5

ipAddress=Context.GetProperty("Address")
UNCpath=getDisplayNamefromID(Context.GetProperty("DeviceID"))

' Get the Windows credentials for the device
strWindowsUsername = Context.GetProperty("CredWindows:DomainAndUserid")
strWindowsPassword = Context.GetProperty("CredWindows:Password")

strComputer="."
strDriveMap=UNCpath

'Timestamp
startTime = Timer()

numAttempts=0

do
	strDrive=random_driveletter() & ":"
	context.logmessage strDrive
	numAttempts = numAttempts+1
	if numAttempts > intCleanupThreshold then
		cleanupdriveletters()
	end if
loop while driveexists(strDrive)

context.logmessage strDrive & " " & strDriveMap & " took " & numAttempts & " attempts to get a free letter"

startMapTime = Timer()

Set objNetwork = CreateObject("WScript.Network")

numAttempts=0
do
	err.clear
	on error resume next
	objNetwork.MapNetworkDrive strDrive, strDriveMap,0,strWindowsUsername,strWindowsPassword
	tmpStatus=err.number
	if tmpStatus <> 0 then
		context.logmessage err.Description & " mapping drive " & strDrive & " to " & strDriveMap
		cleanupdriveletters()
	end if
	context.logmessage "err.num=" & tmpStatus
	numAttempts=numAttempts+1
	if numAttempts > intCleanupThreshold then exit do
loop while tmpStatus <> 0

endMapTime = Timer()
intMapDuration=int((endMapTime-startMapTime)*1000)
context.logmessage "Took " & intMapDuration & "ms to map " & strDrive & " to " & strDriveMap

Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colDisks = objWMIService. _
    ExecQuery("Select * from Win32_MappedLogicalDisk  where Caption = """ & strDrive & """")

For Each objDisk In colDisks
	floatPercUsed=percentage_used(objDisk.Size,objDisk.FreeSpace)
	endTime=Timer()
	intDuration=int((endTime-startTime)*1000)
	context.setvalue floatPercUsed
Next

startMapTime = Timer()
objNetwork.RemoveNetworkDrive strDrive
endMapTime = Timer()
intMapDuration=int((endMapTime-startMapTime)*1000)
context.logmessage "Took " & intMapDuration & "ms to unmap " & strDrive & " from " & strDriveMap

function percentage_used(strDiskSize,strFreeSpace)
	floatReturn=0
	floatReturn=100-Round((strFreeSpace/strDiskSize)*100,1)
	percentage_used=floatReturn
end function

function random_driveletter()
	strReturn="T:"
	Randomize
	intRandom=(int(Rnd()*19))
	'context.logmessage intRandom

	strReturn=CHR(70+intRandom)
	'context.logmessage "CHAR=" & strReturn
	random_driveletter=strReturn
end function

function driveexists(strtmpDrive)
	boolReturn=0
	Set objtmpFileSys = CreateObject("Scripting.FileSystemObject")
	If objtmpFileSys.DriveExists(strtmpDrive) Then
		boolReturn=1
		'context.logmessage "Drive is already in use."
	End If 

	driveexists=boolReturn
end function

function cleanupdriveletters()
	context.logmessage "Cleaning up driveletters to free space"
	Set objtmpNetwork = CreateObject("WScript.Network")
	for i=70 to 89 step 1
		tmpDriveLetter=CHR(i) & ":"
		context.logmessage "Processing letter " & tmpDriveLetter
		on error resume next
		objtmpNetwork.RemoveNetworkDrive tmpDriveLetter
		if err.number then
			context.logmessage tmpDriveLetter & " (" & Replace(Replace(err.description, CHR(13),""),CHR(10),"") & ")"
			err.clear
		else
			context.logmessage "Removed " & tmpDriveLetter
		end if
	next
end function

function getDisplayNamefromID(strtmpDeviceID)
	dim strReturn

	' Get the DB instance used by WhatsUp
	set objDatabase = Context.GetDB

	' Check it worked OK
	if "" = objDatabase then
		Context.SetResult  1, "Problem connecting to database"
	else
		'context.logmessage "Connected to DB OK"

		' We need to find the reference used for this device in the PivotStatisticalMonitorTypeToDevice table first
		strQuery = "SELECT sDisplayName FROM  [WhatsUp].[dbo].[Device] where nDeviceID=" & strtmpDeviceID
		objResultSet =  objDatabase.Execute(strQuery)
		strReturn = objResultSet(0)
	end if
	getDisplayNamefromID=strReturn
end function
Advertisements
Tagged , , , ,

2 thoughts on “Collecting disk usage data from UNC paths

  1. david says:

    Very nice… thanks for sharing!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: