Fujitsu Out-Of-Band Performance Data Collection Probe Action

Fujitsu.Servers.PRIMERGY.OutOfBand.PerfMon.PerformanceMonitor.Probe (ProbeActionModuleType)

Fujitsu Out-Of-Band Performance Data Collection Probe Action Type

Element properties:

TypeProbeActionModuleType
IsolationAny
AccessibilityInternal
RunAsSystem.PrivilegedMonitoringAccount
OutputTypeSystem.PropertyBagData

Member Modules:

ID Module Type TypeId RunAs 
PassThrough ProbeAction System.PassThroughProbe Default
Script ProbeAction Microsoft.Windows.PowerShellPropertyBagTriggerOnlyProbe Default

Source Code:

<ProbeActionModuleType ID="Fujitsu.Servers.PRIMERGY.OutOfBand.PerfMon.PerformanceMonitor.Probe" Accessibility="Internal" RunAs="System!System.PrivilegedMonitoringAccount" Batching="false" PassThrough="false">
<Configuration>
<IncludeSchemaTypes>
<SchemaType>Windows!Microsoft.Windows.PowerShellSchema</SchemaType>
</IncludeSchemaTypes>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="TimeoutSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="0" name="StrictErrorHandling" type="xsd:boolean"/>
<!-- Fixed Parameters -->
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="UserName" type="NonNullString"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="Password" type="NonNullString"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="SkipCACheck" type="xsd:boolean"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="SkipCNCheck" type="xsd:boolean"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" name="ManagementUrl" type="NonNullString"/>
</Configuration>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<ProbeAction ID="PassThrough" TypeID="System!System.PassThroughProbe"/>
<ProbeAction ID="Script" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagTriggerOnlyProbe">
<ScriptName>PerfMonMonitor.ps1</ScriptName>
<ScriptBody><Script>
##################################################################################
# #
# NOTICE #
# #
# COPYRIGHT 2014 - 2016 Fujitsu Technology Solutions #
# ALL RIGHTS RESERVED #
# #
# This computer program is CONFIDENTIAL and contains TRADE SECRETS of #
# Fujitsu Technology Solutions. The receipt or possession of this program does #
# not convey any rights to reproduce or disclose its contents, or to #
# manufacture, use, or sell anything that it may describe, in whole or #
# in part, without the specific written consent of Fujitsu Technology Solutions. #
# Any reproduction of this program without the express written consent #
# of Fujitsu Technology Solutions is a violation of the copyright laws and may #
# subject you to civil liability and criminal prosecution. #
# #
##################################################################################


# This script collects all Performance Sensors information from the iRMC system report
# For cookdown the component status identifier and a mapped HealthStatus
# property bag are returned and filtered afterwards for the specific component status

param(
[int] $TimeoutSeconds = 120,
[string]$UserName,
[string]$Password,
[string]$ManagementUrl,
[string]$SkipCACheck = "False",
[string]$SkipCNCheck = "False",

[string]$ScriptName = "PerfMonMonitor.ps1"

)

$ScriptApi = New-Object -comObject "MOM.ScriptAPI"
if ($ScriptApi -eq $Null) { Exit -1 }

# set CONSTANT variables (can not be changed):
set-variable -name PoShScriptName -value $ScriptName -option constant

[int]$SCRIPT_EVENT_NUMBER = 8209 # a prime

# Note: Keep in sync with discovery
[int]$ERROR_NO_SDR_INFORMATION = 8231 # a prime
[int]$ERROR_NO_TEMP_INFORMATION = 8233 # a prime
[int]$ERROR_NO_POWERCONSUMPTION_INFORMATION = 8237 # a prime

[bool]$propertyBagReturned = $False

# SCCI Temperature Status Value definition
[int]$CMV_SENSSTAT_NOTAVAIL = 0
[int]$CMV_SENSSTAT_OK = 1
[int]$CMV_SENSSTAT_FAIL = 3
[int]$CMV_SENSSTAT_TEMPWARN = 4
[int]$CMV_SENSSTAT_TEMPCRIT = 5
[int]$CMV_SENSSTAT_TEMPOK = 6
[int]$CMV_SENSSTAT_TEMPPREWARN = 7

$hostURL = $ManagementUrl

# Extract the IP from the ManagementUrl
$IP = $ManagementUrl.Substring(0, $ManagementUrl.LastIndexOf(":")).ToUpper().TrimStart("HTTPS://")

# we need to make multiple authenticated HTTP requests...
[System.Net.NetworkCredential]$NetworkCredential = New-Object System.Net.NetworkCredential ($UserName, $Password)
[System.Net.ServicePointManager]::DefaultConnectionLimit = 1000

# Strip any potential garbage at the and of the XML string
Function Clean-XmlString ([string]$xmlString, [string]$endTag) {
if ($xmlString.contains( $endTag )) {
$xmlString.TrimEnd( $xmlString.Substring( ($xmlString.IndexOf($endTag) +$endTag.Length) ))
} else {
$xmlString
}
}

# something went wrong
Function EarlyExit
{
if ($propertyBagReturned -eq $False) {
# Return empty property bag if something went wrong
$propertyBag = $ScriptApi.CreatePropertyBag()
$propertyBag
}
Exit
}

Function Main {

PrepareLogging -Section $SectionPerformanceMonitor -HostTag $TagHostsMonitoring -ServerName $IP -MpName "Fujitsu.Servers.PRIMERGY.OutOfBand.PerfMon"

DebugOut "$IP - Performance Monitoring for Fujitsu Out-Of-Band Server - start"
DebugOut "$IP - ManagementUrl=$ManagementUrl TimeoutSeconds=$TimeoutSeconds SkipCACheck=$SkipCACheck SkipCNCheck=$SkipCNCheck"

[xml]$xml = New-Object XML
[System.Xml.XmlElement]$elem = $Null

try {
# We need SDR Data for the Temperature Entity ID and Entity Instance information
$Response = DoWebRequest -url ($hostURL + "/report.xml?Item=System/SensorDataRecords") -Method "GET" -Credentials $NetworkCredential -RequestTimeout $DEFAULT_REQUEST_TIMEOUT
if ($Response -ne $Null -and $Response.Contains("&lt;Root") ) {
try {
$xml = [xml] ( Clean-XmlString -xmlString $Response -endTag "&lt;/Root&gt;" )
if ($xml -ne $Null -and $xml.HasChildNodes ) {
$BmcFirmwareVersion = $xml.Root.GetAttribute("Version")
DebugOut "$IP - Firmware Version: $BmcFirmwareVersion "
[System.Xml.XmlElement]$sdrInst = $xml.Root.System.SensorDataRecords

$ThreshSdr = @($sdrInst.SDR | where { $_.GetAttribute("RecordType") -eq 1} )
$TempSdr = @($ThreshSdr | where { $_.Data.Decoded.Sensor.TypeName -eq 'Temperature'} )
$powerSdr = @($ThreshSdr | where { $_.Data.Decoded.Sensor.TypeName -eq 'Other Units-based Sensor' -and $_.Data.Decoded.Sensor.BaseUnitName -eq 'Watts'} )
DebugOut "$IP - Threshold SDR: $($ThreshSdr.Count) incl. Temperature: $($TempSdr.Count) PowerConsumption: $($powerSdr.Count) "
}
} catch {
DebugErr $ERROR_NO_SDR_INFORMATION "$IP - Could not process Sensor Data Record information. Exception=$_"
EarlyExit
}
} else {
LogScriptEventWithEventSource -EventSource $IP -EventLevel $WARNING_LEVEL -EventNumber $ERROR_NO_SDR_INFORMATION -Message ("SDR Information not available")
DebugErr $ERROR_NO_SDR_INFORMATION "$IP - SDR Information not available"
EarlyExit
}

# Temperature Sensors
$Response = DoWebRequest -url ($hostURL + "/report.xml?Item=System/Temperatures") -Method "GET" -Credentials $NetworkCredential -RequestTimeout $DEFAULT_REQUEST_TIMEOUT
if ($Response -ne $Null -and $Response.Contains("&lt;Root") ) {
try {
$xml = [xml]( Clean-XmlString -xmlString $Response -endTag "&lt;/Root&gt;" )
if ($xml -ne $Null -and $xml.HasChildNodes ) {
[System.Xml.XmlElement]$tempInst = $xml.Root.System.Temperatures

if ($tempInst -ne $Null ) {
DebugOut "$IP - Found Temperatures"
foreach ($elem in $tempinst.Temperature) {
$SensorName = $elem.Name
$StatusVal = $elem.Status.Innertext
if ($StatusVal -eq $CMV_SENSSTAT_NOTAVAIL) {
DebugOut "$IP -`t`tSkipping N/A Temperature Sensor '$($SensorName)' ..."
continue
}
# Find matching SDR
$sdr = @($TempSdr | where { $_.Data.Decoded.Entity.Name -eq $SensorName } )
if ($sdr.count -eq 0 ) {
continue
}
if ($sdr.count -gt 1) {
DebugOut "$IP -`t`tSkipping Multi Instance / Build To Order Temperature Sensor '$($SensorName)' ..."
continue
}

# Skip Temperature Sensors for Voltage Regulator Modules (VRM) / Voltage Regulator Devices (VRD)
if ( $SensorName.Contains('VR') -and ( ([int]$sdr.Data.Decoded.Entity.ID) -eq $SDR_ENTITY_ID_MEMORY_DEVICE) ) {
DebugOut "$IP -`t`tSkipping VRM/VRD Memory Temperature Sensor '$($SensorName)' ..."
continue
}

if ( $SensorName.Contains('VR') -and ( ([int]$sdr.Data.Decoded.Entity.ID) -eq $SDR_ENTITY_ID_PROCESSOR) ) {
DebugOut "$IP -`t`tSkipping VRM/VRD Processor Temperature Sensor '$($SensorName)' ..."
continue
}

# We monitor only a subset of available Temperature Sensors as Performance Monitors
if (($sdr.Data.Decoded.Entity.ID -eq $SDR_ENTITY_INLET_AIR_TEMP) -or ($sdr.Data.Decoded.Entity.ID -eq $SDR_ENTITY_ID_SYSTEM_BOARD) -or ($sdr.Data.Decoded.Entity.ID -eq $SDR_ENTITY_ID_POWER_SUPPLY) -or ($sdr.Data.Decoded.Entity.ID -eq $SDR_ENTITY_ID_PROCESSOR) -or ($sdr.Data.Decoded.Entity.ID -eq $SDR_ENTITY_ID_MEMORY_DEVICE)){
$SensorUnits = $SensorNumber = $SensorType = $EntityId = $EntityInstance = 'N/A'

if ($sdr.Data.Decoded.Sensor.BaseUnitName -ne $Null) {
$SensorUnits = $sdr.Data.Decoded.Sensor.BaseUnitName
}
if ($sdr.Data.Decoded.Sensor.TypeName -ne $Null) {
$SensorType = $sdr.Data.Decoded.Sensor.TypeName
}
if ($sdr.Data.Decoded.Key.SensorNumber -ne $Null) {
$SensorNumber = $sdr.Data.Decoded.Key.SensorNumber
}
if ($sdr.Data.Decoded.Entity.ID -ne $Null) {
$EntityId = IPMI-GetEntityId ([int]$sdr.Data.Decoded.Entity.ID)
}
if ($sdr.Data.Decoded.Entity.Instance -ne $Null) {
$EntityInstance = $sdr.Data.Decoded.Entity.Instance
}

$propertyBag = $ScriptApi.CreatePropertyBag()

# Map numeric SCCI Temperature Status to health status
switch ($StatusVal) {
$CMV_SENSSTAT_OK {$HealthStatus = 'OK' } # digital discrete
$CMV_SENSSTAT_FAIL {$HealthStatus = 'Error' } # digital discrete
$CMV_SENSSTAT_TEMPWARN {$HealthStatus = 'Warning'} # Threshold
$CMV_SENSSTAT_TEMPCRIT {$HealthStatus = 'Error' } # Threshold
$CMV_SENSSTAT_TEMPOK {$HealthStatus = 'OK' } # Threshold
$CMV_SENSSTAT_TEMPPREWARN {$HealthStatus = 'Warning'} # Unused
default {$HealthStatus = 'Unknown'}
}

# The Out-Of-Band Server this Temperature Monitor is hosted
$propertyBag.AddValue('IP' , $IP)

# Properties to identify this Temperature Monitor Instance
$propertyBag.AddValue('ID' , $SensorName)
$propertyBag.AddValue('SensorType' , $SensorType)
$propertyBag.AddValue('SensorNumber' , $SensorNumber)
$propertyBag.AddValue('EntityId' , $EntityId)
$propertyBag.AddValue('EntityInstance', $EntityInstance)
$propertyBag.AddValue('HealthStatus' , $HealthStatus)
$propertyBag.AddValue('CurrentValue' , $elem.CurrValue) # Actual Performance Monitor Value ...

DebugOut "$IP - Temperature '$($SensorName)' SensorNumber=$($SensorNumber) SensorType='$($SensorType)' Entity ID='$($EntityId)' Entity Instance='$($EntityInstance)' Status='$($elem.Status.Description)' HealthStatus='$($HealthStatus)' Current Value: $($elem.CurrValue) $SensorUnits"
# Return each property bag as we create and populate it.
$propertyBag
$propertyBagReturned = $True
}
}

} else {
DebugErr $ERROR_NO_TEMP_INFORMATION "$IP - Temperature System Report not available"
}
}
} catch {
DebugErr $ERROR_NO_TEMP_INFORMATION "$IP - Could not process iRMC Temperature System Report Information. Exception=$_"
}
} else {
# No response or garbage ...
LogScriptEventWithEventSource -EventSource $IP -EventLevel $WARNING_LEVEL -EventNumber $ERROR_NO_TEMP_INFORMATION -Message ("iRMC System Report Information not available")
DebugErr $ERROR_NO_TEMP_INFORMATION "$IP - iRMC Temperature System Report Information not available"
}

# Power Consumption
$Response = DoWebRequest -url ($hostURL + "/report.xml?Item=System/PowerConsumption") -Method "GET" -Credentials $NetworkCredential -RequestTimeout $DEFAULT_REQUEST_TIMEOUT
if ($Response -ne $Null -and $Response.Contains("&lt;Root") ) {
try {
$xml = [xml]( Clean-XmlString -xmlString $Response -endTag "&lt;/Root&gt;" )
if ($xml -ne $Null -and $xml.HasChildNodes ) {
[System.Xml.XmlElement]$powerInst = $xml.Root.System.PowerConsumption

if ($powerInst -ne $Null ) {
DebugOut "$IP - Processing Power Consumption Information"
foreach ($elem in $powerInst.Sensors.Sensor) {
$SensorName = $elem.Name
$Status = $elem.Status.GetAttribute("Description")
if ($Status -eq 'Not Present') {
DebugOut "$IP -`t`tSkipping Not Present Power Consumption Sensor '$($SensorName)' ..."
continue
}
if ($Status -eq 'N/A') {
DebugOut "$IP -`t`tSkipping N/A Power Consumption Sensor '$($SensorName)' ..."
continue
}

# Find matching SDR
$sdr = @($powerSdr | where { $_.Data.Decoded.Entity.Name -eq $SensorName } )
if ($sdr.count -eq 0 ) {
DebugOut "$IP -`t`tSkipping Power Consumption Sensor '$($sensorName)' due to not found SDR ..."
continue
}
if ($sdr.count -gt 1) {
DebugOut "$IP -`t`tSkipping Multi Instance / Build To Order Power Consumption Sensor '$($SensorName)' ..."
continue
}
# We monitor only a subset of available Power Consumption as Performance Monitors
if (($sdr.Data.Decoded.Entity.ID -eq $SDR_ENTITY_ID_OEM_E0) -or ($sdr.Data.Decoded.Entity.ID -eq $SDR_ENTITY_ID_POWER_SUPPLY) -or ($sdr.Data.Decoded.Entity.ID -eq $SDR_ENTITY_ID_PROCESSOR) -or ($sdr.Data.Decoded.Entity.ID -eq $SDR_ENTITY_ID_SYSTEM_CHASSIS)){

# Note: Entity Instance 0: primary (external) Power Consumption (power plug)
# Entity Instance 1: secondary (internal) Power Consumption (after the PSU internal losses)
# Typical names are: 'Total Power' / 'Total Power Out'
# Skip the 'Total Power Out' instance (also applies to System Chassis for Multi Node Systems)
if ($sdr.Data.Decoded.Entity.ID -eq $SDR_ENTITY_ID_OEM_E0 -and $sdr.Data.Decoded.Entity.Instance -ne 0) {
continue
}
if ($sdr.Data.Decoded.Entity.ID -eq $SDR_ENTITY_ID_SYSTEM_CHASSIS -and $sdr.Data.Decoded.Entity.Instance -ne 0) {
continue
}

$SensorUnits = $SensorNumber = $SensorType = $EntityId = $EntityInstance = 'N/A'

if ($sdr.Data.Decoded.Sensor.BaseUnitName -ne $Null) {
$SensorUnits = $sdr.Data.Decoded.Sensor.BaseUnitName
}
if ($sdr.Data.Decoded.Sensor.TypeName -ne $Null) {
$SensorType = $sdr.Data.Decoded.Sensor.TypeName
}
if ($sdr.Data.Decoded.Key.SensorNumber -ne $Null) {
$SensorNumber = $sdr.Data.Decoded.Key.SensorNumber
}
if ($sdr.Data.Decoded.Entity.ID -ne $Null) {
$EntityId = IPMI-GetEntityId ([int]$sdr.Data.Decoded.Entity.ID)
}
if ($sdr.Data.Decoded.Entity.Instance -ne $Null) {
$EntityInstance = $sdr.Data.Decoded.Entity.Instance
}

$propertyBag = $ScriptApi.CreatePropertyBag()

# Map Status to health status
switch ($Status) {
'OK' {$HealthStatus = 'OK' }
'Critical' {$HealthStatus = 'Error' }
'Warning' {$HealthStatus = 'Warning'}
default {$HealthStatus = 'Unknown'}
}

# The Out-Of-Band Server this Performance Monitor is hosted
$propertyBag.AddValue('IP' , $IP)

# Properties to identify this Performance Monitor Instance
$propertyBag.AddValue('ID' , $SensorName)
$propertyBag.AddValue('SensorType' , $SensorType)
$propertyBag.AddValue('SensorNumber' , $SensorNumber)
$propertyBag.AddValue('EntityId' , $EntityId)
$propertyBag.AddValue('EntityInstance', $EntityInstance)
$propertyBag.AddValue('HealthStatus' , $HealthStatus)
$propertyBag.AddValue('CurrentValue' , $elem.CurrentValue) # Note: Actual Performance Monitor Value ...

DebugOut "$IP - PowerConsumption '$($SensorName)' SensorNumber=$($SensorNumber) SensorType='$($SensorType)' Entity ID='$($EntityId)' Entity Instance='$($EntityInstance)' Status='$($elem.Status.Description)' HealthStatus='$($HealthStatus)' Current Value: $($elem.CurrentValue) $SensorUnits"
# Return each property bag as we create and populate it.
$propertyBag
$propertyBagReturned = $True
}
}

} else {
# Power Consumption is optional
DebugOut "$IP - Power Consumption System Report not available"
}
}
} catch {
DebugErr $ERROR_NO_POWERCONSUMPTION_INFORMATION "$IP - Could not process iRMC Power Consumption System Report Information. Exception=$_"
}
} else {
# No response or garbage ...
LogScriptEventWithEventSource -EventSource $IP -EventLevel $WARNING_LEVEL -EventNumber $ERROR_NO_POWERCONSUMPTION_INFORMATION -Message ("iRMC Power Consumption System Report Information not available")
DebugErr $ERROR_NO_POWERCONSUMPTION_INFORMATION "$IP - iRMC Power Consumption System Report Information not available"
}


} catch {
# Generic Exception ...
LogScriptEventWithEventSource -EventSource $IP -EventLevel $WARNING_LEVEL -EventNumber $SCRIPT_EVENT_NUMBER -Message ("Fujitsu Out-Of-Band Performance Monitoring: Exception=$_")
DebugErr $SCRIPT_EVENT_NUMBER "$ManagementUrl - Temperature Performance Monitoring: Exception=$_"
}

if ($propertyBagReturned -eq $False) {
# Return empty property bag if something went wrong
$propertyBag = $ScriptApi.CreatePropertyBag()
$propertyBag
}

DebugOut "$IP - Performance Monitoring for Fujitsu Out-Of-Band Server - finished"
}


# This script part contains some IPMI helper functions
# and is embedded into the final script via Visual Studio Authoring Extensions


# DT_TempSensorStatus
[int]$CMV_SENSSTAT_NOTAVAIL = 0
[int]$CMV_SENSSTAT_OK = 1
[int]$CMV_SENSSTAT_FAIL = 3
[int]$CMV_SENSSTAT_TEMPWARN = 4
[int]$CMV_SENSSTAT_TEMPCRIT = 5
[int]$CMV_SENSSTAT_TEMPOK = 6
[int]$CMV_SENSSTAT_TEMPPREWARN = 7

# Entity ID Codes
[int]$SDR_ENTITY_ID_UNSPECIFIED = 0x00
[int]$SDR_ENTITY_ID_OTHER = 0x01
[int]$SDR_ENTITY_ID_UNKNOWN = 0x02
[int]$SDR_ENTITY_ID_PROCESSOR = 0x03
[int]$SDR_ENTITY_ID_DISK_BAY = 0x04
[int]$SDR_ENTITY_ID_PERIPHERAL_BAY = 0x05
[int]$SDR_ENTITY_ID_SYS_MGMT_MODULE = 0x06
[int]$SDR_ENTITY_ID_SYSTEM_BOARD = 0x07
[int]$SDR_ENTITY_ID_MEMORY_MODULE = 0x08
[int]$SDR_ENTITY_ID_PROCESSOR_MODULE = 0x09
[int]$SDR_ENTITY_ID_POWER_SUPPLY = 0x0A
[int]$SDR_ENTITY_ID_ADD_IN_CARD = 0x0B
[int]$SDR_ENTITY_ID_FRONT_PANEL_BOARD = 0x0C
[int]$SDR_ENTITY_ID_BACK_PANEL_BOARD = 0x0D
[int]$SDR_ENTITY_ID_POWER_SYSTEM_BOARD = 0x0E
[int]$SDR_ENTITY_ID_DRIVE_BACKPLANE = 0x0F
[int]$SDR_ENTITY_ID_SYS_INT_EXP_BOARD = 0x10
[int]$SDR_ENTITY_ID_OTHER_SYS_BOARD = 0x11
[int]$SDR_ENTITY_ID_PROCESSOR_BOARD = 0x12
[int]$SDR_ENTITY_ID_POWER_UNIT = 0x13
[int]$SDR_ENTITY_ID_POWER_MODULE = 0x14
[int]$SDR_ENTITY_ID_POWER_MGMT = 0x15
[int]$SDR_ENTITY_ID_CHAS_BACK_PANEL = 0x16
[int]$SDR_ENTITY_ID_SYSTEM_CHASSIS = 0x17
[int]$SDR_ENTITY_ID_SUB_CHASSIS = 0x18
[int]$SDR_ENTITY_ID_OTHER_CHAS_BOARD = 0x19
[int]$SDR_ENTITY_ID_DISK_DRIVE_BAY = 0x1A
[int]$SDR_ENTITY_ID_PERIPHERAL_BAY_2 = 0x1B
[int]$SDR_ENTITY_ID_DEVICE_BAY = 0x1C
[int]$SDR_ENTITY_ID_FAN_DEVICE = 0x1D
[int]$SDR_ENTITY_ID_COOLING_UNIT = 0x1E
[int]$SDR_ENTITY_ID_CABLE = 0x1F
[int]$SDR_ENTITY_ID_MEMORY_DEVICE = 0x20
[int]$SDR_ENTITY_ID_SYS_MGMT_SOFTWARE = 0x21
[int]$SDR_ENTITY_ID_BIOS = 0x22
[int]$SDR_ENTITY_ID_OPERATING_SYSTEM = 0x23
[int]$SDR_ENTITY_ID_SYSTEM_BUS = 0x24
[int]$SDR_ENTITY_ID_GROUP = 0x25
[int]$SDR_ENTITY_ID_REMOTE_MGMT_DEVICE = 0x26
[int]$SDR_ENTITY_ID_EXTERNAL_ENVIRONMENT = 0x27
[int]$SDR_ENTITY_ID_BATTERY = 0x28
[int]$SDR_ENTITY_ID_PROCESSING_BLADE = 0x29
[int]$SDR_ENTITY_ID_CONNECTIVITY_SWITCH = 0x2A
[int]$SDR_ENTITY_ID_PROCESSOR_MEMORY_MODULE = 0x2B
[int]$SDR_ENTITY_ID_IO_MODULE = 0x2C
[int]$SDR_ENTITY_ID_PROCESSOR_IO_MODULE = 0x2D
[int]$SDR_ENTITY_ID_MANAGEMENT_CONTROLLER_FW = 0x2E
[int]$SDR_ENTITY_ID_IPMI_CHANNEL = 0x2F
[int]$SDR_ENTITY_ID_PCI_BUS = 0x30
[int]$SDR_ENTITY_ID_PCI_EXPRESS_BUS = 0x31
[int]$SDR_ENTITY_ID_SCSI_BUS = 0x32
[int]$SDR_ENTITY_ID_SATA_SAS_BUS = 0x33
[int]$SDR_ENTITY_ID_PROCESSOR_FSB = 0x34
[int]$SDR_ENTITY_ID_RTC = 0x35
[int]$SDR_ENTITY_INLET_AIR_TEMP = 0x37
[int]$SDR_ENTITY_ID_PIC_FANPRINT = 0xD1
[int]$SDR_ENTITY_ID_LOCAL_VIEW = 0xD2
[int]$SDR_ENTITY_ID_MOTHERBOARD_CTRL = 0xD3
[int]$SDR_ENTITY_ID_PWR_BACKPLANE_CTRL = 0xD4
[int]$SDR_ENTITY_ID_BATTERY_PACK = 0xD5
[int]$SDR_ENTITY_ID_POWER_CTRL = 0xD6
[int]$SDR_ENTITY_ID_GPIO_CTRL1 = 0xD7
[int]$SDR_ENTITY_ID_GPIO_CTRL2 = 0xD8
[int]$SDR_ENTITY_ID_GPIO_CTRL3 = 0xD9
[int]$SDR_ENTITY_ID_GPIO_CTRL4 = 0xDA
[int]$SDR_ENTITY_ID_PECI_CTRL = 0xDB
[int]$SDR_ENTITY_ID_PWR_CAPPING_CTRL = 0xDD
[int]$SDR_ENTITY_ID_OEM_E0 = 0xE0 # System Power Consumption (in - primary)
[int]$SDR_ENTITY_ID_OEM_E1 = 0xE1 # System Power Consumption (out - secondary)

$SensorTypeStrings = @(
# 0x00 ... 0x07
"reserved", "Temperature", "Voltage", "Current", "Fan", "Physical Security (Chassis Intrusion)", "Platform Security Violation Attempt", "Processor",
# 0x08 ... 0x0F
"Power Supply", "Power Unit", "Cooling Device", "Other Units-based Sensor", "Memory", "Drive Slot (Bay)", "POST Memory Resize", "System Firmware Progress (formerly POST Error)",
# 0x10 ... 0x17
"Event Logging Disabled", "Watchdog 1", "System Event", "Critical Interrupt", "Button / Switch", "Module / Board", "Microcontroller / Coprocessor", "Add-in Card",
# 0x18 ... 0x1F
"Chassis", "Chip Set", "Other FRU", "Cable / Interconnect", "Terminator", "System Boot / Restart Initiated", "Boot Error", "Base OS Boot / Installation Status",
# 0x20 ... 0x27
"OS Stop / Shutdown", "Slot / Connector", "System ACPI Power State", "Watchdog 2", "Platform Alert", "Entity Presence", "Monitor ASIC / IC", "LAN",
# 0x28 ... 0x2C
"Management Subsystem Health", "Battery", "Session Audit", "Version Change", "FRU State"
)
#
# Map the IPMI Entity ID to a readable string
# (See IPMI 2.0 Spec. Section 43.14 / Table 43.13)
#
$EntityIdStrings = @(
"Unspecified",
"Other",
"Unknown / Unspecified",
"Processor",
"Disk / Disk Bay",
"Peripheral Bay",
"System Management Module",
"System Board",
"Memory Module",
"Processor Module",
"Power Supply",
"Add-in Card",
"Front Panel Board / Control Panel",
"Back Panel Board",
"Power System Board",
"Drive Backplane",

"System internal Expansion Board",
"Other System Board",
"Processor Board",
"Power Unit / Power Domain",
"Power Module / DC-DC Converter",
"Power Management / Power Distribution Board",
"Chassis Back Panel Board",
"System Chassis",
"Sub-Chassis",
"Other Chassis Board",
"Disk Drive Bay",
"Peripheral Bay 2",
"Device Bay",
"Fan / Cooling Device",
"Cooling Unit / Cooling Domain",
"Cable / Interconnect",

"Memory Device",
"System Management Software",
"System Firmware (BIOS/EFI)",
"Operating System",
"System Bus",
"Group",
"Remote Management Device",
"External Environment",
"Battery",
"Processing Blade",
"Connectivity Switch",
"Processor / Memory Module",
"I/O Module",
"Processor I/O Module",
"Management Controller Firmware",
"IPMI Channel",

"PCI Bus",
"PCI Express Bus",
"SCSI Bus (parallel)",
"SATA / SAS Bus",
"Processor / Front-side Bus",
"Real Time Clock (RTC)",
"0x36 reserved",
"Air Inlet",
"0x38 reserved",
"0x39 reserved",
"0x3A reserved",
"0x3B reserved",
"0x3C reserved",
"0x3D reserved",
"0x3E reserved",
"0x3F reserved",
"DCMI 1.0 Air Inlet",
"DCMI 1.0 Processor",
"DCMI 1.0 Baseboard"
)

$FujitsuOemEntityIdStrings = @(
# 0xD0 ... 0xDF
"ServerView",
"PIC Fanprint",
"LCD Panel",
"MBC Motherboard Ctrl.",
"PBC Power Backplane Ctrl.",
"BAT Battery Pack",
"PWR Power Ctrl.",
"SGP 1",
"SGP 2",
"SGP 3",
"SGP 4",
"PECI Ctrl.",
"Server Start",
"0xDD OEM Entity Id",
"Remote Flash",
"Drive Backplane Termination",

# 0xE0 ... 0xEF
"Power Monitoring",
"System", # Note: Power Consumption Summary Sensor
"0xE2 OEM Entity Id",
"0xE3 OEM Entity Id",
"0xE4 OEM Entity Id",
"0xE5 OEM Entity Id",
"0xE6 OEM Entity Id",
"0xE7 OEM Entity Id",
"0xE8 OEM Entity Id",
"0xE9 OEM Entity Id",
"0xEA OEM Entity Id",
"0xEB OEM Entity Id",
"0xEC OEM Entity Id",
"0xED OEM Entity Id",
"0xEE OEM Entity Id",
"0xEF OEM Entity Id",
# 0xF0 ... 0xFF
"0xF0 OEM Entity Id",
"0xF1 OEM Entity Id",
"0xF2 OEM Entity Id",
"0xF3 OEM Entity Id",
"0xF4 OEM Entity Id",
"0xF5 OEM Entity Id",
"0xF6 OEM Entity Id",
"0xF7 OEM Entity Id",
"0xF8 OEM Entity Id",
"0xF9 OEM Entity Id",
"0xFA OEM Entity Id",
"0xFB OEM Entity Id",
"0xFC OEM Entity Id",
"0xFD OEM Entity Id",
"0xFE OEM Entity Id",
"0xFF OEM Entity Id"
)

function IPMI-GetSensorType([byte] $type)
{
if (($type -ge 0x00) -and ($type -lt $SensorTypeStrings.Count)) {return $SensorTypeStrings[$type]}
if (($type -ge 0xC0) -and ($type -le 0xFF)) {return "OEM Specific"}
return "Unknown Sensor Type: $($type)"
}

function IPMI-GetEntityId([byte] $type)
{
if (($type -ge 0x00) -and ($type -lt $EntityIdStrings.Count)) {return $EntityIdStrings[$type]}
if (($type -ge 0xD0) -and ($type -le 0xFF)) {return $FujitsuOemEntityIdStrings[$type - 0xD0]}
return "Unknown Entity Id: $($type)"
}


# This script part contains helper functions to perform web based requests
# and is embedded into the final script via Visual Studio Authoring Extensions

[int]$DEFAULT_REQUEST_TIMEOUT = 30 # seconds
[int]$DEFAULT_RETRY_INCREMENT = 10 # seconds
[int]$MAX_REQUEST_RETRIES = 3

[int]$ERROR_SSL_CA_ERROR = 8399 # is not a prime
[int]$ERROR_SSL_CN_ERROR = 8499 # is not a prime

[int]$ERROR_BMC_NO_RESPONSE = 8599 # is a prime
[int]$ERROR_BMC_NO_ACCESS = 8699 # is a prime
[int]$ERROR_BMC_TIMEOUT = 8799 # is not a prime
[int]$ERROR_BMC_BUSY = 8999 # is a prime

# Subset of possible HTTP error codes
[int]$HTTP_RC_CONTINUE = 100
[int]$HTTP_RC_OK = 200
[int]$HTTP_RC_CREATED = 201
[int]$HTTP_RC_ACCEPTED = 202
[int]$HTTP_RC_NO_CONTENT = 204
[int]$HTTP_RC_RESET_CONTENT = 205
[int]$HTTP_RC_PARTIAL_CONTENT = 206

[int]$HTTP_RC_MULTIPLE_CHOICES = 300
[int]$HTTP_RC_MOVED_PERMANENTLY = 301
[int]$HTTP_RC_MOVED_TEMPORARILY = 302
[int]$HTTP_RC_NOT_MODIFIED = 304
[int]$HTTP_RC_BAD_REQUEST = 400
[int]$HTTP_RC_UNAUTHORIZED = 401
[int]$HTTP_RC_FORBIDDEN = 403
[int]$HTTP_RC_NOT_FOUND = 404
[int]$HTTP_RC_METHOD_NOT_ALLOWED = 405
[int]$HTTP_RC_NOT_ACCEPTABLE = 406
[int]$HTTP_RC_REQ_TIMEOUT = 408

[int]$HTTP_RC_SERVER_ERROR = 500
[int]$HTTP_RC_NOT_IMPLEMENTED = 501
[int]$HTTP_RC_SERVICE_UNAVAILABLE = 503

[bool]$global:SSL_CA_ERROR = $False
[bool]$global:SSL_CN_ERROR = $False
[bool]$global:SSL_NO_CERT_ERROR = $False


$SslCertificateValidator =
{
Param (
[System.Object] $obj,
[System.Security.Cryptography.X509Certificates.X509Certificate] $certificate,
[System.Security.Cryptography.X509Certificates.X509Chain] $chain,
[System.Net.Security.SslPolicyErrors] $errors
)

if ($errors -eq [System.Net.Security.SslPolicyErrors]::None) {
return $True
}

if (($errors -band [System.Net.Security.SslPolicyErrors]::RemoteCertificateChainErrors) -and ($SkipCACheck -eq $False)) {
$global:SSL_CA_ERROR = $True
return $False
}

if (($errors -band [System.Net.Security.SslPolicyErrors]::RemoteCertificateNameMismatch) -and ($SkipCNCheck -eq $False)) {
$global:SSL_CN_ERROR = $True
return $False
}

# No cert provided
if ($errors -band [System.Net.Security.SslPolicyErrors]::RemoteCertificateNotAvailable) {
$global:SSL_NO_CERT_ERROR = $True
return $False
}

# All checks passed
return $True
}

# Will return $Null on error
Function DoWebRequest(
[String]$url,
[string]$Method = "GET",
[System.Net.NetworkCredential]$Credentials = $NetworkCredential ,
[String]$requestData = $Null,
[int] $RequestTimeout = $DEFAULT_REQUEST_TIMEOUT,
[string]$AuthType = "Basic"
)
{
[int]$retries = 0;
for ($retries = 0; $retries -lt $MAX_REQUEST_RETRIES; $retries++) {
try {
[string]$errorMsg = $Null

$global:SSL_CN_ERROR = $False
$global:SSL_CA_ERROR = $False
$global:SSL_NO_CERT_ERROR = $False

$webRequest = [System.Net.WebRequest]::Create($url)
if ($Credentials -ne $Null) {
if ($AuthType -eq "Basic") {
# Do not wait for the 401 response, send the credentials with the initial request
$AuthData = [Convert]::ToBase64String([Text.Encoding]::Default.GetBytes($Credentials.UserName + ':' + $Credentials.Password));
$webRequest.Headers.Add('Authorization', "Basic $AuthData")

$webRequest.Credentials = $Null
$webRequest.PreAuthenticate = $False
# $webRequest.UseDefaultCredentials = $False
$webRequest.KeepAlive = $False # make sure the connection is not re-used
} else {
$webRequest.Credentials = $Credentials
$webRequest.PreAuthenticate = $True
}
} else {
$webRequest.Credentials = $Null
$webRequest.PreAuthenticate = $False
}
# $webRequest.PreAuthenticate = $False
# $webRequest.UseDefaultCredentials = $false

$webRequest.Timeout = ($RequestTimeout *1000)
$webRequest.ReadWriteTimeout = ($RequestTimeout *1000)
$webRequest.Method = $Method
$webRequest.Accept = "*/*"
$webRequest.KeepAlive = $False # make sure the connection is not re-used
try {
$webRequest.ServicePoint.ConnectionLimit = 1000
$webRequest.ServicePoint.ConnectionLeaseTimeout = 0 # Close Connection after servicing a request
$webRequest.ServicePoint.MaxIdleTime = 1 # in MilliSeconds, close connection afterwards
$webRequest.ServerCertificateValidationCallback = $SslCertificateValidator
} catch {
DebugErr 9999 "$IP - '$url' - Could not set extended config Exception=$_"
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = $SslCertificateValidator
}

if ($requestData.Length -gt 0) {
$buffer = [System.Text.Encoding]::UTF8.GetBytes($requestData)
$webRequest.ContentLength = $buffer.Length;
$requestStream = $webRequest.GetRequestStream()
$requestStream.Write($buffer, 0, $buffer.Length)
$requestStream.Flush()
$requestStream.Close()
}

[System.Timespan]$resTime = Measure-Command {

try {
$webResponse= $webRequest.GetResponse()
} catch [System.Net.WebException] {
$webResponse = $_.Exception.Response
$errorMsg = $_.Exception.Message
$stackTrace = $_.Exception.StackTrace
$innerException = $_.Exception.InnerException
} catch {
$webResponse = $Null
}
}

if ($webResponse -ne $Null) {
[string]$Location = $webResponse.GetResponseHeader("Location") # $webResponse.Headers.Get("Location")
[string]$Server = $webResponse.GetResponseHeader("Server") # $webResponse.Headers.Get("Server")
[System.Net.HttpStatusCode] $statusCode = $($webResponse.StatusCode.value__)

if ( $global:iRMCDetected -eq $False ){
if ($Server -match "iRMC") {
$global:iRMCDetected = $True
}
}
$responseStream = New-Object System.IO.StreamReader($webResponse.GetResponseStream())
$result = $responseStream.ReadToEnd()
$responseStream.Close()
$webResponse.Close()

switch ( $($webResponse.StatusCode.value__) ) {
$HTTP_RC_OK { # 200
DebugOut "$IP - $url request handled within $($resTime.TotalSeconds) seconds..."
return $result
}
$HTTP_RC_MOVED_PERMANENTLY { # 301
if ($Location -match "login") {
LogScriptEventWithEventSource -EventSource $IP -EventLevel $WARNING_LEVEL -EventNumber $ERROR_BMC_NO_ACCESS -Message ("Invalid credentials")
}
return
}
$HTTP_RC_MOVED_TEMPORARILY { # 302
if ($Location -match "login") {
LogScriptEventWithEventSource -EventSource $IP -EventLevel $WARNING_LEVEL -EventNumber $ERROR_BMC_NO_ACCESS -Message ("Invalid credentials")
}
return
}
$HTTP_RC_UNAUTHORIZED { # 401
LogScriptEventWithEventSource -EventSource $IP -EventLevel $WARNING_LEVEL -EventNumber $ERROR_BMC_NO_ACCESS -Message ("Invalid credentials")
return
}
$HTTP_RC_FORBIDDEN { # 403
LogScriptEventWithEventSource -EventSource $IP -EventLevel $WARNING_LEVEL -EventNumber $ERROR_BMC_NO_ACCESS -Message ("No permission (403)")
return
}
$HTTP_RC_NOT_FOUND { # 404
return
}
$HTTP_RC_SERVER_ERROR { # 500
return
}
$HTTP_RC_NOT_IMPLEMENTED { # 501
return
}
$HTTP_RC_SERVICE_UNAVAILABLE { # 503
LogScriptEventWithEventSource -EventSource $IP -EventLevel $WARNING_LEVEL -EventNumber $ERROR_BMC_BUSY -Message ("iRMC is too busy (503)")
DebugErr $ERROR_BMC_BUSY "$IP - '$url' - iRMC is too busy to handle request"
return
}

default {
return $result
}
}
} else {

# Check for SSL related errors
if ($global:SSL_CN_ERROR -eq $True) {
LogScriptEventWithEventSource -EventSource $IP -EventLevel $INFO_LEVEL -EventNumber $ERROR_SSL_CN_ERROR -Message ("Certificate Common Name (CN) Mismatch")
DebugOut "$IP - $url Certificate Name (CN) Mismatch ..."
return
} elseif ($global:SSL_CA_ERROR -eq $True) {
LogScriptEventWithEventSource -EventSource $IP -EventLevel $INFO_LEVEL -EventNumber $ERROR_SSL_CA_ERROR -Message ("Certificate Authority (CA) or Certificate Chain Error")
DebugOut "$IP - $url Certificate Authority (CA) or Chain Error ..."
return
} elseif ($global:SSL_NO_CERT_ERROR -eq $True) {
LogScriptEventWithEventSource -EventSource $IP -EventLevel $INFO_LEVEL -EventNumber $ERROR_SSL_ERROR -Message ("No Certificate present")
DebugOut "$IP - $url No Certificate present ..."
return
}

# no response (object), check for the timeout value.
# If the connection gets closed during early send/receive,
# this is typically within a few seconds, otherwise the configured timeout will have expired
if ($resTime -ne $Null -and [int]$resTime.TotalSeconds -lt 5) {
[int]$retryDelay = (($retries +1) * $DEFAULT_RETRY_INCREMENT)
# LogScriptEventWithEventSource -EventSource $IP -EventLevel $WARNING_LEVEL -EventNumber $ERROR_BMC_NO_RESPONSE -Message ("'$url' no response / connection closed ")
if ($errorMsg -ne $Null) { DebugWarn "$IP - '$url' no response / connection closed within $($resTime.TotalSeconds) seconds - will retry in $retryDelay seconds ($errorMsg)"}
else { DebugWarn "$IP - '$url' no response / connection closed within $($resTime.TotalSeconds) seconds - will retry in $retryDelay seconds (no details available)"}
if ($innerException -ne $Null) { DebugWarn "InnerException:`r`n$innerException" }
if ($stackTrace -ne $Null ) { DebugWarn "Stack Trace:`r`n$stackTrace" }
Start-Sleep -Seconds $retryDelay
} else {
# Note: do no report actual timeout seconds here, or alert suppression will not fully work due to different text
LogScriptEventWithEventSource -EventSource $IP -EventLevel $WARNING_LEVEL -EventNumber $ERROR_BMC_TIMEOUT -Message ("'$url' no response. Timeout was $RequestTimeout seconds")
DebugOut "$IP - '$url' no response within $($resTime.TotalSeconds) seconds. Timeout was $RequestTimeout seconds"
return
}
}
} catch {
# LogScriptEventWithEventSource -EventSource $IP -EventLevel $WARNING_LEVEL -EventNumber $SCRIPT_EVENT_NUMBER -Message ("'$url' generic Exception=$_")
DebugWarn "$IP - '$url' generic Exception=$_"
}
}
LogScriptEventWithEventSource -EventSource $IP -EventLevel $WARNING_LEVEL -EventNumber $ERROR_BMC_NO_RESPONSE -Message ("'$url' no response after $retries retries (last error: $errorMsg)")
DebugOut "$IP - '$url' no response after $retries retries (last error: $errorMsg)"
}



# This script part contains helper functions to perform various logging activities
# and is embedded into the final script via Visual Studio Authoring Extensions

# Log an event into the registry, Source will be 'Health Service Script'
# See https://msdn.microsoft.com/en-us/library/bb437630.aspx
[int]$WARNING_LEVEL = 2
[int]$ERROR_LEVEL = 1
[int]$INFO_LEVEL = 0

$LOGFILE_VERSION = 8.1.0.0

# Generic version
Function RaiseEvent {
Param (
[parameter(Mandatory=$true)]
[string]$EventSource = "Fujitsu Out-Of-Band",
[parameter(Mandatory=$true)]
[int]$EventLevel,
[parameter(Mandatory=$true)]
[int]$EventNumber,
[parameter(Mandatory=$true)]
[string]$Message
)

$channel = "Operations Manager"

if ([System.Diagnostics.EventLog]::SourceExists($EventSource) -eq $False) {
try {
[System.Diagnostics.EventLog]::CreateEventSource($EventSource, $channel)
} catch {

}
}

$eventLog = new-object System.Diagnostics.EventLog -ArgumentList @($channel)
$eventLog.Source = $EventSource

$eventData = @()
$eventData += $EventSource
$eventData += $Message
$eventData += $PoShScriptName

# Note: map different enum values
if($EventLevel -eq $INFO_LEVEL) {
$EventLevel = [System.Diagnostics.EventLogEntryType]::Information
} elseif($EventLevel -eq $WARNING_LEVEL) {
$EventLevel = [System.Diagnostics.EventLogEntryType]::Warning
} elseif($EventLevel -eq $ERROR_LEVEL) {
$EventLevel = [System.Diagnostics.EventLogEntryType]::Error
}

$eventInstance = new-object System.Diagnostics.EventInstance -ArgumentList @($EventNumber, 0, $EventLevel)
$eventLog.WriteEvent($eventInstance, $eventData)
}

Function LogScriptEventWithEventSource {
Param (
[parameter(Mandatory=$true)]
[string]$EventSource = "Fujitsu Out-Of-Band",
[parameter(Mandatory=$true)]
[ValidateRange(0,2)]
[int]$EventLevel,
[parameter(Mandatory=$true)]
[int]$EventNumber,
[parameter(Mandatory=$true)]
[string]$Message
)
DebugOut "Writing Event $($EventNumber) Level=($EventLevel) Source='$($EventSource)' Message='$($Message)'"
if ($ScriptApi -ne $Null) {
$ScriptApi.LogScriptEvent($EventSource, $EventNumber, $EventLevel, $Message)
}
}

# Backwards compatible wrapper
Function LogScriptEvent {
Param (
[parameter(Mandatory=$true)]
[ValidateRange(0,2)]
[int]$EventLevel,
[parameter(Mandatory=$true)]
[int]$EventNumber,
[parameter(Mandatory=$true)]
[string]$Message
)
# Note: Log will be written always with Event Source 'Health Service Script'
if ($ScriptApi -ne $Null) {
# Note: do not use actual script name to consolidate Alert Suppression from parallel scripts
$ScriptApi.LogScriptEvent("Fujitsu Out-Of-Band", $EventNumber, $EventLevel, $Message)
# $ScriptApi.LogScriptEvent($PoShScriptName, $EventNumber, $EventLevel, $Message)
}
}

# set CONSTANT variables (can not be changed):
set-variable -name SVISCOMLogXmlName -value "SVISCOM-OutOfBand.xml" -option constant
set-variable -name SVISCOMLogXm_Name -value "SVISCOM-OutOfBand.xm_" -option constant
set-variable -name SectionRoot -value "root" -option constant
set-variable -name SectionCommentSection -value "CommentSection" -option constant

# Traces for Discoveries
set-variable -name SectionServerDiscovery -value "ServerDiscovery" -option constant
set-variable -name SectionSmashDiscovery -value "SmashDiscovery" -option constant
set-variable -name SectionRaidDiscovery -value "RaidDiscovery" -option constant
set-variable -name SectionPerformanceDiscovery -value "PerformanceDiscovery" -option constant

# Traces for Monitors
set-variable -name SectionHardwareComponentMonitor -value "HardwareComponentsMonitor" -option constant
set-variable -name SectionComponentStatusMonitor -value "ComponentStatusMonitor" -option constant
set-variable -name SectionRaidMonitor -value "RaidMonitor" -option constant
set-variable -name SectionPerformanceMonitor -value "PerformanceMonitor" -option constant

set-variable -name SectionCommentHosts -value "CommentHosts" -option constant
set-variable -name TagDebugMode -value "DebugMode" -option constant
set-variable -name TagOverWrite -value "OverWrite" -option constant
set-variable -name TagHostsDiscovery -value "HostsForDiscovery" -option constant
set-variable -name TagHostsMonitoring -value "HostsForMonitoring" -option constant

# --------------------------------------------------------------------------
# Global variables = variables, which are changed in different functions ...
# ... and the changed value shall be available in the calling function
# --------------------------------------------------------------------------
$global:DebugMode = $False
$global:DebugFile = $False
$global:OverWrite = $True
$global:DebugHosts = ""
$global:DebugForHost = "$False"
$global:ErrFilePrefix = "ERRORTrace"
$global:WarnFilePrefix = "WARNINGTrace"
$global:LogTargetName = ""
$global:LogFilePrefix = ""
$global:LogFilePath = "$Env:TEMP\SVISCOM\SVISCOM-OutOfBand"
$global:LogFileName = "$LogFilePath\$($LogFilePrefix).log"

$global:MPVERSION = "N/A" # default
$global:MP_NAME = "N/A" # default

# --------------------------------------------------------------------------
Function Set-CurrentManagementPackVersion
{
Param (
[string] $RegistryPath = "HKLM:\SOFTWARE\Fujitsu\ServerView Suite\SCOM Integration\SVISCOM-OutOfBand",
[string] $MpName = "Fujitsu.Servers.PRIMERGY.OutOfBand"
)

if ($RegistryPath -ne $Null -and $MpName -ne $Null) {
# Load SCOM Extensions if not already done
$OMPSInstallKey = "HKLM:\Software\Microsoft\System Center Operations Manager\12\Setup\Powershell\V2"
$regKey = get-item $OMPSInstallKey
$OMPSInstallPath = $regKey.GetValue("InstallDirectory")
$omModule = $OMPSInstallPath + "OperationsManager"
Import-Module -Name $omModule

$MP = Get-SCOMManagementPack -Name $MpName
if ($MP -ne $Null) {
$MpVersion = "$($MP.Version.Major).$($MP.Version.Minor).$($MP.Version.Build).$($MP.Version.Revision)"
DebugOut "'$($MP.DisplayName)' Management Pack Version is $MpVersion"
try {
Set-ItemProperty -Path $RegistryPath -Name ( "$($MpName).CurrentVersion") -Value $MpVersion -Type String -ErrorAction Stop
} catch {
DebugErr $SCRIPT_EVENT_NUMBER "Error writing Management Pack CurrentVersion. Exception: $_"
}
}
}
}

Function Get-CurrentManagementPackVersion
{
Param (
[string] $RegistryPath = "HKLM:\SOFTWARE\Fujitsu\ServerView Suite\SCOM Integration\SVISCOM-OutOfBand",
[string] $MpName = "Fujitsu.Servers.PRIMERGY.OutOfBand"
)
if ($RegistryPath -ne $Null -and $MpName -ne $Null) {
try {
$regKey = get-item $RegistryPath
$global:MPVERSION = $regKey.GetValue( "$($MpName).CurrentVersion" )
} catch {}
}
}

Function PrepareLogging
{
Param (
[string] $Section,
[string] $HostTag,
[string] $ServerName,
[switch] $CreateSampleLogFile,
[string] $MpName = "Fujitsu.Servers.PRIMERGY.OutOfBand"
)

$global:LogFilePrefix = GiveBaseName $PoShScriptName
$global:LogFileName = "$global:LogFilePath\$($global:LogFilePrefix)Trace_$ServerName.log"
$global:MP_NAME = $MpName

Get-CurrentManagementPackVersion -MpName $MpName

if ($CreateSampleLogFile) {
CreateLogXmlFile
}
if ($global:DebugMode -eq $False) {
GetLogXmlFile $Section $HostTag $ServerName
}

CreateLogFile

#DebugOut "SYSTEMDRIVE = $env:SYSTEMDRIVE"
#DebugOut "TEMP = $env:TEMP"
DebugOut "LogFilePath = $global:LogFilePath"
DebugOut "LogFileName = $global:LogFileName"

$global:LogTargetName = $ServerName
}

Function GiveBaseName
{
Param (
[string] $in
)

$a = $in.split('.')
Write-Output "$($a[0])"
}

Function CreateLogXmlFile
{
$fileOK = $False
$pathOK = $False
$Xm_FileName = "$global:LogFilePath\$SVISCOMLogXm_Name"

# create the target directory, if it does not exist
if ( ! (Test-Path -Path $global:LogFilePath)) {
New-Item -ItemType directory -Path $global:LogFilePath | Out-Null
}
if (Test-Path -Path $global:LogFilePath) {
$pathOK = $True
}

if (Test-Path -Path $Xm_FileName) {
$txt = get-content $Xm_FileName
foreach ($line in $txt) {
if ($line.contains($LOGFILE_VERSION)) {
$fileOK = $True
break
}
}
}

if (($pathOK -eq $True) -and ($fileOK -eq $False)) {
# we write a new SVISCOM-OutOfBand.xm_ file every time the MP is changed to make sure all
# INI-Values are documented for use by the customer if anything changes.
if (Test-Path -Path $Xm_FileName) {
Remove-Item -Path $Xm_FileName -Force | Out-Null
}
#Create xm_ file
New-Item -Path $Xm_FileName -ItemType File | Out-Null

Add-Content -Path $Xm_FileName -Value @"
&lt;$SectionRoot&gt;
&lt;!--
$SVISCOMLogXmlName Debug XML file Version $LOGFILE_VERSION

With this file logging for PowerShell scripts within the
- Fujitsu Out-Of-Band Management Pack and
- Optional Extension Management Packs for the Fujitsu Out-Of-Band Management Pack
can be enabled.

Rename the file type from '.xm_' to '.xml' to enable reading this file.

Note: You have to enable debug for a script and also select the server in
the '&lt;$TagHostsDiscovery&gt;' or '&lt;$TagHostsMonitoring&gt;' section to generate traces (see below).

The following sections specify for which PowerShell scripts the traces will be generated;
Each of the sections represents a single PowerShell script.

'&lt;$TagDebugMode&gt;' enables logging (yes) or disables logging (no)
'&lt;$TagOverWrite&gt;' defines continuous logging (no) or single script run logging (yes)
--&gt;
&lt;!-- DISCOVERIES --&gt;
&lt;!-- The following section enables trace files for the Out-Of-Band Server discovery script --&gt;
&lt;$SectionServerDiscovery&gt;
&lt;$TagDebugMode&gt;yes&lt;/$TagDebugMode&gt;
&lt;$TagOverWrite&gt;no&lt;/$TagOverWrite&gt;
&lt;/$SectionServerDiscovery&gt;
&lt;!-- The following section enables trace files for the SMASH device discovery script --&gt;
&lt;$SectionSmashDiscovery&gt;
&lt;$TagDebugMode&gt;yes&lt;/$TagDebugMode&gt;
&lt;$TagOverWrite&gt;no&lt;/$TagOverWrite&gt;
&lt;/$SectionSmashDiscovery&gt;
&lt;!-- The following section enables trace files for the RAID discovery script --&gt;
&lt;$SectionRaidDiscovery&gt;
&lt;$TagDebugMode&gt;yes&lt;/$TagDebugMode&gt;
&lt;$TagOverWrite&gt;no&lt;/$TagOverWrite&gt;
&lt;/$SectionRaidDiscovery&gt;
&lt;!-- The following section enables trace files for the Performance Monitor discovery script --&gt;
&lt;$SectionPerformanceDiscovery&gt;
&lt;$TagDebugMode&gt;yes&lt;/$TagDebugMode&gt;
&lt;$TagOverWrite&gt;no&lt;/$TagOverWrite&gt;
&lt;/$SectionPerformanceDiscovery&gt;

&lt;!-- MONITORS --&gt;
&lt;!-- The following section enables trace files for the main server Hardware Components (CPU/Memory/Fan/PowerSupply) monitoring script --&gt;
&lt;$SectionHardwareComponentMonitor&gt;
&lt;$TagDebugMode&gt;yes&lt;/$TagDebugMode&gt;
&lt;$TagOverWrite&gt;no&lt;/$TagOverWrite&gt;
&lt;/$SectionHardwareComponentMonitor&gt;
&lt;!-- The following section enables trace files for the 'Component Status' monitoring script --&gt;
&lt;$SectionComponentStatusMonitor&gt;
&lt;$TagDebugMode&gt;yes&lt;/$TagDebugMode&gt;
&lt;$TagOverWrite&gt;no&lt;/$TagOverWrite&gt;
&lt;/$SectionComponentStatusMonitor&gt;
&lt;!-- The following section enables trace files for the RAID monitoring script --&gt;
&lt;$SectionRaidMonitor&gt;
&lt;$TagDebugMode&gt;yes&lt;/$TagDebugMode&gt;
&lt;$TagOverWrite&gt;no&lt;/$TagOverWrite&gt;
&lt;/$SectionRaidMonitor&gt;
&lt;!-- The following section enables trace files for the Performance monitoring script --&gt;
&lt;$SectionPerformanceMonitor&gt;
&lt;$TagDebugMode&gt;yes&lt;/$TagDebugMode&gt;
&lt;$TagOverWrite&gt;no&lt;/$TagOverWrite&gt;
&lt;/$SectionPerformanceMonitor&gt;

&lt;!--
The following sections specify for which servers the traces will be generated:

In the '&lt;$TagHostsDiscovery&gt;' and '&lt;$TagHostsMonitoring&gt;' sections
single or multiple servers can be specified for verbose debug output
during the discovery and/or during monitoring.

Use '&lt;$TagHostsDiscovery&gt;' for selecting hosts for the discovery trace.
Use '&lt;$TagHostsMonitoring&gt;' for selecting hosts for the monitoring trace.

Use 'all' (without quote signs) for all Fujitsu Out-Of-Band Servers monitored by SCOM.
Use a single IP address or a comma separated list to select multiple single servers
Example:
&lt;$TagHostsDiscovery&gt;all&lt;/$TagHostsDiscovery&gt;
&lt;$TagHostsMonitoring&gt;192.168.1.100,192.168.1.101,192.168.1.102&lt;/$TagHostsMonitoring&gt;

will generate discovery traces for all Fujitsu Out-Of-Band Servers and
will generate monitoring traces only for servers with the IP address
192.168.1.100 192.168.1.101 and 192.168.1.102
--&gt;
&lt;$TagHostsDiscovery&gt;all&lt;/$TagHostsDiscovery&gt;
&lt;$TagHostsMonitoring&gt;all&lt;/$TagHostsMonitoring&gt;
&lt;/$SectionRoot&gt;
"@
}
}

Function GetLogXmlFile
{
Param (
[string] $Section,
[string] $HostTag,
[string] $ServerName
)

$XmlFileName = "$global:LogFilePath\$SVISCOMLogXmlName"
$ListOfHosts = ""

if (Test-Path -Path $global:LogFilePath) {
if (Test-Path -Path $XmlFileName) {
[xml]$xmlfile = Get-Content $XmlFileName

if ($xmlfile.$SectionRoot.$section.$TagDebugMode -ne $null) {
if ($($xmlfile.$SectionRoot.$Section.$TagDebugMode).ToUpper() -eq "YES") {
$global:DebugMode = $True
$global:DebugFile = $True
}
}

if ($xmlfile.$SectionRoot.$section.$TagOverWrite -ne $null) {
if ($($xmlfile.$SectionRoot.$Section.$TagOverWrite).ToUpper() -eq "NO") {
$global:OverWrite = $False
}
}

if ($xmlfile.$SectionRoot.$HostTag -ne $null) {
$global:DebugHosts = $($xmlfile.$SectionRoot.$HostTag).ToLower()
}

# Check if DEBUG shall run for this server.
# There are two possibilities to check: "all" server DEBUG is on or this server is in the list.
if ($global:DebugHosts -eq "all") {
$global:DebugForHost = $True
} else {
# Check if this host is in the list of DebugHosts
$ListOfHosts = $($global:DebugHosts).split(',')
DebugOut "Searching for host: $ServerName"
DebugOut "in list of DebugHosts: $global:DebugHosts"

if ($ServerName.ToLower() -in $ListOfHosts) {
$global:DebugForHost = $True
}
}

} # else file does not exist
} # else directory does not exist
}

Function CreateLogFile
{
# For some reason checking for "$True" with "if ($global:a -and $global:b)" is not evaluated correctly!!!
# It works OK in a test with a simple PS script ... no idea why ... Thus we use:
if ($global:DebugForHost -eq $True) {
if ($global:DebugFile -eq $True) {
# Create the target directory, if it does not exist
if (!(Test-Path -Path $global:LogFilePath)) {
New-Item -ItemType directory -Path $global:LogFilePath | Out-Null
}

# Check if file exists and delete if it does and OverWrite is set to TRUE
if (Test-Path -Path $global:LogFileName) {
DebugOut ""
DebugOut "Log file already exists at: $global:LogFileName"
if ($global:OverWrite -eq $True) {
Remove-Item -Path $global:LogFileName -Force | Out-Null
}
}
# If the file has just been removed (OverWrite = YES) or the file does not exist: create it
if (!(Test-Path -Path $global:LogFileName)) {
#Create log file
New-Item -Path $global:LogFileName -ItemType File | Out-Null
}

Add-Content -Path $global:LogFileName -Value @"
********** $(Get-Date -Format F) **********`r
********** $($global:LogFileName) **********`r
********** Management Pack '$($global:MP_NAME)' Version: $($global:MPVERSION)`r
"@
}
}
}

Function DebugOut
{
Param (
[string] $Text
)

if ($global:DebugForHost -eq $True) {
if ($global:DebugMode -eq $True) {
Write-Host $Text
}

if ($global:DebugFile -eq $True) {
if ($global:LogFileName.Length -gt 0) {
if (Test-Path -Path $global:LogFileName) {
$DateTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
Add-Content -Path $global:LogFileName -Value "$DateTime $Text"
}
}
}
}
}

Function DebugWarn
{
Param (
[string] $Text
)

DebugOut "Warning: $Text"

if ($global:DebugForHost -eq $True) {
if ($global:DebugFile -eq $True) {
$WarnLogFile = "$global:LogFilePath\$($WarnFilePrefix)_$($global:LogTargetName).log"
$DateTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
Add-Content -Path $WarnLogFile -Value "[$($DateTime)] [$($PoShScriptName)] $($Text)"
}
}
}

Function DebugErr
{
Param (
[int] $ErrNo,
[string] $Text
)

DebugOut "Error: $Text"

if ($global:DebugForHost -eq $True) {
if ($global:DebugFile -eq $True) {
$ErrLogFile = "$global:LogFilePath\$($ErrFilePrefix)_$($global:LogTargetName).log"
$DateTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
Add-Content -Path $ErrLogFile -Value "[$($ErrNo)] [$($DateTime)] [$($PoShScriptName)] $($Text)"
}
}
}




Main
</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>UserName</Name>
<Value>$Config/UserName$</Value>
</Parameter>
<Parameter>
<Name>Password</Name>
<Value>$Config/Password$</Value>
</Parameter>
<Parameter>
<Name>ManagementUrl</Name>
<Value>$Config/ManagementUrl$</Value>
</Parameter>
<Parameter>
<Name>TimeoutSeconds</Name>
<Value>$Config/TimeoutSeconds$</Value>
</Parameter>
<Parameter>
<Name>SkipCACheck</Name>
<Value>$Config/SkipCACheck$</Value>
</Parameter>
<Parameter>
<Name>SkipCNCheck</Name>
<Value>$Config/SkipCNCheck$</Value>
</Parameter>
<Parameter>
<Name>ScriptName</Name>
<Value>PerfMonMonitor.ps1</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
<StrictErrorHandling>$Config/StrictErrorHandling$</StrictErrorHandling>
</ProbeAction>
</MemberModules>
<Composition>
<Node ID="Script">
<Node ID="PassThrough"/>
</Node>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.PropertyBagData</OutputType>
<TriggerOnly>true</TriggerOnly>
</ProbeActionModuleType>