Skip to main content

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

Comments

  1. This script looks EXTREMELY useful, but you left no instructions on how to run it. Any way I try I get errors.

    ReplyDelete
  2. I changed the two parts that you indicate need to be changed, but it still doesn't work. Does it make a difference if our SMS server uses port 800 instead of port 80?

    ReplyDelete
  3. what's the error you're getting rilian?

    ReplyDelete
  4. Great script.. saved me a bunch of time.. now I don't have to create my own.. .. thanks again.

    lbrown

    ReplyDelete
  5. it's specified in the script itself, but i should point that that you'll need to set the "siteserver" and "reportingurl" to your environment. "siteserver" is the name of your sms server. the "reportingurl" is generally the something like smsreporting_xyz where xyz is the site code.

    ReplyDelete
  6. Hi there,

    This looks great; however when I run it I get the following error message come up:

    "showadverts.vbs(77, 1) Microsoft VBScript runtime error: Subscript out of range: 'UBound'"

    What am I doing wrong please?

    ReplyDelete
  7. james - did you set these fields?

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


    if so, either you do not have access under the account you're using or the values are incorrect. the error you're stating sounds like it wasn't able to pull the ads from your sms server to go through them.

    ReplyDelete
  8. @rillian - realized i never answered your question. if your port is different, i would set the following values like this, in your case:

    siteserver = "mysmsserver"
    reportingurl = "smsreporting_xyz:800"

    ReplyDelete
  9. Hi there,

    Yeah - I did modify those two entries.

    In the end, to get it to work, we had to modify the script. We put an "on error resume next" into the script so that it would carry on.

    It seems that it's a problem that is unique to our environment.

    Cheers anyway and thanks for the script since it's helped enormously!

    ReplyDelete
  10. hey rob - i bet you have an orphaned object of some type. adding on error resume next is probably helping it skip the errored object and move on to the next available.

    glad it's working though!

    ReplyDelete
  11. This comment has been removed by a blog administrator.

    ReplyDelete

Post a Comment

Popular posts from this blog

using preloadpkgonsite.exe to stage compressed copies to child site distribution points

UPDATE: john marcum sent me a kind email to let me know about a problem he ran into with preloadpkgonsite.exe in the new SCCM Toolkit V2 where under certain conditions, packages will not uncompress.  if you are using the v2 toolkit, PLEASE read this blog post before proceeding.   here’s a scenario that came up on the mssms@lists.myitforum.com mailing list. when confronted with a situation of large packages and wan links, it’s generally best to get the data to the other location without going over the wire. in this case, 75gb. :/ the “how” you get the files there is really not the most important thing to worry about. once they’re there and moved to the appropriate location, preloadpkgonsite.exe is required to install the compressed source files. once done, a status message goes back to the parent server which should stop the upstream server from copying the package source files over the wan to the child site. anyway, if it’s a relatively small amount of packages, you can

How to Identify Applications Using Your Domain Controller

Problem Everyone has been through it. We've all had to retire or replace a domain controller at some point in our checkered collective experiences. While AD provides very intelligent high availability, some applications are just plain dumb. They do not observe site awareness or participate in locating a domain controller. All they want is the name or IP of one domain controller which gets hardcoded in a configuration file somewhere, deeply embedded in some file folder or setting that you are never going to find. How do you look at a DC and decide which applications might be doing it? Packet trace? Logs? Shut it down and wait for screaming? It seems very tedious and nearly impossible. Potential Solution Obviously I wouldn't even bother posting this if I hadn't run across something interesting. :) I ran across something in draftcalled Domain Controller Isolation. Since it's in draft, I don't know that it's published yet. HOWEVER, the concept is based off

sccm: content hash fails to match

back in 2008, I wrote up a little thing about how distribution manager fails to send a package to a distribution point . even though a lot of what I wrote that for was the failure of packages to get delivered to child sites, the result was pretty much the same. when the client tries to run the advertisement with an old package, the result was a failure because of content mismatch. I went through an ordeal recently capturing these exact kinds of failures and corrected quite a number of problems with these packages. the resulting blog post is my effort to capture how these problems were resolved. if nothing else, it's a basic checklist of things you can use.   DETECTION status messages take a look at your status messages. this has to be the easiest way to determine where these problems exist. unfortunately, it requires that a client is already experiencing problems. there are client logs you can examine as well such as cas, but I wasn't even sure I was going to have enough m