O R G A N I C / F E R T I L I Z E R: 04.08

Apr 29, 2008

another blog to add to your long list of news feeds...

in case you haven't heard, microsoft made a couple of announcements about scom at mms.  the first one is about a new beta product called cross platform extensions which lets you manage unix/linux through openwsman, openpegasus (cimom), and ms supplied scom providers.  this is good stuff for painting the heterogeneity picture.

keep up with what they're doing at http://blogs.msdn.com/scxplat/.

Apr 3, 2008

inventory sms advanced client component configuration...

i've read numerous sources about how to disable components of the sms advanced client.  now trying to find which clients have that setting off was another mystery all together.  alas, not totally hidden.  it's exposed in root\ccm\policy\machine\actualconfig.

by the way, did you know you can turn off the inventory agent?  i'm not sure what kind of usefulness could derive from that, but it's there.  if you've turned off the inventory agent, good luck.  this won't help you.  :) 

this is going to require a sms_def.mof change.  fortunately, it doesn't require a client compile so wipe that sweat off your brow and keep reading.

 

i found two ways to do this.  one is what i refer to as the long way (which i was doing when i was trying to figure out how everything worked.)  the other, i will refer to as the short way.  obviously (and just like in real life), the short way is always better.  so first, i present to you ... the short way!

//  *Software Distribution
    #pragma namespace ("\\\\.\\root\\cimv2\\sms")

    [SMS_Report     (TRUE),
    SMS_Group_Name ("SMS Advanced Client Config"),
    Namespace      ("root\\\\ccm\\\\policy\\\\machine\\\\actualconfig"),
    SMS_Class_ID   ("MCO|SMS_CLIENT_CONFIG|1.0") ]

    class CCM_ComponentClientConfig : SMS_Class_Template

    {
    [SMS_Report (TRUE),key  ]    string   ComponentName;
    [SMS_Report (TRUE)      ]    boolean  Enabled;
    };

 

for my environment, componentname and enabled were the only two fields i needed.  it's for this reason that i can utilize the short way approach.  you see, in the short way, i'm drawing from the single class "ccm_componentclientconfig".  (this appears to be some combined class of all the other configuration classes.)  behind the scenes, we're actually performing a wmi query that would look like this:

select componentname, enabled from ccm_componentclientconfig

 

clear?  okay, moving on.  if i wanted to extract other columns from all 5 of the component configuration classes, they would have to match each other or the query would fail.  for instance, one like this would bomb out since cachecontenttimeout only exists in ccm_softwaredistributionclientconfig :

select componentname, enabled, cachecontenttimeout from ccm_componentclientconfig

 

because of this limitation, if you want to draw additional items out, you should consider using the mof below.  note that in the long way mof, the class utilized for each section is different.  i just happened to stumble upon the one up above, otherwise, this is the way i would have gone...

and now, the completely exaggerated, only really, slightly longer (4x as many queries that execute client side though but who cares, ho hum) the long way!

// *Software Distribution #pragma namespace ("\\\\.\\root\\cimv2\\sms") [SMS_Report (TRUE), SMS_Group_Name ("SMS Advanced Client Config"), Namespace ("root\\\\ccm\\\\policy\\\\machine\\\\actualconfig"), SMS_Class_ID ("MCO|SMS_CLIENT_CONFIG|1.0") ] class CCM_SoftwareDistributionClientConfig : SMS_Class_Template { [SMS_Report (TRUE),key ] string ComponentName; [SMS_Report (TRUE) ] boolean Enabled;

[SMS_Report (TRUE)      ]    uint32   CacheContentTimeout;

}; // *Software Metering [SMS_Report (TRUE), SMS_Group_Name ("SMS Advanced Client Config"), Namespace ("root\\\\ccm\\\\policy\\\\machine\\\\actualconfig"), SMS_Class_ID ("MCO|SMS_CLIENT_CONFIG|1.0") ] class CCM_SoftwareMeteringClientConfig : SMS_Class_Template { [SMS_Report (TRUE),key ] string ComponentName; [SMS_Report (TRUE) ] boolean Enabled; }; // *Inventory [SMS_Report (TRUE), SMS_Group_Name ("SMS Advanced Client Config"), Namespace ("root\\\\ccm\\\\policy\\\\machine\\\\actualconfig"), SMS_Class_ID ("MCO|SMS_CLIENT_CONFIG|1.0") ] class CCM_InventoryClientConfig : SMS_Class_Template { [SMS_Report (TRUE),key ] string ComponentName; [SMS_Report (TRUE) ] boolean Enabled; }; // *Remote Tools [SMS_Report (TRUE), SMS_Group_Name ("SMS Advanced Client Config"), Namespace ("root\\\\ccm\\\\policy\\\\machine\\\\actualconfig"), SMS_Class_ID ("MCO|SMS_CLIENT_CONFIG|1.0") ] class CCM_RemoteToolsConfig : SMS_Class_Template { [SMS_Report (TRUE),key ] string ComponentName; [SMS_Report (TRUE) ] boolean Enabled; };

 

notice that the group name and class id stays consistent?  because of that, it flows into the same table.  now look carefully at the section pertaining to CCM_SoftwareDistributionClientConfig.  notice how it has an additional reporting field called "cachecontenttimeout"?  because of this, you'll see additional columns in the output for all the fields.  who cares.  at least you got the data... and in one location!

screenshots below should explain all the mumbling i've been doing.  first, the short way:

image

and once again, the long way.  make note of the column "cachecontenttimeout".

image

and that is that.

searching for records in dns...

yes, you may remember a similar post for enumerating dns ptr records with dnscmd.  this is basically the same thing.  except in this scenario, we're going to use findstr to help locate the records we want.

 

dnscmd myDnsServer /enumrecords myZone.myRoot.com . /continue | findstr crap

crap 3600 A     192.168.1.220
myCrap 3600 A     192.168.1.221
 

 

well, look at that.  that was easy.  we enumerate all records in any given zone, then specify the /continue switch to search all records.  the "." will tell it to pull back everything... and piping through findstr looks for any record with the word "crap" in it.

 
 

you can take it one step further and search all zones.  check out the following example:

 

for /f %a in ('dnscmd myDnsServer /enumzones ^| findstr /i primary') do dnscmd myDnsServer /enumrecords %a . /continue | findstr /i crap

crap 3600 A      192.168.1.220
crap2 [Aging:3569875] 1200 A     192.168.1.143
crap3 [Aging:3569899] 1200 A  192.168.1.142
crap4 [Aging:3569751] 1200 A    192.168.1.136
myCrap 3600 A     192.168.1.221
 
 
the real difference is that this time, we utilized a for loop to run dnscmd first to enumerate all the zones pulling back only the primary zones (easiest way for this example).  since we have them captured in a token, we loop through searching every zone for the name in question.

Apr 1, 2008

how to retrieve your ip address with powershell...

update: this is how it’s performed in powershell v3 as demonstrated here.

(get-netadapter | get-netipaddress | ? addressfamily -eq 'IPv4').ipaddress

 

update: this is by far the easiest.

PS C:\temp> (gwmi Win32_NetworkAdapterConfiguration | ? { $_.IPAddress -ne $null }).ipaddress
192.168.1.101

 

 

are you laughing yet?  i know you probably find this topic amusing.  it's really interesting though.  whenever you get over it, i'll do this in the standard cmd.exe interpreter and then in powershell to show you what kind of coolness powershell does.

done?  okay, good.  this is an interpretation of a demo that bob wells did at our smug meeting.  hope you like it.

i should tell you, it's not as simple as the title would lead you to believe.  i like doing that little slight-of-hand thing since it gives the impression that i'm painting a very easy target on my back for your criticism (though it's probably true in other ways)!  the idea is that we want to retrieve just the ip address.  so here we go...

first of all, let's see how you'd get an ip address out of ipconfig.  since i can't get bob's method of regular expression to work, i created my own for this simple, little demo.  following is a series of commands and results to get to the final product. 

to start with, let's get the results of ipconfig and use findstr to pull out any lines that look like an ip address:

C:\temp>ipconfig | findstr [0-9].\.

   IPv4 Address. . . . . . . . . . . : 192.168.1.101
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . : 192.168.1.1


alrighty, now we have a preliminary list of the addresses we want to use.  problem is, we need to strip it down to only the ip address, getting rid of the subnet mask and default gateway.  we can achieve this by passing the echoed statement back through findstr looking for the word address.  something like this:
C:\temp>for /f "delims=" %a in ('ipconfig ^| findstr [0-9].\.') do @echo %a | findstr "Address"

   IPv4 Address. . . . . . . . . . . : 192.168.1.101


so far, so good.  now let's get the ip address only.  we take the stuff from before and use it to the for command again to split everything with the delimiter ":", which gives us two tokens.  echoing the second one, we get the ip address:
C:\temp>for /f "delims=" %a in ('ipconfig ^| findstr [0-9].\.') do @for /f "tokens=1,2 delims=:" %i in ('@echo %a ^| findstr "Address"') do @echo %j

 192.168.1.101



ah crap!  see that?  there's a space we have to deal with!  to get rid of it, we'll pass it yet again through a for loop.  you see, the default delimiter of a for loop command is space and tab.  when we pass it back through, we just echo it back:

C:\temp>for /f "delims=" %a in ('ipconfig ^| findstr [0-9].\.') do @for /f "tokens=1,2 delims=:" %i in ('@echo %a ^| findstr "Address"') do @for /f %o in ('@echo %j') do @echo %o

192.168.1.101

 

and finally... we arrive at the results we were hoping for.  finally.

 

okay, let's do the same thing in powershell this time.  maybe we'll find it a little easier...

PS C:\temp> ipconfig | findstr [0-9].\.

   IPv4 Address. . . . . . . . . . . : 192.168.1.101
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . : 192.168.1.1

 

so far the results look about the same.  unlike cmd.exe we're not just pushing around text.  in this case, the data is coming back as a string object.  when we run this through powershell, we can actually pull stuff out based on the index of the array.  since we know address is first, we can just call 0 like this:

PS C:\temp> (ipconfig | findstr [0-9].\.)[0]

   IPv4 Address. . . . . . . . . . . : 192.168.1.101

 

hmmm.  that was easy, but we're not done yet.  from here, we need to just retrieve the ip address.  the easiest way to do this is to split the contents (truncated it):

PS C:\temp> ((ipconfig | findstr [0-9].\.)[0]).Split()

IPv4
Address.
.
.
.
:
192.168.1.101

 

output is pretty ugly in that format, isn't it?  luckily, all we need is the last value.  just as 0 is the index which indicates the first member of an array, we can use -1 to indicate the very last one.  in this case, the split function moves the ip address to the very end.  now we can capture that array member and bring it back.  check it out:

PS C:\temp> ((ipconfig | findstr [0-9].\.)[0]).Split()[-1]

192.168.1.101

 

isn't that cool?

 

here's a couple of other things that bob demonstrated.  i'm sure you can figure them out on your own though.  no point in be boring you with my narrative:

[MATH]::Round(((Get-WmiObject win32_computersystem).totalphysicalmemory / 1gb),2)

foreach($file in Get-ChildItem){$size =+ $file.length}