1

I have composed a .vbs file with near zero knowledge of this coding language (with major code from here and here). I put this together to get my computer to tell me the time every 15 minutes (combined with task scheduler). The trickiest part was to have the script check if zoom was running (as to not interrupt video calls with the speech voice). Now, I would like to take it a step further and check for a second process, Microsoft Teams, for the same reason (to not interrupt video calls). So, I have my basic script copied below. It works for telling time and checking for zoom, but I am unsure how to go about adding "Microsoft Teams" to be checked also.

Dim hour_now, minute_now, speaks, speech
hour_now = hour(time)
minute_now = minute(time)

If minute_now = 0 Then
    speaks = "Il est " & hour_now & " heures"
Else
    speaks = "Il est " & hour_now & " heures " & minute_now & " minutes" 
End If

Set speech = CreateObject("sapi.spvoice")




Dim i
Dim strComputer
Dim FindProc
 
strComputer = "."

FindProc = "zoom"

Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery _
    ("Select Name from Win32_Process WHERE Name LIKE '" & FindProc & "%'")

If colProcessList.count>0 then
    'wscript.echo FindProc & " is running"
else
    'wscript.echo FindProc & " is not running"
    speech.Speak speaks
End if

Set objWMIService = Nothing
Set colProcessList = Nothing

I imagine that I'd need to either set the FindProc object to a list of two and either iterate or have it evaluate all at once. Any help is appreciated. BTW, my computer has a French voice so the telling time is written for French.

Also, if anyone has any ideas as how to set this task up with some kind of off/on button or switch, that could be useful, too.

TIA

daileyco
  • 743
  • 5
  • 13
  • 1
    Does this answer your question? [understanding the For Each Loop](https://stackoverflow.com/questions/13245005/understanding-the-for-each-loop) – user692942 Aug 25 '21 at 16:41
  • 1
    Another good example here: https://stackoverflow.com/questions/45688202/how-to-run-loop-check-vbs-for-particular-running-process-or-missing-process – LesFerch Aug 26 '21 at 00:37
  • Thanks for the references, but I'm not sure they completely answer the questions I have. On top of the For Each Loop, I imagine I will need to "store" the results from each call of the `"Select Name ..."` so that at the end I can evaluate the contents of colProcessList. If I added a loop around the current code, would the previous iteration of colProcessList be overwritten by the current iteration? (I'd want to avoid that.) – daileyco Aug 28 '21 at 17:41

2 Answers2

2

The only issue I see with your answer code is that it will fail to say the time if any executable is running that starts with "zoom" or "teams", such as ZoomIt.exe or TeamSpirit.exe. Otherwise, it can all be done with far fewer lines of code. Here's my version:

Set oSapi = CreateObject("sapi.spvoice")
Set oWMI = GetObject("winmgmts://./root/cimv2")

Function ProcessExist(Exe)
  On Error Resume Next
  Set oProcesses = oWMI.ExecQuery("Select Name from Win32_Process Where Name = '" & Exe & "'")
  If oProcesses.Count>0 Then ProcessExist = True Else ProcessExist = False
  On Error Goto 0
End Function

If Not ProcessExist("Zoom.exe") And Not ProcessExist("Teams.exe") Then 
  Speech = "Il est " & hour(time) & " heures "
  If minute(time)>0 Then Speech = Speech & minute(time) & " minutes"
  oSapi.Speak Speech
End If

Alternate version that checks a list of Exes:

Const ExeList = "Zoom,Teams"
Set oSapi = CreateObject("sapi.spvoice")
Set oWMI = GetObject("winmgmts://./root/cimv2")

Function ProcessExist(Exe)
  On Error Resume Next
  Set oProcesses = oWMI.ExecQuery("Select Name from Win32_Process Where Name = '" & Exe & "'")
  If oProcesses.Count>0 Then ProcessExist = True Else ProcessExist = False
  On Error Goto 0
End Function

Function InProcessList()
  ArrExe = Split(ExeList,",")
  InProcessList = False
  For Each Exe In ArrExe
    If ProcessExist(Exe & ".exe") Then InProcessList = True
  Next
End Function

If Not InProcessList Then 
  Speech = "Il est " & hour(time) & " heures "
  If minute(time)>0 Then Speech = Speech & minute(time) & " minutes"
  oSapi.Speak Speech
End If
LesFerch
  • 1,540
  • 2
  • 5
  • 21
  • Nice. Thanks for condensing the code. Would there be a quick way to add a loop component to the code? For example to store "Zoom.exe" and "Teams.exe" within a variable and iterate through that list. Obviously, I could just add another `And Not` condition, but I'm sure there is a way to loop it. I can "think" of a program that would work but am not proficient to write it. I imagine if I have the list of processes, then I can check one at a time. If at any time one of them is running, I stop. If none are running and I am at the end of the loop, then send the text to the SAPI. – daileyco Sep 01 '21 at 21:42
  • There are many ways to do that. My revised answer shows one approach that builds on the previous script. – LesFerch Sep 03 '21 at 02:01
  • this randomly throws errors sometimes. It is inconsistent from what I can tell. Not sure how to debug. – daileyco Jan 19 '22 at 23:11
  • What is the error? I got an intermittent `SWbemObjectEx` error with another [script](https://stackoverflow.com/a/70014782/15764378) that originally used `GetOwner`. Fixed that by checking session id instead. That script also used WMI, so probably a similar issue. May have to add some error handling to this one. – LesFerch Jan 20 '22 at 05:05
  • @daileyco As a quick fix, I added `On Error Resume Next` and `On Error Goto 0` around the WMI call. – LesFerch Jan 21 '22 at 23:59
0

I figured it out. I am not completely satisfied with the fix, but it works and that's all that really matters.

Thanks to comments on post referencing to For Each loops and with some additional sleuthing, this is what I have.

Dim hour_now
Dim minute_now 
Dim speaks 
Dim speech


hour_now = hour(time)
minute_now = minute(time)

If minute_now = 0 Then
    speaks = "Il est " & hour_now & " heures"
Else
    speaks = "Il est " & hour_now & " heures " & minute_now & " minutes" 
End If

Set speech = CreateObject("sapi.spvoice")




Dim strComputer
Dim TheseProcs
Dim colProcessList
Dim mycount
 

strComputer = "."

Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")


TheseProcs = Array("zoom", "teams")

mycount = 0

For Each FindProc In TheseProcs
    Set colProcessList = objWMIService.ExecQuery _
        ("Select Name from Win32_Process WHERE Name LIKE '" & FindProc & "%'")

    If colProcessList.count>0 Then
        'wscript.echo FindProc & " is running"
        mycount = mycount + 1
    End If
Next



If mycount=0 then
        speech.Speak speaks
End if


Set objWMIService = Nothing
Set colProcessList = Nothing

I ran into a couple road blocks, though. Defining the Array() and setting up the For Each loop were straightforward enough. I had difficulty in storing the output within the loop. I tried to first define the colProcessList as an ArrayList then use the colProcessList.Add to combine the results from each iteration, but I kept getting errors thrown that it wasn't allowed for that object (I assume the incompatibility is from the .ExecQuery.). So, then, I brought the colProcessList.count code within the loop and created another variable to track it. After the loop finishes, I then evaluate this object for the speech functionality. I am unsatisfied with this part though as I'm sure there is a better way to capture the output of each iteration. Furthermore, I am not satisfied that the code will execute every iteration, rather than stopping once some condition is met (e.g., mycount>0). I welcome input on these as well as scheduling the task manually with an off/on switch.

daileyco
  • 743
  • 5
  • 13