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

Jan 16, 2008

misc: testing microsoft products...

if you find it cumbersome to build up a total environment just to test products, you can find canned vms for limited use at the microsoft site "run it on a virtual hard disk."  fyi - if you want to extend it from a 30-day trial to a 500-day trial, you'll need your technet subscriber id.

Jan 9, 2008

sms: distribution manager fails to send a package to a distribution point...

just a couple of links to some ways to address this. i find this crops up either occasionally on some of our servers, especially when concerning large packages like security updates. it happens during migration to new hardware occasionally, too. this is the typical error you'll receive:

Package XYZ00234 requires a newer version (3) of source files and the new compressed files haven't arrived yet, current version is 2, skip E:\SMS\inboxes\distmgr.box\INCOMING\Z3AWAX9I.PKG

multiple things you want to look at if you're running into this error:

this a really quick rundown on a way to get things moving. i don't suggest doing this unless you've exhausted the methods above outlined in the first 3 bullets. the dx21 method is the one i'm outlining here for reference. read it in full before you try this to understand what kind of unsupported position you will be putting yourself in.

to begin with, run this package status query:

SELECT * FROM PkgStatus WHERE Type=1 AND Status=1 AND ID='XYZ00234'
most likely, you'll get back a list of the distribution points where you're having a problem with the package. it should look like the following:
ID Type SiteCode PkgServer Personality Status SourceVersion UpdateTime Location ShareName HTTPUrl
XYZ00234 1 XYZ SMSServer1 0 1 93 2008-01-01
to give this a kick in the rear, run this next statement to reset the delta replication value by changing the status to 2 and changing the sourceversion to 0:
UPDATE PkgStatus SET Status=2, SourceVersion=0
WHERE (ID='XYZ00234') AND (TYPE=1) AND (PkgServer='SMSServer1')

and now it should look like this:

ID Type SiteCode PkgServer Personality Status SourceVersion UpdateTime Location ShareName HTTPUrl
XYZ00234 1 XYZ SMSServer1 0 2 0 2008-01-01

if you want to track the progress of a distribution, use the query below.

declare @ver int
declare @pkgid nvarchar(8)

set @pkgid = 'XYZ00234'

select    @ver=MAX(SourceVersion)
from    v_PackageStatusRootSummarizer
where    PackageID = @pkgid

create table #PkgProgress (RecordID int not null, Time datetime not null, SiteCode char(3) not null, PctComplete int not null, MessageID int not null, PRIMARY KEY(SiteCode,Time,RecordID))
insert into #PkgProgress(RecordID,Time,SiteCode,PctComplete,MessageID)

select    msg.RecordID, msg.Time, insSC.InsStrValue as SiteCode, IsNULL(insPC.InsStrValue,100)
       as PctComplete, msg.MessageID
from    v_StatusMessage msg
       join v_StatMsgAttributes att on msg.RecordID=att.RecordID
       and msg.Time=att.AttributeTime
       join v_StatMsgInsStrings insVER on msg.RecordID=insVER.RecordID
       and insVER.InsStrIndex=1
       join v_StatMsgInsStrings insSC on msg.RecordID=insSC.RecordID
       and insSC.InsStrIndex=2
       left join v_StatMsgInsStrings insPC on msg.RecordID=insPC.RecordID
       and insPC.InsStrIndex=3
where    MessageID in (3531,3532,3533)
       and Component in
           ('SMS_ASYNC_RAS_SENDER','SMS_ISDN_RAS_SENDER', 'SMS_LAN_SENDER',
            'SMS_SNA_RAS_SENDER', 'SMS_X25_RAS_SENDER','SMS_WINSOCK_SENDER')
       and att.AttributeID=400
       and att.AttributeValue= @pkgid
       and insVER.InsStrValue=CONVERT(varchar(10),@ver)

select    Sites.SiteCode, prog.Time, prog.MessageID, prog.PctComplete as 'Sending % Complete',
       Sites.Targeted as 'DPs Targeted', 100*Sites.Installed/Sites.Targeted as '% DPs Complete'
from    v_PackageStatusDetailSumm Sites left join (#PkgProgress prog join
       (select SiteCode, MAX(Time) as MaxTime
        from #PkgProgress group by SiteCode)
        as LastProg on prog.Time=LastProg.MaxTime and prog.SiteCode=LastProg.SiteCode)
        on Sites.SiteCode=prog.SiteCode
where    Sites.PackageID = @pkgid and Sites.Targeted>0
order by prog.SiteCode

drop table #PkgProgress

ds: properly changing the srv priority for your domain controllers...

follow this kb article and note the special instructions for windows server 2003.  it specifies "to configure windows server 2003-based domain controllers, use the net logon service group policy "priority set in the domain controller locator dns srv records". 

  • launch the local policy editor by using gpedit.msc
  • drop down administrative templates
  • navigate to system/net logon/dc locator dns records
  • enable the setting "priority set in the dc locator dns srv records"
  • adjust priority to proper value
crap

Jan 4, 2008

mom: receiving alerts for all servers ... with exceptions!

this is cool enough to blog about (which translates to "do not want to forget this later").  in a previous post a long while back, i wrote up a short summary of how to setup an alert rule to receive all notifications for a specified computer group.  let's take that one step further, shall we?

why do this?  imagine this scenario.  you're a domain administrator.  you decided to setup the alert rule specified above and tied it to your domain controllers computer group.  now you're receiving all the alerts for your domain controllers, just like you wanted.  and just like real life ... everything is going along happily until one day someone asks you to do something for them.  this time, they want a notification for security group changes.  not a problem!  you use a helpful little blog post like this to accomplish something pretty close to it.  (by the way, if you are doing this, just use parameter 3 for the group name.)

oh to your chagrin, your inbox fills up with monitoring alerts that you don't really care to see.  since you've got the master alert rule bound to your domain controllers, though, there doesn't seem to be a way out.

 

or is there?  here's how i resolved it.  i made two small modifications to both rules:

 

on the security event notification rule:

  • switch to the alert tab.
  • click the "custom fields..." button.
  • specify a value for customfield1.

crap

on the master alert rule:

  • switch to the alert criteria tab.
  • click the "advanced..." button.
  • choose field "custom field 1", set condition to "not equals" and the value matching what you specified above.

crap[4]

 

with that set, now you will stop receiving all those nagging notifications about other people's group changes.  hope that helps!

mom: correcting a most troublesome mom 2005 agent...

after a long holiday, the first thing i want to do is jump right into disciplining a bad agent.  i wish i could say it was something really painful to lament over.  unfortunately, it wasn't.  nor exciting.  it was like a cockroach: elusive and slippery.  i couldn't make it go away.  this is probably the third time that various corrective actions were done against this server.

it seems the real issue was wmi corruption.  i have no idea what caused it or how it happened.  i suppose as far as wmi goes it's always a mystery.  anyway, it started off that way.  didn't quite end that way.  some of the errors i was seeing:

The response processor failed to execute a response.  The response returned the error message: The remote procedure call failed.

Response Details:

Rule ID:  {E8665A8F-17B6-4C7C-BA62-CAC4E33C13CD}
Response description: script: AD CPU Overload

The response 'script: AD CPU Overload' has been running more than 300 seconds and exceeded the time allowed to run.
This might indicate the response is engaged in an infinite loop or is hanging.


An error occurred on line 250 while executing script 'Microsoft Windows File Server SMB counters calculation'
Source: SWbemRefresher
Description: Invalid class 

 

and now... the things i did to fix it:

  1. repair wmi:
    • Rundll32 wbemupgd, CheckWMISetup
    • Rundll32 wbemupgd, RepairWMISetup
  2. register all wmi components:
    • cd /d %windir%\system32\wbem
    • for %i in (*.dll) do RegSvr32 -s %i
    • for %i in (*.exe) do %i /RegServer
  3. resync wmi performance counters:
    • winmgmt /clearadap
    • winmgmt /resyncperf
  4. recompile all mofs:
    • cd /d %windir%\system32\wbem
    • for /r %i in (*.mof *.mfl) do mofcomp %i
  5. reinstall the mom agent (just to make sure all components are placed back into wmi correctly)

 

after running all of the above steps, i still encountered mom errors where script executions continued to fail.  the next step is a bit unusual because everything in the environment suggests that it doesn't need to be done.  i verified that we were running at least patch 11 (which supposedly addresses this issue) as noted in this article.  since it still continued to fail, i checked out the scriptscan settings to verify that it was turned off.  after verifying both of those things, i decided... what the hell?  i'll just unregister it.  so i did...

 

  1. unregister mcafee 8.0i scriptproxy.dll:
  • cd /d %programfiles%\network associates\virusscan
  • regsvr32 –u scriptproxy.dll

 

and now... it finally works.

Jan 2, 2008

sms: decoding advertflags for "asap"

before i start writing this, let me give some credit to robert mahle for getting me some information confirming stuff in this post. we've been working a bit (har har, no pun intended) trying to figure out how to decode the value of "asap" from the sms admin console into a spreadsheet. before i move too far ahead, some background for you...

in this previous post about displaying advertisement info via a script, we ran into some confusion trying to decode the advertflags value. trying to get "asap" to show up just wasn't happening. the real confusion about this is "asap" is not treated like other schedule data that you'd find by looking for the sms_scheduletoken data type. usually it's held under assignedschedule. despite the fact that "asap" shows up in the sms admin console as a schedule, it's held under advertflags. the sdk confirms this:

AdvertFlags
  Data type: uint32
  Access type: Read/write
  Qualifiers: Bits
  When to announce the advertisement to the user. These bit flags must be coordinated with the
  bit flags specified in the ProgramFlags property of the advertised program. For example, if
  you set ONUSERLOGOFF, the NOUSERLOGGEDIN flag in the program must be set. If the flag
  settings do not match, the program will not be advertised.
 
  The default value is 0.
 
  Bit flags are as follows:
 
  IMMEDIATE (bit 5)
  ONSYSTEMSTARTUP (bit 8)
  ONUSERLOGON (bit 9)
  ONUSERLOGOFF (bit 10)
  NO_DISPLAY (bit 25)
  ONSLOWNET (bit 26)

in order to decode advertflags, you have to have a little bit of understanding regarding how bit flags work. don't worry; we'll get into all that in a second. you know, as long as we're covering "asap" stuff, i suppose we'll use that in our example.

alright, the first thing to do would be to create a little script that will dump out all of your advertisements that are set to "asap." don't sweat it. no coding required. here's a little something you can use. it's from the book sms 2003 recipes: a problem-solution approach. i modified it a little bit for the decoding work we'll be doing.

strSMSServer = "mySMSServer"

Set objLoc =  CreateObject("WbemScripting.SWbemLocator")
Set objSMS= objLoc.ConnectServer(strSMSServer, "root\sms")
Set Results = objSMS.ExecQuery("SELECT * From SMS_ProviderLocation WHERE ProviderForLocalSite = true")
For each Loc in Results
 If Loc.ProviderForLocalSite = True Then
     Set objSMS = objLoc.ConnectServer(Loc.Machine, "root\sms\site_" & Loc.SiteCode)
         strSMSSiteCode = Loc.Sitecode
 End If
Next

Set colAdverts = objSMS.ExecQuery("Select * From SMS_Advertisement order by AdvertisementName")
For Each objAdvert In colAdverts
 if (objadvert.advertflags AND 2^5) then
     wscript.echo objAdvert.AdvertisementName & " ------- " & objAdvert.AdvertFlags
 end if
Next

if i run this script in my environment, i'd get output like the following... (i've changed the names around in case you thought we ran apps from a company called some).

C:\temp>cscript smsadvertisement.vbs
Microsoft (R) Windows Script Host Version 5.7
Copyright (C) Microsoft Corporation. All rights reserved.

Some Custom Screensaver ------- 33554464
Some Antivirus App ------- 33554464
Some Email Disaster Recovery Analyzer ------- 33554464
Some Monitoring Agent ------- 33554464
Some Zip Utility 9.0 ------- 33554464
Some Webby App ------- 33554464

the value following the ------- is the value of advertflags. in my environment, all of these advertisements contain the same value for me (may not be the case for you). i'm going to use the first one called "some custom screensaver." the value, obviously for this one is 33554464. as a reminder...

bit 1bit 2result
000
100
010
111

when using AND as a bitwise operator, this is basically what occurs: as you can see, anything with both comparison bits set to 1 will result in 1. otherwise, you get 0. hold on to that... if you look at the script above, we perform a bitwise AND operation. it happens right here:

if (objadvert.advertflags AND 2^5) then
  wscript.echo objAdvert.AdvertisementName & " ------- " & objAdvert.AdvertFlags
end if

okay, real quick math lesson: 2 to the 5th is ... ? that's right, 32. keep that magic value in your head. it's easier to do it this way because in the sdk, it specifies it's the 5th value. instead of multiplying 2*2*2*2*2, we just raise it to the power of the 5. the 5th bit is "immediate" otherwise known as "asap". take the value you're working with and put it in your calculator as a decimal value. now, click the "bin" radio button. you'll see that the value of 33554464 is converted to 10000000000000000000100000. now, do the same thing for 32 (or 2^5). you'll get 100000. just to make it easier to understand visually, i added leading zeroes, getting this: 00000000000000000000100000. now stack them together:

10000000000000000000100000
00000000000000000000100000
--------------------------
00000000000000000000100000

remember above when i told you that both comparison bits have to be 1 in order for the result bit to be 1? well, look at that. we only have a single place that it occurs.

ANDing the values together gives you a value of 32. (if you don't believe me, paste 100000 into your calculator as a hex value and convert it to dec.) the if/then script statement above is doing this for you.by the way, since you're only checking for one value, the result being greater than 0 is a successful return. technically you could write it as:
if (objadvert.advertflags AND 2^5) > 0 then
  wscript.echo objAdvert.AdvertisementName & " ------- " & objAdvert.AdvertFlags
end if
but you get the idea. since we know the value we return is 32, which is greater than 0, then it successfully found the 5th bit to be turned on. you could also set it to = 2^5 instead.

sms: script to display advertisement information...

we've been frustrated for awhile by the lack of flexibility in the admin console. particularly, i'm referring to the advertisement view. if you're trying to figure out additional details beyond "available after", "expires after", and "status" you won't be able to do it through the gui. i won't lie and say you can't get this information at all. you could... i mean, you could open every advertisement and look at the schedule. that would only take a few minutes right? while you're doing that, i'm going to get more coffee.

alright, back. awake now. frustration has got to be the mother of scripting. :) seems like that's the only time we choose to go that route... and so frustration birthed a new script to help us along. basically a coworker wrote one up that would detail all advertisements and all additional information that you would normally want to know and presents the data in a spreadsheet.

so what kind of stuff would frustrated sms admins like to see anyway? here's our pick: advertisement id, name, start time, mandatory time, expiration time, target collection, and # of clients.

we thought # of clients would be particularly helpful in determining which collections are still used. as an example, you set an advertisement with a single mandatory start time (no recurrence) and point it to a collection of clients. this collection uses a query which would continue to remove clients as they no longer met the criteria, right? let's say the advertisement has been out there for a month. glancing at the spreadsheet, you see 3 clients. so out of whatever value you started at, you get down to 3... seems pretty successful. you check out those 3... they're no longer active. you can get lost trying to figure out which advertisements are no longer required, jumping back and forth from the collection to the ad. now you'll know pretty quickly.

advertisement id and target collection, we realize are visible and available to view in the console. however, in the spreadsheet, these values are actually hyperlinks to a web report with that information. the expiration time column also highlights the advertisements that have an expiration end time that has already been exceeded. why leave that crap around forever? :) anyway, here's an example of what you'd see...

crap

and... here's the script if you want to try it out:

'Define variable and constants
IMMEDIATE = 2^(5)

Dim objAdvertisement
Dim smsadvertisementid()
Dim siteserver
Dim reportingurl
Dim sitecode
Dim starttime
Dim mandatorytime()
Dim adName
Dim adID
Dim expiretime
Dim collection
Dim program
Dim adlisting()
Dim a_adID()
Dim a_starttime()
Dim a_mandatorytime()
Dim a_expiretime()
Dim a_collcount()
Dim a_program()
adlistingcounter=0

siteserver = "mysmsserver" '<--------------------------------------Add your site server name here
reportingurl = "smsreporting_xyz" '<-------------------------------Revise to point to your reporting URL

'Error trapping in case a site server is not specified
If siteserver = "" Then
WScript.Echo "You have not specified a site server. Please define the siteserver variable within the script. Exiting."
WScript.Quit
End If

'Attach to SMS WMI on site server

Set ProviderLoc = GetObject _
   ("winmgmts:{impersonationLevel=impersonate}!\\" & siteserver & "\root\sms:SMS_ProviderLocation")

If Err.Number<>0 Then
   Wscript.Echo "Couldn't get SMS Provider"
   Wscript.Quit
End If

'Determine namespace

WScript.Echo "Determining WMI namespace..."

For Each Location In ProviderLoc.Instances_
    If Location.ProviderForLocalSite = True Then
    WScript.Echo "NAMESPACE=" & Location.NamespacePath
       Set objSWbemServices = GetObject("winmgmts:" & Location.NamespacePath)
       Exit For
  End If
Next

'Get ads
Set colAdvertisements = objSWbemServices.ExecQuery( "Select * From SMS_Advertisement")

adcounter = 0
for Each oAdvertisement In colAdvertisements
ReDim Preserve smsadvertisementid(adcounter)
smsadvertisementid(adcounter)= oAdvertisement.Advertisementid
adcounter=adcounter+1
Next

adcounter = adcounter -1

WScript.Echo "There are " & adcounter & " advertisements in place on " & siteserver & "."




'Put ad info into arrays

For displaycounter = 0 To UBound (smsadvertisementid)
getadproperties (smsadvertisementid(displaycounter))
For a = 0 To UBound (mandatorytime)
ReDim Preserve a_adID (adlistingcounter)
a_adID (adlistingcounter)= adID
ReDim Preserve a_adName (adlistingcounter)
a_adName (adlistingcounter)= adName
ReDim Preserve a_collection (adlistingcounter)
a_collection (adlistingcounter)= collection
ReDim Preserve a_collcount (adlistingcounter)
a_collcount (adlistingcounter) = getcollcount (collection)
ReDim Preserve a_starttime (adlistingcounter)
a_starttime (adlistingcounter) = starttime
ReDim Preserve a_mandatorytime (adlistingcounter)
a_mandatorytime (adlistingcounter) = mandatorytime (a)
ReDim Preserve a_expiretime (adlistingcounter)
a_expiretime (adlistingcounter) = expiretime
ReDim Preserve a_program (adlistingcounter)
a_program (adlistingcounter) = program
adlistingcounter = adlistingcounter+1

Next

Next

adlistingcounter = adlistingcounter-1



'Build Spreadsheet from arrays

WScript.Echo "Adding data to spreadsheet..."
rowval = 2
colval=0
Set objExcel = CreateObject("Excel.Application")

objExcel.Visible = True
objExcel.Workbooks.Add
objExcel.Cells(1, 1).Value = "Advertisement ID"
objExcel.Cells(1, 2).Value = "Name"
objExcel.Cells(1, 3).Value = "Start Time"
objExcel.Cells(1, 4).Value = "Mandatory Time"
objExcel.Cells(1, 5).Value = "Expiration Time"
objExcel.Cells(1, 6).Value = "Target Collection"
objExcel.Cells(1, 7).Value = "Clients"


Set objRange = objExcel.Range("A1","G1")
objRange.Font.Bold = True

For excelcounter = 0 To adlistingcounter
objExcel.Cells(rowval, 1).Value = a_adID(excelcounter)
objExcel.Workbooks(1).Worksheets(1).Hyperlinks.Add _
   objExcel.Cells(rowval, 1), "http://" & siteserver & "/" & reportingurl & "/Report.asp?ReportID=111&AdvertID=" & a_adID(excelcounter)
objExcel.Cells(rowval, 2).Value = a_adName(excelcounter)
objExcel.Cells(rowval, 3).Value = a_starttime(excelcounter)
objExcel.Cells(rowval, 4).Value = a_mandatorytime(excelcounter)
objExcel.Cells(rowval, 5).Value = a_expiretime(excelcounter)
objExcel.Cells(rowval, 6).Value = a_collection(excelcounter)
objExcel.Workbooks(1).Worksheets(1).Hyperlinks.Add _
objExcel.Cells(rowval, 6), "http://" & siteserver & "/" & reportingurl & "/Report.asp?ReportID=135&ID=" & a_collection(excelcounter)
objExcel.Cells(rowval, 7).Value = a_collcount(excelcounter)


If a_expiretime(excelcounter)<> "Never" Then
   If DateDiff ("n",a_expiretime(excelcounter),Now) > 1 Then
   Set objRange = objExcel.Cells(rowval, 5)
   objRange.Interior.ColorIndex = 36


  
   End If
End If
rowval = rowval+1
Next

objExcel.Cells(1, 1).EntireColumn.AutoFit()
objExcel.Cells(1, 2).EntireColumn.AutoFit()
objExcel.Cells(1, 3).EntireColumn.AutoFit()
objExcel.Cells(1, 4).EntireColumn.AutoFit()
objExcel.Cells(1, 5).EntireColumn.AutoFit()
objExcel.Cells(1, 6).EntireColumn.AutoFit()
objExcel.Cells(1, 7).EntireColumn.AutoFit()

WScript.Echo "Done!"


Function getadproperties (advID)
adID=advID
WScript.Echo "Retrieving properties of advertisement " & advid

Set objAdvertisement = GetObject _
   ("WinMgmts:" & Location.NamespacePath & ":SMS_Advertisement.AdvertisementID='" & advID & "'")


starttime = WMIDateStringToDate (objAdvertisement.presenttime)
adName = objAdvertisement.AdvertisementName
ExpirationTimeEnabled = objAdvertisement.ExpirationTimeEnabled
collection = objAdvertisement.collectionid
program = objAdvertisement.programname
If Not ExpirationTimeEnabled Then
expiretime="Never"
Else
expiretime=WMIDateStringToDate (objAdvertisement.ExpirationTime)
End If


intAdvertFlags = objAdvertisement.AdvertFlags








ExpirationTimeEnabled = objAdvertisement.ExpirationTimeEnabled
timecounter = 0
for each objSched In objadvertisement.assignedschedule
select Case objSched.Path_.Class

        Case "SMS_ST_NonRecurring"

           strInfo =  "Non-Recurring Assignment: "

           strInfo = strInfo & "Occurs at " & WMIDateStringToDate (objSched.StartTime)

           if objSched.IsGMT Then

               strInfo = strInfo & " GMT"

           end If

          

       case "SMS_ST_RecurInterval"

           strInfo = "Recurring Interval Assignment: "

           strInfo = strInfo & "Every " & objSched.DaySpan & " days, " & objSched.MinuteSpan & " minutes, "

           strInfo = strInfo & "beginning on " & WMIDateStringToDate(objSched.StartTime)

           if objSched.IsGMT then

               strInfo = strInfo & " GMT"

           end if     

      

       case "SMS_ST_RecurMonthlyByDate"

           strInfo = "Recurring Monthly By Date: "

           strInfo = strInfo & "Occurs on the " & objSched.MonthDay & " day, every " & objSched.ForNumberOfMonths & " months, "

           strInfo = strInfo & "beginning on " & WMIDateStringToDate(objSched.StartTime)

           if objSched.IsGMT Then

               strInfo = strInfo & " GMT"

           end if         

      

       case "SMS_ST_RecurMonthlyByWeekday"

           strInfo = "Recurring Monthly By Weekday: "

           strInfo = strInfo & "Occurs on the " & objSched.Day & " day, every " & objSched.ForNumberOfMonths & " months, " & "for week order " & objSched.WeekOrder & ","

           strInfo = strInfo & "beginning on " & WMIDateStringToDate(objSched.StartTime)

           if objSched.IsGMT Then

               strInfo = strInfo & " GMT"

           end if             

      

       Case "SMS_ST_RecurWeekly"

           strInfo =  "Recurring Monthly By Weekday: "

           strInfo = strInfo & "Occurs on the " & objSched.Day & " day, every " & objSched.ForNumberOfWeeks & " weeks, "

           strInfo = strInfo & "beginning on " &  WMIDateStringToDate(objSched.StartTime)

           if objSched.IsGMT Then

               strInfo = strInfo & " GMT"

           end if             
      
       Case Else
      
                   strInfo =  "Unable to retrieve mandatory time"
              

   End Select
  

ReDim Preserve mandatorytime (timecounter)
mandatorytime(timecounter) = strinfo
timecounter = timecounter +1
Next
If timecounter = 0 Then
strinfo = "No assignment"
      

End if
If (intAdvertFlags And IMMEDIATE) Then
  
strInfo = "As soon as possible"
ReDim Preserve mandatorytime (timecounter)
mandatorytime(timecounter) = strinfo
End If








End Function

Function WMIDateStringToDate(dtmInstallDate)
WMIDateStringToDate = CDate(Mid(dtmInstallDate, 5, 2) & "/" & Mid(dtmInstallDate, 7, 2) & "/" & Left(dtmInstallDate, 4) & " " & Mid (dtmInstallDate, 9, 2) & ":" & Mid(dtmInstallDate, 11, 2) & ":" & Mid(dtmInstallDate, 13, 2))

End Function




Function getcollcount (collid)
num_clients = 0
Set colQueryCollectionResults=objSWbemServices.ExecQuery _
   ("SELECT Count (Name) FROM SMS_FullCollectionMembership WHERE CollectionID='" & collid & "'")

For Each objResult In colQueryCollectionResults
   
getcollcount = objresult.count   
Next


End Function