Disk Partition to Logical Disk Discovery Rule

Microsoft.Windows.Server.6.2.DiskPartitionContainsLogicalDisk.Discovery (Discovery)

This rule discovers the relationships between disk partitions and logical disks

Knowledge Base article:

Summary

This Discovery Rule discovers and populates the Windows Server relationship class named "Disk Partition Contains Logical Disk" with instances of the Disk Partition contains Logical Disk relationship.

Element properties:

TargetMicrosoft.Windows.Server.6.2.DiskPartition
EnabledTrue
Frequency14400
RemotableFalse

Object Discovery Details:

Discovered relationships and their attribuets:

Member Modules:

ID Module Type TypeId RunAs 
DiscoveryDataSource DataSource Microsoft.Windows.TimedPowerShell.DiscoveryProvider Default

Source Code:

<Discovery ID="Microsoft.Windows.Server.6.2.DiskPartitionContainsLogicalDisk.Discovery" Enabled="true" Target="WindowsServer!Microsoft.Windows.Server.6.2.DiskPartition">
<Category>Discovery</Category>
<DiscoveryTypes>
<DiscoveryRelationship TypeID="Microsoft.Windows.Server.6.2.DiskPartitionContainsLogicalDisk"/>
</DiscoveryTypes>
<DataSource ID="DiscoveryDataSource" TypeID="Windows!Microsoft.Windows.TimedPowerShell.DiscoveryProvider">
<IntervalSeconds>14400</IntervalSeconds>
<SyncTime/>
<ScriptName>DiskPartitionContainsLogicalDisk.ps1</ScriptName>
<ScriptBody><Script>

param ($SourceID, $ManagedEntityId, $TargetComputer, $TargetComputerID, $DeviceID)
$ErrorActionPreference = "Stop"

# Event type constants
$EVENT_TYPE_LOG = 0
$EVENT_TYPE_ERROR = 1
$EVENT_TYPE_WARNING = 2
$EVENT_TYPE_INFORMATION = 4

# Typed property bag constants
$PROPERTY_TYPE_ALERT = 0
$PROPERTY_TYPE_EVENT = 1
$PROPERTY_TYPE_PERFORMANCE = 2
$PROPERTY_TYPE_STATE = 3

# State type constants
$STATE_SUCCESS = "Success"
$STATE_WARNING = "Warning"
$STATE_ERROR = "Error"

$momAPI = new-object -comObject MOM.ScriptAPI


# WMI Constant
$wbemCimtypeUseDefault = 0 #Use Default Type CIM type - Custom
$wbemCimtypeSint16 = 2 #Signed 16-bit integer
$wbemCimtypeSint32 = 3 #Signed 32-bit integer
$wbemCimtypeReal32 = 4 #32-bit real number
$wbemCimtypeReal64 = 5 #64-bit real number
$wbemCimtypeString = 8 #String
$wbemCimtypeBoolean = 11 #Boolean value
$wbemCimtypeObject = 13 #CIM object
$wbemCimtypeSint8 = 16 #Signed 8-bit integer
$wbemCimtypeUint8 = 17 #Unsigned 8-bit integer
$wbemCimtypeUint16 = 18 #Unsigned 16-bit integer
$wbemCimtypeUint32 = 19 #Unsigned 32-bit integer
$wbemCimtypeSint64 = 20 #Signed 64-bit integer
$wbemCimtypeUint64 = 21 #Unsigned 64-bit integer
$wbemCimtypeDatetime = 101 #Date/time value
$wbemCimtypeReference = 102 #Reference to a CIM object
$wbemCimtypeChar16 = 103 #16-bit character

$ErrAction_None = 0
$ErrAction_Trace = 1
$ErrAction_ThrowError = 16
$ErrAction_Abort = 32
$ErrAction_ThrowErrorAndAbort = 48

$DISKSIZE_BYTES_IN_MB = 1048576

$g_ErrorEventNumber = 4001
$g_TraceEventNumber = 4002
$g_DebugFlag = $false

#---------------------------------------------------------------------------
# Returns WMI Instance requested. Tries to execute WMI query a N times.
#---------------------------------------------------------------------------
Function WMIGetInstanceExTryN
{
param ([string]$sTargetComputer,
[string]$sNamespace,
[string]$sInstanceQuery,
[int]$N)

for ($i = 0; $i -lt $N; $i++)
{
$error.Clear();

Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $sTargetComputer -SessionOption $cimSessionOption
$oInstance = Get-CimInstance -CimSession $cimsession -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
catch
{
$oInstance = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}

if ($error.Count -gt 0)
{
if ($i -eq ($N-1))
{
ThrowScriptError ("The class name '" + $sInstanceQuery + "' returned no instances. Please check to see if this is a valid WMI class name.") $error[0]
}
}
else
{
break;
}
sleep -m 1000
}

return $oInstance
}

#---------------------------------------------------------------------------
# Returns WMI Instance requested.
#---------------------------------------------------------------------------
Function WMIGetInstanceEx
{
param ([string]$sTargetComputer,
[string]$sNamespace,
[string]$sInstanceQuery)

$error.Clear();

Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $sTargetComputer -SessionOption $cimSessionOption
$oInstance = Get-CimInstance -CimSession $cimsession -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
catch
{
$oInstance = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery)
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
if ($error.Count -gt 0)
{
ThrowScriptError ("The class name '" + $sInstanceQuery + "' returned no instances. Please check to see if this is a valid WMI class name.") $error[0]
}

return $oInstance
}

#---------------------------------------------------------------------------
# Connect to WMI.
#---------------------------------------------------------------------------
Function WMIConnect
{
param ([string]$sTargetComputer,
[string]$sNamespace)

$error.Clear()

# !!! Refactoring comment:
# Original VBScript only tries to connect to the namespace. Piping to get only the first one saves time.
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $sTargetComputer -SessionOption $cimSessionOption
$oWMI = Get-CimClass -CimSession $cimsession -Namespace $sNamespace -ErrorAction SilentlyContinue | select -First 1
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
if ($error.Count -gt 0)
{
$msg = "Unable to open WMI Namespace 'winmgmts:\\" + $sTargetComputer + "\" + $sNamespace + "'. Check to see if the WMI service is enabled and running, and ensure this WMI namespace exists."
ThrowScriptError $msg $error[0]
}
}

#---------------------------------------------------------------------------
# Returns WMI Instance requested.
#---------------------------------------------------------------------------
Function WMIGetInstance
{
param ([string]$sTargetComputer,
[string]$sNamespace,
[string]$sInstanceQuery)

WMIConnect $sTargetComputer $sNamespace
$oInstance = WMIGetInstanceEx $sTargetComputer $sNamespace $sInstanceQuery
return $oInstance
}

#---------------------------------------------------------------------------
# Returns WMI Instance requested.
#---------------------------------------------------------------------------
Function WMIGetInstanceNoAbort
{
param ([string]$sTargetComputer,
[string]$sNamespace,
[string]$sInstanceQuery)

Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $sTargetComputer -SessionOption $cimSessionOption
$oInstance = Get-CimInstance -CimSession $cimsession -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
catch
{
$oInstance = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query ("Select * from "+$sInstanceQuery) -ErrorAction SilentlyContinue
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
return $oInstance
}

#---------------------------------------------------------------------------
# Executes the WMI query and returns the result set.
#---------------------------------------------------------------------------
Function WMIExecQuery
{
param ([string]$sTargetComputer,
[string]$sNamespace,
[string]$sQuery)

$error.Clear()

# !!! Refactoring comment:
# Original VBScript only tries to connect to the namespace. Piping to get only the first one saves time.
Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $sTargetComputer -SessionOption $cimSessionOption
$oWMI = Get-CimClass -CimSession $cimsession -Namespace $sNamespace -ErrorAction SilentlyContinue | select -First 1
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
if ($error.Count -gt 0)
{
$msg = "Unable to open WMI Namespace 'winmgmts:\\" + $sTargetComputer + "\" + $sNamespace + "'. Check to see if the WMI service is enabled and running, and ensure this WMI namespace exists."
ThrowScriptError $msg, $error[0]
}


try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $sTargetComputer -SessionOption $cimSessionOption
$oQuery = Get-CimInstance -CimSession $cimsession -Namespace $sNamespace -Query $sQuery -ErrorAction SilentlyContinue
}
catch
{
$oQuery = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query $sQuery -ErrorAction SilentlyContinue
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}
if ($error.Count -gt 0)
{
ThrowScriptError ("The Query '" + $sQuery + "' returned an invalid result set. Please check to see if this is a valid WMI Query.") $error[0]
}

return $oQuery
}

#---------------------------------------------------------------------------
# Executes the WMI query and returns the result set, no abort version.
#---------------------------------------------------------------------------
Function WMIExecQueryNoAbort
{
param ([string]$sTargetComputer,
[string]$sNamespace,
[string]$sQuery)

Load-CimModules
try
{
$cimSessionOption = New-CimSessionOption -Protocol DCOM
$cimsession = New-CimSession -ComputerName $sTargetComputer -SessionOption $cimSessionOption
$oQuery = Get-CimInstance -CimSession $cimsession -Namespace $sNamespace -Query $sQuery -ErrorAction SilentlyContinue
}
catch
{
$oQuery = Get-WMIObject -ComputerName $sTargetComputer -Namespace $sNamespace -Query $sQuery -ErrorAction SilentlyContinue
}
Finally
{
Get-CimSession | Remove-CimSession
$cimsession =$null
$cimSessionOption = $null
}

return $oQuery
}

#---------------------------------------------------------------------------
# Creates an event and sends it back to the mom server.
#---------------------------------------------------------------------------
Function ThrowScriptErrorNoAbort
{
param ([string]$sMessage,
[System.Management.Automation.ErrorRecord]$oErr)
# Retrieve the name of this (running) script
$ScriptFileName = $MyInvocation.ScriptName

if ($oErr -ne $null)
{
$sMessage = $sMessage + ". " + $oErr.ErrorDetails
}

$momAPI.LogScriptEvent($ScriptFileName, $g_ErrorEventNumber, $EVENT_TYPE_ERROR, $sMessage)

Write-Host $sMessage
}

#---------------------------------------------------------------------------
# Creates an event and sends it back to the mom server.
#---------------------------------------------------------------------------
Function ThrowScriptError
{
param ([string]$sMessage,
[System.Management.Automation.ErrorRecord]$oErr)
ThrowScriptErrorNoAbort $sMessage $oErr
exit
}

#---------------------------------------------------------------------------
# Outputs to file and echo for debugging purposes
#---------------------------------------------------------------------------
Function TraceLogMessage
{
param ([string]$sMessage)

Write-Host $sMessage

If ($g_DebugFlag -eq $true)
{
# Retrieve the name of this (running) script
$ScriptFileName = $MyInvocation.ScriptName

$momAPI.LogScriptEvent($ScriptFileName, $g_TraceEventNumber, $EVENT_TYPE_INFORMATION, $sMessage)
}
}

#---------------------------------------------------------------------------
# Verifies the expression. If equals to False then generates an error and quits the script
# Usage:
# Verify Not WMISet Is Nothing, "WMISet is invalid!"
# Verify WMISet.Count = 1, "Invalid quantity of services with name 'Server' (qty = " &amp; WMISet.Count &amp; ")."
#---------------------------------------------------------------------------
Function Verify
{
param ([bool]$bBool,
[string]$sMessage)

If ($bBool -eq $false)
{
ThrowScriptError $sMessage $null
}
}

Function GetRegistryKeyValue
{
param ([string]$keyPath,
[string]$key)

$error.Clear()

$strKeyValue = Get-ItemProperty -Path $keyPath -Name $key -ErrorAction SilentlyContinue
if ($error.Count -gt 0)
{
ThrowScriptError ("An error occurred while reading the registry: '" + $keyPath + $key + "'") $error[0]
}
return $strKeyValue.$key
}


#---------------------------------------------------------------------------
# Function: ExpressedInMB
# Usage:
# Parameter (SizeInBytes)
# Returns the Size Expressed in MBytes
#---------------------------------------------------------------------------
Function ExpressedInMB
{
param ($SizeInBytes)

$NumberSizeExpInMB = [math]::Round($SizeInBytes / $DISKSIZE_BYTES_IN_MB, 0)
return $NumberSizeExpInMB
}

Function Load-CimModules
{
$error.Clear()

$CimModule = Get-Module CimCmdlets

if ($null -eq $CimModule)
{
Import-Module CimCmdlets
$error.Clear()
}
}Function Main()
{
$objWMIColl = $null

$IsCluster = CheckCluster $TargetComputer
#write-host $IsCluster

if ($IsCluster -eq $true)
{
$objWMIColl = GetClusterDiskCollection $TargetComputer
}

$oDiscoveryData = $momAPI.CreateDiscoveryData(0, $SourceID, $ManagedEntityId)

if ((DoDiscovery $TargetComputer $TargetComputerID $oDiscoveryData $IsCluster $objWMIColl $DeviceID) -ge 0)
{
$oDiscoveryData
}
}

Function DoDiscovery
{
param ([string]$sTargetComputer, [string]$sTargetComputerID, $oDisc, [bool]$IsCluster, $objWMIColl, $sDeviceID)

$WMISet = WMIExecQuery $sTargetComputer "root\cimv2" "associators of {win32_diskpartition='$sDeviceID'} where ResultClass=Win32_LogicalDisk"

if ($WMISet -ne $null)
{
$IsClusterDisk = CheckIsClusterDisk $WMISet.DeviceID $WMISet.VolumeSerialNumber $IsCluster $objWMIColl

if ($IsClusterDisk -eq $false)
{
$oInstancePartition = $oDisc.CreateClassInstance("$MPElement[Name='WindowsServer!Microsoft.Windows.Server.6.2.DiskPartition']$")
$oInstancePartition.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", $sTargetComputerID)
$oInstancePartition.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.LogicalDevice']/DeviceID$", $sDeviceID)

$oInstanceLogicalDisk = $oDisc.CreateClassInstance("$MPElement[Name='WindowsServer!Microsoft.Windows.Server.6.2.LogicalDisk']$")
$oInstanceLogicalDisk.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", $sTargetComputerID)
$oInstanceLogicalDisk.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.LogicalDevice']/DeviceID$", $WMISet.DeviceID)

$oInstanceRelationship = $oDisc.CreateRelationshipInstance("$MPElement[Name='Microsoft.Windows.Server.6.2.DiskPartitionContainsLogicalDisk']$")
$oInstanceRelationship.source = $oInstancePartition
$oInstanceRelationship.target = $oInstanceLogicalDisk
$oDisc.AddInstance($oInstanceRelationship)
}
}

return 0
}


Function CheckCluster
{
param ([string]$sTargetComputer)

$error.Clear()
$oInstances = WMIExecQueryNoAbort $sTargetComputer "root\cimv2" "Select ID, Name from Win32_ServerFeature where Name = 'Failover Clustering'"

if ($error.Count -gt 0 -or $oInstances.Count -eq 0)
{
return $false
}
else
{
return $true
}
}

Function CheckIsClusterDisk
{
param ([string]$sDeviceID, [string]$sSerialNumber, [bool]$IsCluster, $objWMIColl)


if ($IsCluster -eq $true)
{

$bFlag = $false
foreach ($item in $objWMIColl)
{
$hexsn = "{0:X}" -f $item.SerialNumber
if (($hexsn -eq $sSerialNumber.trimstart("0")) -and ($item.Path -eq $sDeviceID))
{
$bFlag = $true
break
}
}

if ($bFlag -eq $true)
{
return $true
}
else
{
return $false
}
}
else
{
return $false
}
}

Function GetClusterDiskCollection
{
param ([string]$sTargetComputer)

$error.Clear()
$oInstances = WMIExecQueryNoAbort $sTargetComputer "root\MSCluster" "Select Path, SerialNumber From MSCluster_DiskPartition"

if ($error.Count -gt 0)
{
write-host "error!"
return $null
}
else
{
return $oInstances
}
}

Main





</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>SourceID</Name>
<Value>$MPElement$</Value>
</Parameter>
<Parameter>
<Name>ManagedEntityId</Name>
<Value>$Target/Id$</Value>
</Parameter>
<Parameter>
<Name>TargetComputer</Name>
<Value>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$</Value>
</Parameter>
<Parameter>
<Name>TargetComputerID</Name>
<Value>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value>
</Parameter>
<Parameter>
<Name>DeviceID</Name>
<Value>$Target/Property[Type="Windows!Microsoft.Windows.LogicalDevice"]/DeviceID$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>300</TimeoutSeconds>
</DataSource>
</Discovery>