Dim g_oClusterUtil
Set g_oClusterUtil = new ClusterUtil
Dim oArgs
Set oArgs = WScript.Arguments
If oArgs.Count < 3 Then
g_oUtil.LogMessage _
g_oUtil.DBG_ERROR, _
"Need to provide arguments"
Wscript.Quit -1
End If
'==========================================================================
' Initialize the arguments in VBScript
'==========================================================================
Dim NodeName
NodeName = oArgs(0)
Dim GroupName
GroupName = oArgs(1)
Dim MethodName
MethodName = oArgs(2)
Dim timeoutInSeconds
timeoutInSeconds = oArgs(3)
'==========================================================================
' Main
'==========================================================================
g_oUtil.LogMessage _
g_oUtil.DBG_TRACE, _
"Started at machine local time: " & CStr(Time)
Dim e
Set e = New Error
On Error Resume Next
Dim Service
Set Service = GetObject("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy}!\\" & NodeName & "\root\mscluster")
e.Save
On Error Goto 0
If IsEmpty(Service) Or e.Number <> 0 Then
g_oUtil.ThrowScriptError "Unable to connect.", e
End If
On Error Resume Next
Dim oGroup
Set oGroup = Service.ExecQuery("select Name, State from MSCluster_ResourceGroup where Name = """ & g_oClusterUtil.EscapeString(GroupName) & """")
e.Save
On Error Goto 0
If IsEmpty(oGroup) Or e.Number <> 0 Then
g_oUtil.ThrowScriptError "The Query returned an invalid result set. Please check to see if this is a valid WMI Query.", e
End If
On Error Resume Next
Dim oRealGroup
For Each oRealGroup in oGroup
Select Case MethodName
Case "Delete" Call DeleteGroup(Service, oRealGroup)
Case "Move" Call MoveToNextNode(Service, oRealGroup)
Case "Online"
WScript.Echo "The state of the " & oRealGroup.Name & " resource group is " & ConvertNumericResourceGroupStateToString (oRealGroup.State)
WScript.Echo "Attempting to bring the resource group online"
oRealGroup.BringOnline(timeoutInSeconds)
Set oRealGroup = Service.Get(oRealGroup.Path_)
WScript.Echo "The state of the " & oRealGroup.Name & " resource group is " & ConvertNumericResourceGroupStateToString (oRealGroup.State)
Case "Offline"
WScript.Echo "The state of the " & oRealGroup.Name & " resource group is " & ConvertNumericResourceGroupStateToString (oRealGroup.State)
WScript.Echo "Attempting to take the resource group offline"
oRealGroup.TakeOffline(timeoutInSeconds)
Set oRealGroup = Service.Get(oRealGroup.Path_)
WScript.Echo "The state of the " & oRealGroup.Name & " resource group is " & ConvertNumericResourceGroupStateToString (oRealGroup.State)
Case Else g_oUtil.LogMessage _
g_oUtil.DBG_ERROR, _
"Unrecognized method " & MethodName & " used"
End Select
Next
g_oUtil.LogMessageNewLine _
g_oUtil.DBG_TRACE, _
"Finished at machine local time: " & CStr(Time)
End Sub
Function ConvertNumericResourceGroupStateToString(ByVal state)
Dim textualState
Select Case state
Case 0
textualState = "Online"
Case 1
textualState = "Offline"
Case 2
textualState = "Failed"
Case 3
textualState = "Partial Online"
Case 4
textualState = "Pending"
Case Else
textualState = "Unknown"
End Select
While DoLoop
Dim oResources
Set oResources = oService.ExecQuery("select GroupComponent, PartComponent from MSCluster_ResourceGroupToResource where GroupComponent = ""MSCluster_ResourceGroup.Name=\""" & g_oClusterUtil.EscapeString(g_oClusterUtil.EscapeString(g_oClusterUtil.EscapeString(oGroup.Name))) & "\""""")
e.Save
On Error Goto 0
If e.Number <> 0 Then
g_oUtil.ThrowScriptError "The Query for resources returned an error. Please check to see if this is a valid WMI Query.", e
End If
On Error Resume Next
If IsEmpty(oResources) Or oResources.Count = 0 Then
g_oUtil.LogMessage _
g_oUtil.DBG_TRACE, _
"No more resources in group " & oGroup.Name
DoLoop = False
Else
g_oUtil.LogMessage _
g_oUtil.DBG_TRACE, _
oResources.Count & " resources in group " & oGroup.Name
Dim oResource
For Each oResource in oResources
Dim oRes
Set oRes = oService.Get(oResource.PartComponent)
e.Save
On Error Goto 0
If IsNull(oRes) Then
Exit For
End If
If e.Number <> 0 Then
g_oUtil.ThrowScriptError "Did not get a resource. Please check to see if this is a valid WMI Query.", e
End If
On Error Resume Next
Dim oDepResources
Set oDepResources = oService.ExecQuery("select Antecedent, Dependent from MSCluster_ResourceToDependentResource where Dependent = ""MSCluster_Resource.Name=\""" & g_oClusterUtil.EscapeString(g_oClusterUtil.EscapeString(g_oClusterUtil.EscapeString(oRes.Name))) & "\""""")
e.Save
On Error Goto 0
If e.Number <> 0 Then
g_oUtil.ThrowScriptError "The Query for dependent resources returned an error. Please check to see if this is a valid WMI Query.", e
End If
On Error Resume Next
If IsEmpty(oDepResources) Or oDepResources.Count = 0 Then
DeleteResource (oRes)
End If
Next
End If
Wend
oGroup.DeleteGroup
e.Save
On Error Goto 0
If e.Number <> 0 Then
g_oUtil.ThrowScriptError "Unable to delete resource group.", e
End If
On Error Resume Next
End Sub
Sub DeleteResource (_
ByRef oRes _
)
Dim e
Set e = New Error
On Error Resume Next
If Not ( oRes.State = 4 ) Then
oRes.TakeOffline 32,767
e.Save
On Error Goto 0
If e.Number <> 0 Then
g_oUtil.ThrowScriptError "Unable to take resource " & oRes.Name & " offline.", e
End If
On Error Resume Next
End If
oRes.DeleteResource
e.Save
On Error Goto 0
If e.Number <> 0 Then
g_oUtil.ThrowScriptError "Unable to delete resource " & oRes.Name & "." , e
End If
On Error Resume Next
Dim oActiveNode
Set oActiveNode = oService.ExecQuery("select GroupComponent, PartComponent from MSCluster_NodeToActiveGroup where PartComponent = ""MSCluster_ResourceGroup.Name=\""" & g_oClusterUtil.EscapeString(g_oClusterUtil.EscapeString(g_oClusterUtil.EscapeString(oGroup.Name))) & "\""""")
e.Save
On Error Goto 0
If IsEmpty(oActiveNode) Or e.Number <> 0 Then
g_oUtil.ThrowScriptError "The Query for active node returned an invalid result set. Please check to see if this is a valid WMI Query.", e
End If
On Error Resume Next
Dim newNodeName
newNodeName = NodeName
If oActiveNode.Count > 0 Then
Dim oNode
For Each oNode in oActiveNode
Dim oActive
Set oActive = oService.Get(oNode.GroupComponent)
e.Save
On Error Goto 0
If IsNull(oActive) Then
Exit For
End If
If e.Number <> 0 Then
g_oUtil.ThrowScriptError "Did not get a Node. Please check to see if this is a valid WMI Query.", e
End If
On Error Resume Next
Dim oNodes
Set oNodes = oService.ExecQuery("select Name, State from MSCluster_Node where Name != '" & oActive.Name & "'")
e.Save
On Error Goto 0
If IsEmpty(oNodes) Or e.Number <> 0 Then
g_oUtil.ThrowScriptError "The Query for nodes returned an invalid result set. Please check to see if this is a valid WMI Query.", e
End If
On Error Resume Next
Dim oNextNode
For Each oNextNode in oNodes
' only move when node is online
If oNextNode.State = 0 Then
newNodeName = oNextNode.Name
g_oUtil.LogMessage _
g_oUtil.DBG_TRACE, _
"Trying to move group " & oGroup.Name & " to node " & newNodeName
e.Save
On Error Goto 0
If IsEmpty(oNodes) Or e.Number <> 0 Then
g_oUtil.ThrowScriptError "Get node name failed.", e
End If
On Error Resume Next
Call oGroup.MoveToNewNode ( newNodeName, 32,767 )
e.Save
On Error Goto 0
If IsEmpty(oNodes) Or e.Number <> 0 Then
g_oUtil.ThrowScriptError "Move to new node failed.", e
End If
On Error Resume Next
Exit Sub
End If
Next
Exit For
Next
End If
g_oUtil.ThrowScriptError "Unable to move group " & oGroup.Name & " as there are no online nodes.", -1
Class Error
Public Description
Public Number
Public Source
Sub Class_Initialize()
Number = 0
End Sub
Sub Save
Description = Err.Description
Number = Err.Number
Source = Err.Source
Err.Clear
End Sub
Sub Raise(strDescription)
Err.Raise Number, Source, strDescription & GetErrorString(Number, Description)
End Sub
End Class
'==========================================================================
' Class: ClusterUtil
' Description: Utility methods for clustering
'==========================================================================
Class ClusterUtil
'**********************************************************************
Public Function EscapeString(ByVal sText)
Const METACHARACTERS = """"
Dim sResult
Dim i
For i = 1 To Len(sText)
Dim sCurrentChar
sCurrentChar = Mid(sText, i, 1)
If InStr(METACHARACTERS, sCurrentChar) <> 0 Then
sResult = sResult & "\"
End If
sResult = sResult & sCurrentChar
Next
EscapeString = sResult
End Function
End Class 'ClusterUtil
'==========================================================================
' Class: Util
' Description: Utility methods for logging
'==========================================================================
Class Util
'**********************************************************************
Public Function ThrowScriptErrorNoAbort(ByVal sMessage, ByVal oErr)
LogMessage _
DBG_ERROR, _
sMessage & vbCrLf & oErr.Description
Set ThrowScriptErrorNoAbort = Nothing
End Function
'**********************************************************************
Public Function ThrowScriptError(Byval sMessage, ByVal oErr)
ThrowScriptErrorNoAbort sMessage, oErr
Quit
Set ThrowScriptError = Nothing
End Function
Public Function Quit
LogMessage _
DBG_ERROR, _
"Terminated on error!"
Wscript.Quit -1
End Function
' Used to say to LogMessage when/how to print the message.
Public DBG_NONE
Public DBG_ERROR
Public DBG_WARNING
Public DBG_TRACE
'Internal Debug Level
Private m_nDebugLevel
'======================================================================
' Method: Class_Initialize
' Description: This is the constructor
' Parameters:
'======================================================================
Private Sub Class_Initialize()
' Initialize Debug level constants
DBG_TRACE = 1
DBG_WARNING = 2
DBG_ERROR = 3
DBG_NONE = 4
'by default only errors are logged
m_nDebugLevel = DBG_ERROR
End Sub
'======================================================================
' Method: GetCurrentLevel
' Description: retrieve current logging level.
' Parameters:
'======================================================================
Public Function GetCurrentLevel()
GetCurrentLevel = m_nDebugLevel
End Function
'======================================================================
' Method: SetDebugLevel
' Description: To change the debugging output level of information
' generated by this utility.
' Parameters:
' nLevel - DBG_NONE, DBG_TRACE, DBG_WARNING or DBG_ERROR
'======================================================================
Public Sub SetDebugLevel(ByVal nLevel)
m_nDebugLevel = nLevel
End Sub
'======================================================================
' Method: LogMessage
' Description: Log a debug message to ScriptContext
' Parameters:
' nLevel - Debug level for the message that
' we're logging.
' strMessage - The message to write to the trace.
'======================================================================
Public Sub LogMessage( _
ByVal nLevel, _
ByVal strMessage _
)
If (nLevel >= GetCurrentLevel()) Then
if (nLevel = DBG_ERROR) Then
WScript.Echo "[Error]: " & strMessage
ElseIf (nLevel = DBG_WARNING) Then
WScript.Echo "[Warning]: " & strMessage
ElseIf (nLevel = DBG_TRACE) Then
WScript.Echo "[Trace]: " & strMessage
End If
End If
End Sub
Public Sub LogMessageNewLine( _
ByVal nLevel, _
ByVal strMessage _
)
If (nLevel >= GetCurrentLevel()) Then
if (nLevel = DBG_ERROR) Then
WScript.Echo vbCrLf & "[Error]: " & strMessage
ElseIf (nLevel = DBG_WARNING) Then
WScript.Echo vbCrLf & "[Warning]: " & strMessage
ElseIf (nLevel = DBG_TRACE) Then
WScript.Echo vbCrLf & "[Trace]: " & strMessage
End If
End If
End Sub
End Class ' Util </Script></Contents>
<Unicode>false</Unicode>
</File>
</Files>
</WriteAction>
</MemberModules>
<Composition>
<Node ID="WA"/>
</Composition>
</Composite>
</ModuleImplementation>
<InputType>System!System.BaseData</InputType>
</WriteActionModuleType>