# encoding: ascii
# api: powershell
# title: CIM SMI-S Query Library
# description: The function queries any CIM server, called CIMOM, that supports the CIM-XML interface. It creates an XML message to encapsulate the CIM query, converts the message to byte stream and then sends it using HTTP POST method. The response byte stream is converted back to XML message and name value paris are parsed out. SMI-S is an instance of CIM, and is thus also fully supported.
# version: 0.2
# type: function
# author: Parul Jain
# license: CC0
# function: Invoke-CIM_EnumerateInstances
# x-poshcode-id: 3985
# x-archived: 2014-04-08T03:50:08
# x-published: 2014-02-22T18:57:00
#
#
function Invoke-CIM_EnumerateInstances {
<#
.SYNOPSIS
Enumerate Instances of a class on a CIMOM via CIM-XML interface
.DESCRIPTION
Primary use case of this function is to gather inventory and performance information from IT
infrastructure assets. The inventory information feeds into capacity planning, troubleshooting,
managing product life cycle, budgeting, vendor price negotiations and technology strategy in
large enterprise environments. The output from this function would typically go into a datawarehouse
front ended with a business intelligence platform such as COGNOS, QlikView, Business Objects, etc.
The function queries any CIM server, called CIMOM, that supports the CIM-XML interface. It
creates an XML message to encapsulate the CIM query, converts the message to byte stream and
then sends it using HTTP POST method. The response byte stream is converted back to XML message
and name value pairs are parsed out. SMI-S is an instance of CIM, and is thus also fully supported.
Tested against SAN devices such as EMC Symmetrix VMAX Fibre Channel Storage Array and Cisco MDS
Fibre Channel switch. It can be used to query VMWARE vSphere vCenter, IBM XIV, NetApp Filer, EMC
VNX Storage Array, HP Insight Manager, Dell OpenManage, HDS: USP, USPV, VSP, AMS, etc.
.NOTES
Author: Parul Jain (paruljain@hotmail.com)
Version: 0.2, Jan, 2013
Requires: PowerShell v2 or better
.EXAMPLE
This works with EMC Symmetrix
Invoke-CIM_EnumerateInstances -Class Symm_StorageSystem -CIMServer seserver -user admin -Pass '#1Password' -ns 'root/emc'
.PARAMETER class
Mandatory. Information within CIM is classified into classes. The device documentation (or SNIA
documntation in case of SMI-S) should list all the classes supported by the CIMOM. CIM_ComputerSystem
class is available universally and is a good place to start testing.
.PARAMETER CIMServer
Mandatory. IP address or DNS name of the device or CIMOM server if CIMOM runs outside the device
.PARAMETER user
Mandatory. User ID authorized to perform queries. Most hardware vendors have a factory default
.PARAMETER pass
Mandatory. Password for the user. Again most hardware vendors have a factory default for servicing the equipment
.PARAMETER port
Optional. The TCP port number that the CIMOM is listening to. Default is used if not specified.
.PARAMETER ssl
Optional switch. When used function will use HTTPS instead of default HTTP
.PARAMETER ns
Optional. CIM namespace to use. Default is root/cimv2. EMC uses root/emc
.PARAMETER dbg
Optional switch. Returns CIM-XML response message instead of parsed name-value pairs for
troubleshooting parsing if needed
#>
[CmdletBinding()]
Param (
[parameter(Mandatory=$true, ValueFromPipeline=$true)][String]$Class,
[parameter(Mandatory=$true, ValueFromPipeline=$false)][String]$User,
[parameter(Mandatory=$true, ValueFromPipeline=$false)][String]$Pass,
[parameter(Mandatory=$true, ValueFromPipeline=$false)][String]$CIMServer,
[parameter(Mandatory=$false, ValueFromPipeline=$false)][String]$Port,
[parameter(Mandatory=$false, ValueFromPipeline=$false)][Switch]$ssl,
[parameter(Mandatory=$false, ValueFromPipeline=$false)][String]$ns = 'root/cimv2',
[parameter(Mandatory=$false, ValueFromPipeline=$false)][Switch]$dbg
)
# CIM-XML message template
$messageText = @'
<?xml version="1.0" encoding="utf-8" ?>
<CIM CIMVERSION="2.0" DTDVERSION="2.0">
<MESSAGE ID="1000" PROTOCOLVERSION="1.0">
<SIMPLEREQ>
<IMETHODCALL NAME="EnumerateInstances">
<LOCALNAMESPACEPATH>
</LOCALNAMESPACEPATH>
<IPARAMVALUE NAME="ClassName">
<CLASSNAME NAME="CIM_ComputerSystem" />
</IPARAMVALUE>
<IPARAMVALUE NAME="DeepInheritance">
<VALUE>FALSE</VALUE>
</IPARAMVALUE>
<IPARAMVALUE NAME="LocalOnly">
<VALUE>TRUE</VALUE>
</IPARAMVALUE>
<IPARAMVALUE NAME="IncludeClassOrigin">
<VALUE>FALSE</VALUE>
</IPARAMVALUE>
<IPARAMVALUE NAME="IncludeQualifiers">
<VALUE>FALSE</VALUE>
</IPARAMVALUE>
</IMETHODCALL>
</SIMPLEREQ>
</MESSAGE>
</CIM>
'@
# Parse the XML text into XMLDocument
$message = [xml]($messageText)
# Set class name
($message.CIM.MESSAGE.SIMPLEREQ.IMETHODCALL.IPARAMVALUE | where { $_.Name -eq 'ClassName' }).Classname.Name = $Class
# Set the namespace
$nsNode = $message.SelectSingleNode('/CIM/MESSAGE/SIMPLEREQ/IMETHODCALL/LOCALNAMESPACEPATH')
foreach ($item in $ns.split('/')) {
$nsNode.InnerXml += '<NAMESPACE NAME="' + $item + '" />'
}
# Do not validate server certificate when using HTTPS
# Amazing how easy it is to create a delegated function in PowerShell!
[Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
# Process other parameters and switches
if ($ssl) { $protocol = 'https://' } else { $protocol = 'http://' }
if (!$port) { if ($ssl) { $port = '5989' } else { $port = '5988' } }
$url = $protocol + $CIMServer + ":" + $port + '/cimom'
# Instantiate .Net WebClient class
$req = New-Object Net.WebClient
# Add headers required by CIMOM
$req.Headers.Add('Content-Type', 'application/xml;charset="UTF-8"')
$req.Headers.Add('CIMOperation', 'MethodCall')
$req.Headers.Add('CIMMethod', 'EnumerateInstances')
$req.Headers.Add('CIMObject', $ns)
$req.Headers.Add('Authorization', 'Basic ' + [Convert]::ToBase64String([text.encoding]::UTF8.GetBytes($user + ':' + $pass)))
# Send the message to CIMOM server and build $result object based on response XML
$result = [xml]($req.UploadString($url, $message.OuterXml))
# Return the raw XML message and exit if debug option is used
if ($dbg) { return $result }
# Parse attributes from response and build object $object from it
foreach ($instance in @($result.CIM.MESSAGE.SIMPLERSP.IMETHODRESPONSE.IRETURNVALUE.'Value.NamedInstance')) {
$object = New-Object PSObject
foreach ($prop in @($instance.instance.property)) {
if ($prop.value -ne $null -and $prop.value -ne '') {
$object | Add-Member -MemberType NoteProperty -Name $prop.Name -Value $prop.Value
}
}
$object # Return multiple objects (array)
}
}
function Invoke-CIM_GetInstance {
[CmdletBinding()]
Param (
[parameter(Mandatory=$true, ValueFromPipeline=$true)][String]$Class,
[parameter(Mandatory=$true, ValueFromPipeline=$false)][String]$User,
[parameter(Mandatory=$true, ValueFromPipeline=$false)][String]$Pass,
[parameter(Mandatory=$true, ValueFromPipeline=$false)][String]$CIMServer,
[parameter(Mandatory=$false, ValueFromPipeline=$false)][String]$Port,
[parameter(Mandatory=$false, ValueFromPipeline=$false)][Switch]$ssl,
[parameter(Mandatory=$false, ValueFromPipeline=$false)][String]$ns = 'root/cimv2',
[parameter(Mandatory=$false, ValueFromPipeline=$false)][Switch]$dbg,
[parameter(Mandatory=$true, ValueFromPipeline=$false)][String]$key
)
# CIM-XML message template
$messageText = @'
<?xml version="1.0" encoding="utf-8" ?>
<CIM CIMVERSION="2.0" DTDVERSION="2.0">
<MESSAGE ID="1000" PROTOCOLVERSION="1.0">
<SIMPLEREQ>
<IMETHODCALL NAME="GetInstance">
<LOCALNAMESPACEPATH>
</LOCALNAMESPACEPATH>
<IPARAMVALUE NAME="InstanceName">
<INSTANCENAME CLASSNAME="Symm_StorageSystem">
<KEYBINDING NAME="CreationClassName">
<KEYVALUE VALUETYPE="string">Symm_StorageSystem</KEYVALUE>
</KEYBINDING>
<KEYBINDING NAME="Name">
<KEYVALUE VALUETYPE="string">SYMMETRIX+000192601380</KEYVALUE>
</KEYBINDING>
</INSTANCENAME>
</IPARAMVALUE>
<IPARAMVALUE NAME="LocalOnly">
<VALUE>FALSE</VALUE>
</IPARAMVALUE>
</IMETHODCALL>
</SIMPLEREQ>
</MESSAGE>
</CIM>
'@
# Parse the XML text into XMLDocument
$message = [xml]($messageText)
# Set class name
($message.CIM.MESSAGE.SIMPLEREQ.IMETHODCALL.IPARAMVALUE | where { $_.Name -eq 'InstanceName' }).InstanceName.ClassName = $Class
(($message.CIM.MESSAGE.SIMPLEREQ.IMETHODCALL.IPARAMVALUE |
where { $_.Name -eq 'InstanceName' }).instancename.keybinding | where { $_.Name -eq 'CreationClassName' }).KeyValue.InnerText = $Class
(($message.CIM.MESSAGE.SIMPLEREQ.IMETHODCALL.IPARAMVALUE |
where { $_.Name -eq 'InstanceName' }).instancename.keybinding | where { $_.Name -eq 'Name' }).KeyValue.InnerText = $Key
# Set the namespace
$nsNode = $message.SelectSingleNode('/CIM/MESSAGE/SIMPLEREQ/IMETHODCALL/LOCALNAMESPACEPATH')
foreach ($item in $ns.split('/')) {
$nsNode.InnerXml += '<NAMESPACE NAME="' + $item + '" />'
}
# Do not validate server certificate when using HTTPS
# Amazing how easy it is to create a delegated function in PowerShell!
[Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
# Process other parameters and switches
if ($ssl) { $protocol = 'https://' } else { $protocol = 'http://' }
if (!$port) { if ($ssl) { $port = '5989' } else { $port = '5988' } }
$url = $protocol + $CIMServer + ":" + $port + '/cimom'
# Instantiate .Net WebClient class
$req = New-Object Net.WebClient
# Add headers required by CIMOM
$req.Headers.Add('Content-Type', 'application/xml;charset="UTF-8"')
$req.Headers.Add('CIMOperation', 'MethodCall')
$req.Headers.Add('CIMMethod', 'GetInstance')
$req.Headers.Add('CIMObject', $ns)
$req.Headers.Add('Authorization', 'Basic ' + [Convert]::ToBase64String([text.encoding]::UTF8.GetBytes($user + ':' + $pass)))
# Send the message to CIMOM server and build $result object based on response XML
$result = [xml]($req.UploadString($url, $message.OuterXml))
# Return the raw XML message and exit if debug option is used
if ($dbg) { return $result }
# Parse attributes from response and build object $object from it
$object = New-Object PSObject
foreach ($prop in @($result.CIM.MESSAGE.SIMPLERSP.IMETHODRESPONSE.IRETURNVALUE.INSTANCE.PROPERTY)) {
if ($prop.value -ne $null -and $prop.value -ne '') {
$object | Add-Member -MemberType NoteProperty -Name $prop.Name -Value $prop.Value
}
}
$object # Return multiple objects (array)
}
function Get-EMCStoragePools ($SMIserver) {
Invoke-CIM_EnumerateInstances -Class EMC_ConcreteStoragePool -CIMserver $SMIserver -user admin -Pass '#1Password' -ns 'root/emc'
}
function Get-SNIADiskDriveView ($SMIServer) {
Invoke-CIM_EnumerateInstances -Class SNIA_DiskDriveView -CIMserver $SMIserver -user admin -Pass '#1Password' -ns 'root/emc'
}
function Get-SymmStorageSystem ([string]$SMIServer, [string]$sid) {
if (!$sid) {
Invoke-CIM_EnumerateInstances -Class Symm_StorageSystem -CIMserver $SMIserver -user admin -Pass '#1Password' -ns 'root/emc'
} else {
Invoke-CIM_GetInstance -Class Symm_StorageSystem -ns 'root/emc' -user admin -pass '#1Password' -CIMServer $SMIserver -key 'SYMMETRIX+' + $sid
}
}
function Get-SymmStorageVolume ($SMIServer) {
# Caution - returns a LOT OF DATA!
Invoke-CIM_EnumerateInstances -Class Symm_StorageVolume -CIMServer $SMIServer -User admin -Pass '#1Password' -ns 'root/emc'
}