Code:
/*
Windows Management Instrumentation Enumerator
[Generates output compatible with the DMTF's Managed Object Format (MOF)]
Copyright (c) 2009 Sebastian Garth
THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
TODO:
- Provide connection options (username, password, authentication, timeout, etc.)
- Detect qualifier 'flavors'
- Generalize the class so that output is written to any TextWriter object
*/
using System;
using System.Collections;
using System.Management;
class WmiEnumerator
{
public class Option
{
public enum Category
{
Definitions,
Properties,
Methods,
Qualifiers,
Instances,
/*
IMPORTANT: New option enumerations *must* be added before ProgramOptionCount.
*/
ProgramOptionCount
};
public string Name;
public bool Enabled;
public string Description;
public Option( string Name, bool Enabled, string Description )
{
this.Name = Name;
this.Enabled = Enabled;
this.Description = Description;
}
};
Option [ ] ProgramOptions = new Option[ ( int )Option.Category.ProgramOptionCount ];
static void Main( string [ ] CommandLine )
{
new WmiEnumerator( CommandLine );
}
WmiEnumerator( string [ ] CommandLine )
{
/*
IMPORTANT: Option names *must* be all lowercase (this doesn't apply to user input, however).
*/
ProgramOptions[ ( int )Option.Category.Definitions ] = new Option( "definitions", true, "List class definitions" );
ProgramOptions[ ( int )Option.Category.Properties ] = new Option( "properties", true, "List class member properties" );
ProgramOptions[ ( int )Option.Category.Methods ] = new Option( "methods", true, "List class member methods" );
ProgramOptions[ ( int )Option.Category.Qualifiers ] = new Option( "qualifiers", true, "List class/property/method metadata" );
/*
NOTE: Enumerating some types of instances generates a huge amount of output,
while others cause the program to hang for a while, so this option is disabled, by default.
*/
ProgramOptions[ ( int )Option.Category.Instances ] = new Option( "instances", false, "List class instances (use selectively)" );
if( CommandLine.Length == 0 )
{
Console.WriteLine( @"Usage: [-[<OPTION>][<MODIFIER>]] [\\<SERVER>][\<NAMESPACE(S)>][:<CLASSNAME>]" );
Console.WriteLine( "Example: wmie.exe root" );
Console.WriteLine( "Note: Multiple classes/namespaces can be specified, each with custom options" );
Console.WriteLine( "Option modifiers:" );
Console.WriteLine( "\t+ : Enable option" );
Console.WriteLine( "\t- : Disable option" );
Console.WriteLine( "Note: If no modifier is specified, option is enabled" );
Console.WriteLine( "Options:" );
for( int Index = 0; Index < ProgramOptions.Length; ++Index )
{
Console.WriteLine
(
"\t" + ProgramOptions[ Index ].Name + " : " + ProgramOptions[ Index ].Description
+
" [default: " + ( ProgramOptions[ Index ].Enabled ? "on" : "off" ) + "]"
);
}
Console.WriteLine( "Note: Partial option names may be used (if unambiguous)" );
}
else foreach( string Command in CommandLine )
{
try
{
/*
NOTE: If the user supplies mangled input that even remotely resembles an option, an IndexOutOfRange exception might
be thrown. We'll just leave it up to the exception handler report this, rather than go to extremes to detect it here.
*/
if( Command[ 0 ] == '-' )
{
bool OptionState = true;
int LastIndex = Command.Length - 1;
char OptionModifier = Command[ LastIndex ];
if( OptionModifier == '+' )
{
--LastIndex;
}
else if( OptionModifier == '-' )
{
--LastIndex;
OptionState = false;
}
string SelectedOption = Command.Substring( 1, LastIndex ).ToLower( );
/*
Since partial matches of option names are allowed, we need to ensure that the substring doesn't match multiple options.
*/
int
OptionMatches = 0,
MatchedOptionIndex = 0;
for( int Index = 0; Index < ProgramOptions.Length; ++Index )
{
if( ProgramOptions[ Index ].Name.IndexOf( SelectedOption ) == 0 )
{
++OptionMatches;
MatchedOptionIndex = Index;
}
}
if( OptionMatches == 1 )
{
ProgramOptions[ MatchedOptionIndex ].Enabled = OptionState;
}
else if( OptionMatches > 1 )
{
throw new Exception( "Ambiguous request for option '" + SelectedOption + "'" );
}
else/* OptionMatches == 0 */
{
throw new Exception( "Invalid option '" + SelectedOption + "'" );
}
}
else
{
ManagementClass CimClassCategory = new ManagementClass( Command );
if( CimClassCategory.Path.IsClass )
{
PrintClassInformation( CimClassCategory );
}
else
{
EnumerationOptions CimClassEnumerationOptions = new EnumerationOptions( );
CimClassEnumerationOptions.EnumerateDeep = true;
foreach( ManagementClass NextCimClassCategory in CimClassCategory.GetSubclasses( CimClassEnumerationOptions ) )
{
PrintClassInformation( NextCimClassCategory );
}
}
}
}
/*
NOTE: Exceptions thrown due to invalid/unservicable WBEM requests are simply reported and then processing continues normally,
while malformed option switches, memory access faults, etc, are treated as fatal errors, thus forcing the program to abort.
*/
catch( ManagementException ManagementExceptionObject )
{
Console.Write( "\nError: " + ManagementExceptionObject.Message );
}
catch( Exception GeneralExceptionObject )
{
Console.Write( "\nFatal: " + GeneralExceptionObject.Message );
break;
}
}
}
void PrintClassInformation( ManagementClass CimClassCategory )
{
int
/*
Number of spaces per tab.
*/
DefaultTabSize = 4,
/*
NOTE: To ensure uniform formatting, ClassCategoryIndentation should be some multiple of DefaultTabSize.
*/
ClassCategoryIndentation = DefaultTabSize * 0,
ClassMemberIndentation = Math.Max( ClassCategoryIndentation * 2, DefaultTabSize );
if( ProgramOptions[ ( int )Option.Category.Definitions ].Enabled )
{
if( ProgramOptions[ ( int )Option.Category.Qualifiers ].Enabled )
{
PrintQualifiers( CimClassCategory.Qualifiers, ClassCategoryIndentation );
}
object CimClassSuperclassNameValue = CimClassCategory.SystemProperties[ "__SUPERCLASS" ].Value;
Console.Write
(
GenerateTabString( ClassCategoryIndentation ) + "class " + CimClassCategory.Path.ClassName
+
( CimClassSuperclassNameValue == null ? "" : " : " + CimClassSuperclassNameValue.ToString( ) ) + "\n"
+
GenerateTabString( ClassCategoryIndentation ) + "{\n\n"
);
if( ProgramOptions[ ( int )Option.Category.Properties ].Enabled )
{
foreach( PropertyData CimClassProperty in CimClassCategory.Properties )
{
if( ProgramOptions[ ( int )Option.Category.Qualifiers ].Enabled )
{
PrintQualifiers( CimClassProperty.Qualifiers, ClassMemberIndentation );
}
Console.Write
(
GenerateTabString( ClassMemberIndentation ) + ExpandTypeNameText( CimClassProperty ) + " "
+
CimClassProperty.Name
+
(
CimClassProperty.Value == null ? "" : " = " + ExpandTypeValueText( CimClassProperty.Value )
)
+
";\n\n"
);
}
}
if( ProgramOptions[ ( int )Option.Category.Methods ].Enabled )
{
foreach( MethodData CimClassMethod in CimClassCategory.Methods )
{
if( ProgramOptions[ ( int )Option.Category.Qualifiers ].Enabled )
{
PrintQualifiers( CimClassMethod.Qualifiers, ClassMemberIndentation );
}
int CimClassMethodOutParameterCount =
CimClassMethod.OutParameters == null ? 0 : CimClassMethod.OutParameters.Properties.Count;
PropertyData [ ] CimClassMethodOutParameters = null;
/*
Print the function return type. If there are more 'out' values, they will be printed as method parameters.
*/
Console.Write( GenerateTabString( ClassMemberIndentation ) );
if( CimClassMethodOutParameterCount > 0 )
{
CimClassMethod.OutParameters.Properties.CopyTo
(
CimClassMethodOutParameters = new PropertyData[ CimClassMethodOutParameterCount ], 0
);
Console.Write( ExpandTypeNameText( CimClassMethodOutParameters[ 0 ] ) + " " );
}
Console.Write( CimClassMethod.Name + "(" );
/*
If non-zero, OutputComma simply indicates that a comma needs to be output before the next parameter.
*/
int OutputComma = 0;
if( CimClassMethod.InParameters != null )
{
foreach( PropertyData CimClassMethodInParameter in CimClassMethod.InParameters.Properties )
{
if( OutputComma++ != 0 )
{
Console.Write( "," );
}
Console.Write
(
" [ IN ] " + ExpandTypeNameText( CimClassMethodInParameter ) + " "
+
CimClassMethodInParameter.Name
);
}
}
if( CimClassMethodOutParameterCount > 1 )
{
/*
We need to skip the first 'out' parameter, since it has already been printed.
*/
for( int Index = 1; Index < CimClassMethodOutParameterCount; ++Index )
{
if( OutputComma++ != 0 )
{
Console.Write( "," );
}
Console.Write
(
" [ OUT ] " + ExpandTypeNameText( CimClassMethodOutParameters[ Index ] ) + " "
+
CimClassMethodOutParameters[ Index ].Name
);
}
}
Console.Write( " );\n\n" );
}
}
Console.Write( GenerateTabString( ClassCategoryIndentation ) + "};\n\n" );
}
if( ProgramOptions[ ( int )Option.Category.Instances ].Enabled )
{
foreach( ManagementObject CimClassInstance in CimClassCategory.GetInstances( ) )
{
Console.Write( GenerateTabString( ClassCategoryIndentation ) + "instance of " + CimClassCategory.Path.ClassName + "\n{\n\n" );
foreach( PropertyData CimClassInstanceProperty in CimClassInstance.Properties )
{
Console.Write
(
GenerateTabString( ClassMemberIndentation ) + ExpandTypeNameText( CimClassInstanceProperty ) + " "
+
CimClassInstanceProperty.Name + " = "
+
(
CimClassInstanceProperty.Value == null ? "null" : ExpandTypeValueText( CimClassInstanceProperty.Value )
)
+
";\n\n"
);
}
Console.Write( GenerateTabString( ClassCategoryIndentation ) + "};\n\n" );
}
}
}
void PrintQualifiers( QualifierDataCollection CimQualifierCollection, int Indentation )
{
if( CimQualifierCollection.Count != 0 )
{
Console.Write( GenerateTabString( Indentation ) + "[ " );
int Index = 0;
foreach( QualifierData CimQualifier in CimQualifierCollection )
{
if( Index++ != 0 )
{
Console.Write( ", " );
}
Console.Write( CimQualifier.Name );
if( CimQualifier.Value != null )
{
Console.Write( "( " + ExpandTypeValueText( CimQualifier.Value ) + " )" );
}
}
Console.Write( " ]\n" );
}
}
static string GenerateTabString( int NumberOfSpaces )
{
string TabString = "";
while( NumberOfSpaces-- > 0 )
{
TabString += " ";
}
return TabString;
}
static string ExpandTypeNameText( PropertyData Property )
{
int CimValueNameOffest = 4;
string PropertyTypeNameText = null;
string OptionalArrayBrackets = Property.IsArray ? " [ ]" : "";
if( Property.Type == CimType.Reference )
{
PropertyTypeNameText = Property.Qualifiers[ "CIMTYPE" ].Value.ToString( ).Substring( CimValueNameOffest )
+
OptionalArrayBrackets + " ref";
}
else
{
PropertyTypeNameText = Property.Type.ToString( ) + OptionalArrayBrackets;
}
return PropertyTypeNameText;
}
static string ExpandTypeValueText( object Object )
{
string ExpandedText = null;
if( Object.GetType( ).IsArray )
{
ExpandedText = ExpandTypeArrayValuesText_( Object );
}
else if( Convert.GetTypeCode( Object ) == TypeCode.String )
{
ExpandedText = "\"" + Object.ToString( ) + "\"";
}
else if( Convert.GetTypeCode( Object ) == TypeCode.Char )
{
ExpandedText = "'" + Object.ToString( ) + "'";
}
else
{
ExpandedText = Object.ToString( );
}
return ExpandedText;
}
/*
NOTE: ExpandTypeArrayValuesText_ and ExpandTypeArrayValuesTextIfIsOfType_ should only be called from within ExpandTypeValueText.
*/
static string ExpandTypeArrayValuesText_( object Object )
{
bool Validated = false;
string ExpandedText = null;
ExpandTypeArrayValuesTextIfIsOfType_< System.Object >( Object, ref ExpandedText, ref Validated );
ExpandTypeArrayValuesTextIfIsOfType_< System.Char >( Object, ref ExpandedText, ref Validated );
ExpandTypeArrayValuesTextIfIsOfType_< System.String >( Object, ref ExpandedText, ref Validated );
ExpandTypeArrayValuesTextIfIsOfType_< System.Boolean >( Object, ref ExpandedText, ref Validated );
ExpandTypeArrayValuesTextIfIsOfType_< System.Byte >( Object, ref ExpandedText, ref Validated );
ExpandTypeArrayValuesTextIfIsOfType_< System.SByte >( Object, ref ExpandedText, ref Validated );
ExpandTypeArrayValuesTextIfIsOfType_< System.UInt16 >( Object, ref ExpandedText, ref Validated );
ExpandTypeArrayValuesTextIfIsOfType_< System.Int16 >( Object, ref ExpandedText, ref Validated );
ExpandTypeArrayValuesTextIfIsOfType_< System.UInt32 >( Object, ref ExpandedText, ref Validated );
ExpandTypeArrayValuesTextIfIsOfType_< System.Int32 >( Object, ref ExpandedText, ref Validated );
ExpandTypeArrayValuesTextIfIsOfType_< System.UInt64 >( Object, ref ExpandedText, ref Validated );
ExpandTypeArrayValuesTextIfIsOfType_< System.Int64 >( Object, ref ExpandedText, ref Validated );
ExpandTypeArrayValuesTextIfIsOfType_< System.Single >( Object, ref ExpandedText, ref Validated );
ExpandTypeArrayValuesTextIfIsOfType_< System.Double >( Object, ref ExpandedText, ref Validated );
/*
This exception should *never* occur. If it does then there is a bug in the program logic.
*/
if( !Validated )
{
throw new Exception( "Logic error: unsupported type conversion" );
}
return ExpandedText;
}
static void ExpandTypeArrayValuesTextIfIsOfType_< Type >( object Object, ref string ExpandedText, ref bool Validated )
{
if( !Validated )
{
Validated = true;
Type [ ] ArrayOfType = null;
try
{
ArrayOfType = ( Type [ ] )Object;
}
catch( Exception )
{
Validated = false;
}
if( Validated )
{
ExpandedText = "{ ";
for( int Index = 0; Index < ArrayOfType.Length; ++Index )
{
if( Index != 0 )
{
ExpandedText += ", ";
}
ExpandedText += ExpandTypeValueText( ArrayOfType[ Index ] );
}
ExpandedText += " }";
}
}
}
};