When you are waiting for a package to arrive and process at a workstation, this script will notify you when the Referenced CacheElements count changes.
With no parameters, it just displays the current information, plus an extensive summary of the cache details.
Parameter: WAIT will wait until one change and then exit
Parameter: WATCH will keep displaying as changes occur without exiting.
Features:
- It will relaunch itself if it finds it’s running as a WSCRIPT program instead of the desired CSCRIPT program.
- It shows the numbers using a big display font, for easy-to-see changes
- Works on remote machines
[VBScript code] ' Script to monitor arrival of a package into the cache, etc ' Author: Roger C ' Strategy: Read the list of REFERENCED classic packages from the cache ' Also read the list of files, so we cna detect if files come or go ' repeatedly check the cache, and trigger when the item count changes Option Explicit forceCScriptExecution ' avoid running as a wscript, which shows popup message boxes '====================================================================== '---[ Define variables '====================================================================== Dim service Dim oUIResManager Dim oCache Dim oCacheElement Dim oCacheElements, oPrograms Dim strWMIClass, oWMI Dim strQuery Dim NextAvailableID Dim ColItems Dim CurrentElementCount, CurrentReferenceCount, CurrentProgramsCount Dim objItem Dim arrCurrentFilenames(0), arrPreviousFilenames() dim OldElementCount, OldReferenceCount Dim i Dim Version : Version = "2.0.0.0" Dim arg() Dim HostName: Hostname = "" Dim Verbose : Verbose=False Dim WATCH: WATCH = False Dim WAIT: WAIT = False Dim Verb : Verb = "Details for " DIM RelaunchedAsCscript : RelaunchedAsCscript = False '====================================================================== '---[ Initial processing of arguments '====================================================================== reDim arg(wscript.arguments.count) for i = 0 to wscript.arguments.count - 1 arg(i) = ucase(wscript.arguments(i)) if instr(arg(i),"HOST:") then HostName = Mid(arg(i),instr(arg(i),"HOST:") + 5) end if if instr(arg(i),"HOSTNAME:") then HostName = Mid(arg(i),instr(arg(i),"HOSTNAME:") + 9) end if if arg(i)="VERBOSE" or arg(i)="-VERBOSE" or arg(i)="/VERBOSE" then Verbose=True end if if arg(i)="WATCH" or arg(i)="-WATCH" or arg(i)="/WATCH" then WATCH=True end if if arg(i)="WAIT" or arg(i)="-WAIT" or arg(i)="/WAIT" then WAIT=True end if if arg(i)="RELAUNCHED" then RelaunchedAsCscript = true end if if arg(i)="/?" or arg(i)="-?" or arg(i)="/HELP" or arg(i)="-HELP" or arg(i)="HELP" then wscript.echo left(wscript.ScriptName,len(wscript.ScriptName)-4) & "[v." & Version & "]" wscript.echo "Displays information about and monitors changes to the the SCCM cache" & vbcrlf wscript.echo "Parameters:" wscript.echo " HOST : Name/IP of the remote host to monitor" wscript.echo " WAIT : Wait for the referenced cache items to change once" wscript.echo " WATCH : Wait forever for the referenced cache items to change" wscript.echo "VERBOSE : Display addional information about the cache" & vbcrlf CleanupAndExit() end if next if HostName = "" then HostName = "localhost" end if if WATCH then Verb ="Watching for change to " if WAIT then Verb ="Waiting for change to " if Verb = "Details for " then Verbose = True wscript.echo Verb & Hostname '====================================================================== '---[ Confirm WMI is operational '====================================================================== on error resume next set service = GetObject ("winmgmts:\\" & Hostname ) on error goto 0 if not IsObject(service) then LogWriteln("Can't connect to WMI interface on " & Hostname ) CleanupAndExit() end if '====================================================================== '---[ Connect to SCCM class '====================================================================== on error resume next set oUIResManager = createobject("UIResource.UIResourceMgr") on error goto 0 if NOT isobject(oUIResManager) then wscript.echo "Can't create WMI connection to SCCM Resource Manager" CheckForCCMEXECProcess() CleanupAndExit() end if '====================================================================== '---[ read the basic Cache info '====================================================================== on error resume next set oCache=oUIResManager.GetCacheInfo() on error goto 0 if oCache is nothing then LogWriteln("Error accessing oUIResManager.GetCacheInfo()") wscript.echo "Couldn't get available cache info" set oUIResManager=nothing CheckForCCMEXECProcess() CleanupAndExit() end if if Verbose then wscript.echo "TotalSize: " & oCache.TotalSize /1024 & " GB" wscript.echo "FreeSize: " & oCache.FreeSize /1024 & " GB" wscript.echo "Location: " & oCache.Location wscript.echo "MaxCacheDuration: " & oCache.MaxCacheDuration /60/24 & " days" wscript.echo "ReservedSize: " & oCache.ReservedSize & " GB" wscript.echo "TombstoneDuration: " & oCache.TombstoneDuration /60 & " Hours" end if '====================================================================== '---[ read the next available Cache ID (next folder name) using WMI '====================================================================== strWMIClass = "winmgmts:\\" & Hostname & "\root\ccm\SoftMgmtAgent" on error resume next Set oWMI = GetObject(strWMIClass) on error goto 0 if not IsObject(oWMI) then ' didn't read it CheckForCCMEXECProcess() CleanupAndExit() end if on error goto 0 strQuery = "SELECT * FROM CacheConfig" on error resume next Set colItems = oWMI.ExecQuery(strQuery,,48) on error goto 0 NextAvailableID = "none" if isobject(colItems) then on error resume next For Each objItem In colItems NextAvailableID = objItem.NextAvailableId ' read the only record, to get the nextavailableID Next on error goto 0 if Err.number 0 then LogWriteln("CacheConfig WMI query did not return a collection: [" & strWMIClass & " : " & strQuery & "]. Aborting.") CleanupAndExit() end if on error goto 0 else LogWriteln("Error: no results from query against local WMI class: [" & strWMIClass & " : " & strQuery & "]. Aborting.") CleanupAndExit() end if if Verbose then LogWriteln("NextAvailableID: " & NextAvailableID) '====================================================================== '---[ read the Scripts '====================================================================== on error goto 0 set oCache=oUIResManager.GetAvailableScripts() if oCache is nothing then set oUIResManager=nothing wscript.echo "Couldn't get available scripts info" end if if Verbose then wscript.echo "Scripts: " & oCache.Count '====================================================================== '---[ read the Program elements '====================================================================== if Verbose then set oPrograms = createobject("UIResource.Programs") ' connect to Class: PROGRAMS if oPrograms is nothing then wscript.echo "Couldn't get programs info" else CurrentProgramsCount = oPrograms.Count wscript.echo "Programs: " & CurrentProgramsCount for i = 1 to CurrentProgramsCount wscript.echo oPrograms.item(i) next end if end if '====================================================================== '---[ read the application items '====================================================================== ' ** these are applications (not programs), which are not used in this organization if Verbose then on error goto 0 set oUIResManager = createobject("UIResource.UIResourceMgr") set oCache=oUIResManager.GetAvailableApplications() ' class is Programs if oCache is nothing then set oUIResManager=nothing wscript.echo "Unable to read applications" end if wscript.echo "Applications: " & oCache.Count if oCache.Count > 0 then for i = 0 to oCache.Count + 1 wscript.echo "Applications: " & oCache.item(i).Name next end if end if '====================================================================== '---[ read the Cache Elements '====================================================================== on error goto 0 set oCache=oUIResManager.GetCacheInfo() set oCacheElements=oCache.GetCacheElements 'GetCacheElements GetCacheElements GetCacheElements GetCacheElements GetCacheElements CurrentElementCount = oCacheElements.Count if Verbose then wscript.echo "Total CacheElements: " & CurrentElementCount '====================================================================== '---[ Count the referenced cache elements '====================================================================== on error goto 0 CurrentReferenceCount = CountReferences() ShowReferencedCacheElements wscript.echo "Referenced CacheElements: " & CurrentReferenceCount if not (WATCH or WAIT) then CleanupAndExit() end if wscript.echo BigNum(CurrentReferenceCount) '---[ Wait for the count to change 0 then MaybeS = "" : if .ReferenceCount > 1 then MaybeS = "s" wscript.echo "----[ Item " & .ContentID & " ver." & .ContentVersion & " ]---( "& .ReferenceCount & " reference" & MaybeS & " )------" MyPath = .Location MyFilenameList = ListDir(MyPath & "\*.*") For j = 0 to ubound(MyFilenameList) wscript.echo "EXISTING: " & MyFilenameList(j) AddFilenameToList(MyFilenameList(j)) Next end if end with next end function '====================================================================== function AddFilenamesToList(ThisFilename) ' add the current filename to the array if not already there; echo to the screen '====================================================================== if arrCurrentFilenames(ThisFilename) then if FilenameIsInList(ThisFilename) then reDim preserve arrCurrentFilenames(ubound(arrCurrentFilenames) + 1) arrCurrentFilenames(ubound(arrCurrentFilenames)) = ThisFilename wscript.echo "NEW: " & ThisFilename return end if end if end function '====================================================================== Function ShowDeletedElements '====================================================================== Dim i, j for i = 1 to ubound(arrPreviousFilenames) FoundFilename = false for j = 1 to ubound(arrCurrentFilenames) if arrPreviousFilenames(i) = arrCurrentFilenames(j) then FoundFilename = true next if FoundFilename = false then wscript.echo "REMOVED: " & arrPreviousFilenames(i) next end function '====================================================================== function FilenameIsInList(ThisFilename) ' add the given filename to the array if it;s not already there '====================================================================== Dim i FilenameIsInList = False for i = 1 to ubound(arrCurrentFilenames) if arrCurrentFilenames(ubound(arrCurrentFilenames), 1) = ThisFile then FilenameIsInList = True return End if next end function '====================================================================== function CopyTheFileArray ' copy the elements in Current array to Previous array '====================================================================== Dim i if isArray(arrCurrentFilenames) then reDim arrPreviousFilenames(ubound(arrCurrentFilenames))' 0 then RefCount = RefCount +1 end if end with next CountReferences = RefCount end function '====================================================================== function LogWriteln(s) '====================================================================== wscript.echo (s) end function '====================================================================== function CheckForCCMEXECProcess() '====================================================================== Dim Found_CCMExec : Found_CCMExec = False Dim Process on error resume next set service = GetObject ("winmgmts:\\" & Hostname) on error goto 0 if not IsObject(service) then LogWriteln("Cannot connect to WMI at all for further details") else for each Process in Service.InstancesOf ("Win32_Process") If ucase(Process.Name) = "CCMEXEC.EXE" then Found_CCMExec = True next if Found_CCMExec then LogWriteln("CCMExec is running") else LogWriteln("CCMExec is not running") end if end if Dim FSO Set FSO = CreateObject("Scripting.FileSystemObject") If fso.FileExists("\\" & Hostname & "\c$\windows\ccm\ccmexec.exe") Then LogWriteln("Found CCMExec.exe on C$ drive") else LogWriteln("Can't find \\" & Hostname & "\c$\windows\ccm\ccmexec.exe") end if end function 'wscript.echo ubound(MyFilenameList) 'wscript.echo MyFilenameList(0) '---[ list the files in the folder (if it's not just one cab file, like an update 'if right(MyFilenameList(0),4) ".cab" then 'end if 'wscript.echo "[" & i & "] ContentVersion : " & .ContentVersion & "" 'wscript.echo "[" & i & "] ReferenceCount : " & .ContentVersion & "" 'wscript.echo "[" & i & "] CacheElementID : " & .CacheElementID & "" ' Item is a "IPrograms :: Program class 'wscript.echo "[" & i & "] ContentID : " & .ContentID & "" 'wscript.echo "[" & i & "] ContentSize : " & .ContentSize & " KB" 'wscript.echo "[" & i & "] LastReferenceTime : " & .LastReferenceTime & "" 'wscript.echo "[" & i & "] Location : " & .Location & "" '====================================================================== '---[ supporting functions for reading a directory '====================================================================== '====================================================================== Public Function ListDir (ByVal Path) '====================================================================== Dim fso: Set fso = CreateObject("Scripting.FileSystemObject") If Path = "" then Path = "*.*" Dim Parent, Filter if fso.FolderExists(Path) then ' Path is a directory Parent = Path Filter = "*" Else Parent = fso.GetParentFolderName(Path) If Parent = "" Then If Right(Path,1) = ":" Then Parent = Path: Else Parent = "." Filter = fso.GetFileName(Path) If Filter = "" Then Filter = "*" End If ReDim a(10) Dim n: n = 0 Dim Folder: Set Folder = fso.GetFolder(Parent) Dim Files: Set Files = Folder.Files Dim File For Each File In Files If CompareFileName(File.Name,Filter) Then If n > UBound(a) Then ReDim Preserve a(n*2) a(n) = File.Path n = n + 1 End If Next ReDim Preserve a(n-1) ListDir = a End Function '====================================================================== Private Function CompareFileName (ByVal Name, ByVal Filter) ' (recursive) '====================================================================== CompareFileName = False Dim np, fp: np = 1: fp = 1 Do If fp > Len(Filter) Then CompareFileName = np > len(name): Exit Function If Mid(Filter,fp) = ".*" Then ' special case: ".*" at end of filter If np > Len(Name) Then CompareFileName = True: Exit Function End If If Mid(Filter,fp) = "." Then ' special case: "." at end of filter CompareFileName = np > Len(Name): Exit Function End If Dim fc: fc = Mid(Filter,fp,1): fp = fp + 1 Select Case fc Case "*" CompareFileName = CompareFileName2(name,np,filter,fp) Exit Function Case "?" If np <= Len(Name) And Mid(Name,np,1) "." Then np = np + 1 Case Else If np > Len(Name) Then Exit Function Dim nc: nc = Mid(Name,np,1): np = np + 1 If Strcomp(fc,nc,vbTextCompare)0 Then Exit Function End Select Loop End Function '====================================================================== Private Function CompareFileName2 (ByVal Name, ByVal np0, ByVal Filter, ByVal fp0) '====================================================================== Dim fp: fp = fp0 Dim fc2 Do ' skip over "*" and "?" characters in filter If fp > Len(Filter) Then CompareFileName2 = True: Exit Function fc2 = Mid(Filter,fp,1): fp = fp + 1 If fc2 "*" And fc2 "?" Then Exit Do Loop If fc2 = "." Then If Mid(Filter,fp) = "*" Then ' special case: ".*" at end of filter CompareFileName2 = True: Exit Function End If If fp > Len(Filter) Then ' special case: "." at end of filter CompareFileName2 = InStr(np0,Name,".") = 0: Exit Function End If End If Dim np For np = np0 To Len(Name) Dim nc: nc = Mid(Name,np,1) If StrComp(fc2,nc,vbTextCompare)=0 Then If CompareFileName(Mid(Name,np+1),Mid(Filter,fp)) Then CompareFileName2 = True: Exit Function End If End If Next CompareFileName2 = False End Function '====================================================================== Function BigNum(MyNum) '====================================================================== Dim Digit, lines(7), Last, i,j Last = len(cstr(MyNum)) - 1 for i = 0 to Last ' for each digit, 0 is leftmost digit Digit = (mid(cstr(MyNum),i+1,1)) for j = 0 to 5 ' for each line, ut it into the line array lines(j) = lines(j) & mid(f(Digit),j*8 + 1,8) if i = Last then BigNum = BigNum & Lines(j) & vbcrlf next next end function '====================================================================== Function F(MyChar) '====================================================================== Select Case MyChar Case 1 f=" __ /_ | | | | | | | |_| " Case 2 f=" ___ |__ \ ) | / / / /_ |____| " Case 3 f=" ____ |___ \ __) | |__ _ < | (_) | \___/ " Case 9 f=" ___ / _ \ | (_) | \__, | / / /_/ " Case 0 f=" ___ / _ \ | | | | | | | | | |_| | \___/ " end select end function '====================================================================== Sub forceCScriptExecution '====================================================================== Dim Arg, Str If Not LCase( Right( WScript.FullName, 12 ) ) = "\cscript.exe" Then For Each Arg In WScript.Arguments If InStr( Arg, " " ) Then Arg = """" & Arg & """" Str = Str & " " & Arg Next Str = Str & " Relaunched" CreateObject( "WScript.Shell" ).Run _ "cscript //nologo """ & WScript.ScriptFullName & """ " & Str WScript.Quit End If End Sub