I created a disk utilization vbscript so that I can monitor free space on each individual disk on servers. The script also checks to see whether the server is part of cluster and only reports back the information for disks assigned to each specific cluster resource. Before I added AuthenticationLevel to the script, I would get the below error message, in the event log, and the script would error out, on the cluster servers:
Log Name: Application
Source: Microsoft-Windows-WMI
Date: 11/12/2010 2:57:19 PM
Event ID: 5605
Task Category: None
Level: Error
Keywords: Classic
User: N/A
Computer: ***********
Description:
Access to the root\mscluster namespace was denied because the namespace is marked with RequiresEncryption but the script or application attempted to connect to this namespace with an authentication level below Pkt_Privacy. Change the authentication level to Pkt_Privacy and run the script or application again.
After I added AuthenticationLevel to the script, the error still occurs in the event logs, on the clusters, but it returns back the correct information. Could someone let me know what I'm missing? Below is the script. I have removed the IP and domain specific information. I have put in bold the AuthenticationLevel sections.
'2345678901234567890123456789012345678901234567890123456789012345678901234567890
' Try to format for an 80 character display.
'===============================================================================
'
' NAME: disk-utilization.vbs
'
' AUTHOR: Bryan Roeben
' DATE : 20101006
'
' COMMENT: For use with APM monitoring template, for monitoring disk
' utilization. Credit to Solarwinds for "borrowed" logic.
'
' CHANGE LOG:
' 20101027 - Cleaned up script and removed assumptions
'
' 20101109 - Added code to look at % free of individual drives, instead of the
' total % free of all drives. Added code for clusters.
'
' 20101115 - Added code to ignore drives in which the page file takes
' most of the space
'
'==========================================================================
Option Explicit
On Error Resume Next
'Exit codes to set the state of the Orion monitor
Const UP_STATE = 0
Const DOWN_STATE = 1
Const WARNING_STATE = 2
Const CRITICAL_STATE = 3
Const PAGE_DRIVE_LEVEL = 80
Const wbemFlagReturnImmediately = &h10
Const wbemFlagForwardOnly = &h20
'Set the initial % free warning and critical levels for disk monitoring
Const CRITICAL_LEVEL = 5
Const WARNING_LEVEL = 10
Dim strComputer, strNPM0, strNPM1, strUser, strPassword
Dim dblPctFree, intFree, intTotal, objItem, colItems, objSWbemLocator
Dim objSWbemServices, objArgs, objWMILocator, objWMIServices, strNetBIOS
Dim strResourceName, strFQDN, intErrorState, bolCluster, intNumDrives, Element
Dim aryResources(), aryResult, bolIsCluster, bolIsNode, bolIsResource, intCount
Dim bolMatch, strIPname, strServiceName, objPage, colPages, intPctPageFile, bolPage
Dim intCritical, intWarning
' *** Initialization of some variables ***
intCount = 0
intFree = 0
intTotal = 0
intNumDrives = 0
intErrorState = UP_STATE
bolIsCluster = 0
bolIsNode = 0
bolIsResource = 0
intCritical = 0
intWarning = 0
' Check to make sure we got the arguements that what we need
If (WScript.Arguments.Count < 3) Then
WScript.Echo "Message: Incomplete number of arguments passed to script"
WScript.Quit(FAIL)
End If
Set objArgs = WScript.Arguments
'Use the following syntax for Script Arguments field in APM Monitor script:
'${IP} ${USER} ${PASSWORD}
strComputer = objArgs(0) 'IP address of remote computer
strUser = objArgs(1) 'admin username to access remote computer
strPassword = objArgs(2) 'admin password to access remote computer
strNPM0 = "X.X.X.X" ' IP address of SDLNETMGMT01
strNPM1 = "X.X.X.X" ' IP address of SDLNPM01
'Calls Win32 Provider info
'If remote computer is Orion box, then use local wmi call.
'Otherwise use remote call.
If (strComputer = strNPM0) or (strComputer = strNPM1) Then
Set objSwbemServices = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate," _
& "authenticationLevel=pktPrivacy}!" _
& "\\" & strComputer & "\root\cimv2")
Else
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
objSWbemLocator.Security_.AuthenticationLevel = 6
objSWbemLocator.Security_.ImpersonationLevel = 3
Set objSWbemServices = objSWbemLocator.ConnectServer( _
strComputer, "root\cimv2", strUser, strPassword)
End If
'Determines if the server is part of cluster
Set colItems = objSwbemServices.ExecQuery("Select * from Win32_Service")
For Each objItem in colItems
If objItem.Name = "ClusSvc" Then
bolIsCluster = 1
End If
Next
If bolIsCluster Then
'Calls Failover Cluster Provider info
'If remote computer is Orion box, then use local wmi call.
'Otherwise use remote call.
If (strComputer = strNPM0) or (strComputer = strNPM1) Then
Set objWMIServices = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate," _
& "authenticationLevel=pktPrivacy}!" _
& "\\" & strComputer & "\root\mscluster")
Else
Set objWMILocator = CreateObject("WbemScripting.SWbemLocator")
objWMILocator.Security_.AuthenticationLevel = 6
objWMILocator.Security_.ImpersonationLevel = 3
Set objWMIServices = objWMILocator.ConnectServer( _
strComputer, "root\mscluster", strUser, strPassword)
End If
strFQDN = NSlookup(strComputer)
strNetBIOS = RemoveDomain(strFQDN, "")
'Determines whether the Orion node is a cluster node
Set colItems = objWMIServices.ExecQuery("Select * from MSCluster_Node")
For Each objItem in colItems
If objItem.Name = strNetBIOS Then
bolIsNode = 1
End If
Next
'Determines whether the Orion node is a cluster resource
Set colItems = objWMIServices.ExecQuery( _
"Select * from MSCluster_Resource where Type = 'IP Address'")
For Each objItem in colItems
If objItem.PrivateProperties.Address = strComputer Then
bolIsResource = 1
strIPname = objItem.Name
strServiceName = "MSCluster_Resource.Name=" _
& chr(34) & strIPname & chr(34)
End If
Next
'If the server is a cluster node, then get a list of all resource disks
'All disks but these are to be monitored
If bolIsNode Then
Set colItems = objWMIServices.ExecQuery( _
"Select * from MSCluster_Resource where" _
& " Type = 'Physical Disk'")
For Each objItem in colItems
ReDim Preserve aryResources(intCount)
aryResources(intCount) = Left(objItem.Name, 2)
intCount=intCount+1
Next
'If the server is a cluster resource, then get a list of all disks
'specific to the resource. These are the only disks to be monitored.
ElseIf bolIsResource Then
Set colItems = objWMIServices.ExecQuery( _
"Select * from MSCluster_ResourceGroupToResource" _
& " Where PartComponent = '" & strServiceName &"'")
For Each objItem in colItems
strResourceName = objItem.GroupComponent
Next
Set colItems = objWMIServices.ExecQuery( _
"Select * from MSCluster_ResourceGroupToResource" _
& " Where GroupComponent = '" & strResourceName &"'")
For Each objItem in colItems
ReDim Preserve aryResources(intCount)
aryResources(intCount) = Left( _
RemoveResourceInfo(objItem.PartComponent,""),2)
intCount=intCount+1
Next
End If
End If
'Obtains all physical disks on server
Set colItems = objSwbemServices.ExecQuery( _
"Select * From Win32_LogicalDisk Where DriveType = '3' and" _
& " Size > '0'", "WQL", wbemFlagReturnImmediately + wbemFlagForwardOnly)
'Enumerates Percent Free space on all drives
For Each objItem in colItems
bolPage = 1
'Obtain the page file information, if present on drive.
Set colPages = objSwbemServices.ExecQuery( _
"Select * From Win32_PageFile Where Drive = '" & objItem.Name & "'")
For Each objPage in colPages
intPctPageFile = int (100 * (objPage.FileSize / objItem.Size))
If intPctPageFile < PAGE_DRIVE_LEVEL Then
bolPage = 1
Else
bolPage = 0
End If
Next
'If server is a cluster resource, then it calculates
'percent free space for all cluster resource specific drives
If (bolIsResource AND bolPage) Then
For Each Element in aryResources
If Element = objItem.Name Then
intFree = objItem.FreeSpace
intTotal = objItem.Size
If intTotal = 0 Then
dblPctFree = 0
Else
dblPctFree = int(100 * (intFree / intTotal))
End If
If dblPctFree < CRITICAL_LEVEL Then
intCritical = intCritical + 1
intNumDrives = intNumDrives +1
Elseif dblPctFree < WARNING_LEVEL Then
intWarning = intWarning +1
intNumDrives = intNumDrives +1
End If
End If
Next
'If the server is a cluster node, then it lists percent free for all
'drives, except for resource specific ones.
ElseIf (bolIsNode AND bolPage) Then
bolMatch = 0
For Each Element in aryResources
If Element = objItem.Name Then
bolMatch = 1
End If
Next
If bolMatch = 0 then
intFree = objItem.FreeSpace
intTotal = objItem.Size
If intTotal = 0 Then
dblPctFree = 0
Else
dblPctFree = int(100 * (intFree / intTotal))
End If
If dblPctFree < CRITICAL_LEVEL Then
intCritical = intCritical + 1
intNumDrives = intNumDrives +1
Elseif dblPctFree < WARNING_LEVEL Then
intWarning = intWarning +1
intNumDrives = intNumDrives +1
End If
End If
'If server is not part of a cluster, then it calculates percent free
'for all drives.
ElseIf bolPage Then
intFree = objItem.FreeSpace
intTotal = objItem.Size
If intTotal = 0 Then
dblPctFree = 0
Else
dblPctFree = int(100 * (intFree / intTotal))
End If
If dblPctFree < CRITICAL_LEVEL Then
intCritical = intCritical + 1
intNumDrives = intNumDrives +1
Elseif dblPctFree < WARNING_LEVEL Then
intWarning = intWarning +1
intNumDrives = intNumDrives +1
End If
End If
Next
If intCritical > 0 Then
intErrorState = CRITICAL_STATE
Elseif intWarning >0 Then
intErrorState = WARNING_STATE
End If
'Outputs the results in a format useable by Orion
If intErrorState = WARNING_STATE Then
Wscript.Echo "Message: The server has drives with less than 10%" _
& " free disk space."
Elseif intErrorState = CRITICAL_STATE Then
Wscript.Echo "Message: The server has drives with less than 5%" _
& " free disk space."
Else
Wscript.Echo "Message: All drives on server have 10% or greater" _
& " free disk space."
End If
WScript.Echo "Statistic:" & Int(intNumDrives)
WScript.Quit(intErrorState)
' Function to perform an NSLookup on the provided IP address
Function NSlookup(sHost)
' Both IP address and DNS name is allowed
' Function will return the opposite
Dim oRE, bInpIP, oShell, oFS, sTemp, sTempFile, oTF, sLine, sData
Set oRE = New RegExp
oRE.Pattern = "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$"
bInpIP = False
If oRE.Test(sHost) Then
bInpIP = True
End If
Set oShell = CreateObject("Wscript.Shell")
Set oFS = CreateObject("Scripting.FileSystemObject")
sTemp = oShell.ExpandEnvironmentStrings("%TEMP%")
sTempFile = sTemp & "\" & oFS.GetTempName
'Run NSLookup via Command Prompt
'Dump results into a temp text file
oShell.Run "%ComSpec% /c nslookup.exe " & sHost _
& " >" & sTempFile, 0, True
'Open the temp Text File and Read out the Data
Set oTF = oFS.OpenTextFile(sTempFile)
'Parse the text file
Do While Not oTF.AtEndOfStream
sLine = Trim(oTF.Readline)
If LCase(Left(sLine, 5)) = "name:" Then
sData = Trim(Mid(sLine, 6))
If Not bInpIP Then
'Next line will be IP address(es)
'Line can be prefixed with "Address:" or "Addresses":
aLine = Split(oTF.Readline, ":")
sData = Trim(aLine(1))
End If
Exit Do
End If
Loop
'Close it
oTF.Close
'Delete It
oFS.DeleteFile sTempFile
If Lcase(TypeName(sData)) = LCase("Empty") Then
NSlookup = ""
Else
NSlookup = sData
End If
End Function
'Function takes a fqdn and remove the dn
Function RemoveDomain(fqdn, replStr)
Dim regEx
Set regEx = New RegExp
regEx.Pattern = ".domain.com"
regEx.IgnoreCase = True
RemoveDomain = UCase(regEx.Replace(fqdn, replStr))
End Function
'Function takes a resource name and removes the WMI info
Function RemoveResourceInfo(resource, replStr)
Dim regEx
Set regEx = New RegExp
regEx.Pattern = "MSCluster_Resource.Name=" & chr(34)
regEx.IgnoreCase = True
RemoveResourceInfo = regEx.Replace(resource, replStr)
End Function