I'm new to programming. I've made a simple codeblock that runs a Windows program POSTOPEN when I open an application in Lotus Notes 8.5.3 (basic)
' [ML]Check if user is member of the [ConnectClient] role.
ipConnect = HasRole("[ConnectClient]")
If ipConnect = True Then
Dim result As Integer
Print "Postopen: Has [ConnectClient] role - starting Connect Client"
result = Shell("c:\program files (x86)\ipvision\Connect\connect.exe", 1)
End If
Is there any way for Lotus Script to check if a Windows process is already running?
Thanks
According to this snippet: http://blog.panagenda.com/pub/panablog.nsf/d6plinks/FLOR-7D5KZR
I assume following code could work: http://coderstalk.blogspot.sk/2009/10/list-windows-xp-running-process-and.html
Option Explicit
Dim oProc, oWMIServ, colProc
Dim strPC, strList
Dim StrSpace
strPC = "."
Set oWMIServ = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strPC & "\root\cimv2")
Set colProc = oWMIServ.ExecQuery("Select * from Win32_Process")
strSpace = string(20," ")
strList = "ProcName" & strSpace & vbTab & "ProcID" & vbCrLf & string(45,"-")
For Each oProc In colProc
strSpace = string(28 - len(oProc.Name)," ")
strList = strList & vbCrLf & oProc.Name & strSpace & vbTab & oProc.ProcessId
Next
So once you have process ID (assuming you have ran your task by shellid function), execute chceck for all running processes and determine whether there is processid you have started.
BTW: the same approach can be used to terminate such process. Just google for >"winmgmts" lotusscript<.
Use Shell to run tasklist and direct the output to a file. Then read the file in LotusScript and check if the process is listed there.
edit
Looks like you can even check if a specific process if running using tasklist:
tasklist /FI "IMAGENAME eq connect.exe" /FO CSV > search.log
How to check if a process is running via a batch script
Related
I have a simple vbscript that count the number of files/subfolders in a folder, if the number greater than 5, it will pop up a message to user. I can run this script manually under admin or normal user account, but after I scheduled it in task scheduler as admin, it shows task running, [task started] [action started] [created task process] but it never ends and I never see the message box pops up under user accounts. Is there anything wrong?
Code:
Set filesys = CreateObject("Scripting.FileSystemObject")
Set shell = CreateObject("Shell.Application")
Set RTMFolder = filesys.GetFolder("C:\work\RTM")
Set PMFolder = filesys.GetFolder("C:\work\Powermill")
Set RTMFiles = RTMFolder.Files
Set PMFiles = PMFolder.SubFolders
NumberOfRTM = RTMFiles.Count
NumberofPM = PMFiles.Count
'Wscript.echo NumberOfRTM
Set wshShell = WScript.CreateObject( "WScript.Shell" )
strComputerName = wshShell.ExpandEnvironmentStrings( "%COMPUTERNAME%" )
If NumberOfRTM >= 5 Then
msgbox "Dear user on " & strComputerName & vbcrlf & " " & vbcrlf & "There are more than 5 RTM files saved on C:\WORK\RTM folder, Please move them to K drive.", &h51000, "Clean up C:\work\RTM"
shell.Open "C:\WORK\RTM"
End If
If NumberofPM >= 5 Then
msgbox "Dear user on " & strComputerName & vbcrlf & " " & vbcrlf & "There are more than 5 Powermill files saved on C:\WORK\Powermill folder, Please Clean it up.", &h51000, "Clean up C:\work\Powermill"
shell.Open "C:\WORK\Powermill"
End If
'Release memory
Set RTMFolder = Nothing
Set PMFolder = Nothing
Set RTMFiles = Nothing
Set PMFiles = Nothing
Try your program/script to be c:\windows\syswow64\cscript.exe or even c:\windows\system32\cscript.exe and then have the argument be c:\path_to_your_vbs\your.vbs
I want to keep open the PowerShell console once the execution has finished.
Actually, after the .exe execution, the PowerShell shut down. I would like to review the outputs once the execution stops, but I can't with the current code.
Sub Button_run_st()
Dim strPName As String
Dim strA As String
strPName = Range("C14").Text
strA = "--dd=" & Application.ActiveWorkbook.Path
Call Shell("" & strPName & " " & strA & "", vbNormalNoFocus)
End Sub
Does anyone know how to do it?
I'm trying to attach a vbscript onto my windows scheduler so that as soon as I open a program (for example, Google Chrome) it runs an excel macro in the background. I've looked into task scheduler and can't find the ability to trigger events based on opening another program, as opposed to an administrative message or error. Sorry for the noob question!
This is from Windows SDK WMI section. http://msdn.microsoft.com/en-us/library/aa392396(v=vs.85).aspx
This monitors 6 (i=0 to 5) program starts and exits.
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" _
& strComputer & "\root\CIMV2")
Set objEvents = objWMIService.ExecNotificationQuery _
("SELECT * FROM Win32_ProcessTrace")
Wscript.Echo "Waiting for events ..."
i = 0
Do Until i=5
Set objReceivedEvent = objEvents.NextEvent
'report an event
Wscript.Echo "Win32_ProcessTrace event occurred" & VBNewLine _
& "Process Name = " _
& objReceivedEvent.ProcessName & VBNewLine _
& "Process ID = " _
& objReceivedEvent.Processid & VBNewLine _
& "Session ID = " & objReceivedEvent.SessionID
i = i+ 1
Loop
I have a simple script that monitors processes' different performance statistics in Windows XP in a loop until it is terminated.
Despite my efforts, the script's memory footprint increases in size over time.
Any advice is greatly appreciated.
Set fso = CreateObject("Scripting.FileSystemObject")
logFileDirectory = "C:\POSrewrite\data\logs"
Dim output
Dim filePath
filePath = "\SCOPerformance-" & Day(Now()) & Month(Now()) & Year(Now()) & ".log"
IF fso.FolderExists(logFileDirectory) THEN
ELSE
Set objFolder = fso.CreateFolder(logFileDirectory)
END IF
logFilePath = logFileDirectory + filePath + ""
IF (fso.FileExists(logFilePath)) THEN
set logFile = fso.OpenTextFile(logFilePath, 8, True)
output = VBNewLine
output = output & (FormatDateTime(Now()) + " Open log file." & VBNewLine)
ELSE
set logFile = fso.CreateTextFile(logFilePath)
output = output & (FormatDateTime(Now()) + " Create log file." & VBNewLine)
END IF
output = output & (FormatDateTime(Now()) + " Begin Performance Log data." & VBNewLine)
output = output & ( "(Process) (Percent Processor Time) (Working Set(bytes)) (Page Faults Per Second) (PrivateBytes) (PageFileBytes)" & VBNewLine)
WHILE (True)
On Error Resume NEXT
IF Err = 0 THEN
strComputer = "."
Set objRefresher = CreateObject("WbemScripting.SWbemRefresher")
Set objServicesCimv2 = GetObject("winmgmts:\\" _
& strComputer & "\root\cimv2")
Set objRefreshableItem = _
objRefresher.AddEnum(objServicesCimv2 , _
"Win32_PerfFormattedData_PerfProc_Process")
objRefresher.Refresh
' Loop through the processes three times to locate
' and display all the process currently using
' more than 1 % of the process time. Refresh on each pass.
FOR i = 1 TO 3
objRefresher.Refresh
FOR Each Process in objRefreshableItem.ObjectSet
IF Process.PercentProcessorTime > 1 THEN
output = output & (FormatDateTime(Now()) & "," & i ) & _
("," & Process.Name & _
+"," & Process.PercentProcessorTime & "%") & _
("," & Process.WorkingSet) & ("," & Process.PageFaultsPerSec) & _
"," & Process.PrivateBytes & "," & Process.PageFileBytes & VBNewLine
END IF
NEXT
NEXT
ELSE
logFile.WriteLine(FormatDateTime(Now()) + Err.Description)
END IF
logFile.Write(output)
output = Empty
set objRefresher = Nothing
set objServicesCimv2 = Nothing
set objRefreshableItem = Nothing
set objFolder = Nothing
WScript.Sleep(10000)
Wend
I think the main problem with your script is that you initialize WMI objects inside the loop, that is, on every iteration of the loop, even though these objects are always the same:
strComputer = "."
Set objRefresher = CreateObject("WbemScripting.SWbemRefresher")
Set objServicesCimv2 = GetObject("winmgmts:\\" _
& strComputer & "\root\cimv2")
Set objRefreshableItem = _
objRefresher.AddEnum(objServicesCimv2 , _
"Win32_PerfFormattedData_PerfProc_Process")
You need to move this code out of the loop, e.g., at the beginning of the script.
Other tips and suggestions:
Use Option Explicit and explicitly declare all variables used in your script. Declared variables are slightly faster than undeclared ones.
Use FileSystemObject.BuildPath to combine multiple parts of the path. The useful thing about this method is that it inserts the necessary path separators for you.
logFileDirectory = "C:\POSrewrite\data\logs"
filePath = "SCOPerformance-" & Day(Now) & Month(Now) & Year(Now) & ".log"
logFilePath = fso.BuildPath(logFileDirectory, filePath)
The objFolder variable isn't used in your script, so there's no need to create it. Also, you can make the FolderExists check more readable by rewriting it as follows:
If Not fso.FolderExists(logFileDirectory) Then
fso.CreateFolder logFileDirectory
End If
Move repeated code into subroutines and functions for easier maintenance:
Function DateTime
DateTime = FormatDateTime(Now)
End Function
...
output = output & DateTime & " Open log file." & vbNewLine
Usually you don't need parentheses when concatenating strings:
output = output & DateTime & "," & i & _
"," & Process.Name & _
"," & Process.PercentProcessorTime & "%" & _
"," & Process.WorkingSet & "," & Process.PageFaultsPerSec & _
"," & Process.PrivateBytes & "," & Process.PageFileBytes & vbNewLine
In this article, Eric Lippert (Literally worked on designing and building VBScript at Microsoft) indicates that the order in which you dispose of things may be important. Maybe you are running into one of these bugs?
I'll let you read the rest...
When Are You Required To Set Objects To Nothing?
I would recommend against running the script in a permanent loop within the script unless you actually need such a tight loop. I would suggest a single iteration within in the script, called from Scheduled tasks.
I have run into the exact same issue, using it for a procmon-style attempt to capture a rogue process that appears to be respawning.
Narrowing it all down, it appears to be the objRefresher.Refresh and there simply appears to be no way around it
What I did to overcome this was use a for...next to run it 100 times, then immediately afterwards run the following, which would simply respawn the script and shutdown:
CreateObject("Wscript.Shell").Run """" & WScript.ScriptFullName & """", 0, False
So I would watch the memory crawl from 5Mb to 40Mb, then drop back down to 5Mb
Given a pre-configured ODBC System DSN, I'd like to write a function that gracefully tests that connection using VBA.
Private Function TestConnection(ByVal dsnName As String) As Boolean
' What goes here?? '
End Function
Edit: To clarify, the System DSNs are pointing to external SQL Server 2005 databases, with Windows NT authentication.
One approach I've tried is to send some random query to the target database and catch the error. If the query works, return true. If there's an error then return false. This works just fine but it feels...kludgy. Is there a more elegant way, especially one that doesn't rely on On Error Goto ?
Note: It's a legacy Access 2000 database I'm working on, so any solution can't have any Access 2007 or 2003 dependencies. I'd like to make it generic to VBA, but if there's a simple way in Access that's fine too.
Much obliged for any advice.
Dim cnn As ADODB.Connection
Dim canConnect as Boolean
Set cnn = New ADODB.Connection
cnn.Open "DSN HERE"
If cnn.State = adStateOpen Then
canConnect = True
cnn.Close
End If
Msgbox canConnect
EDIT: DSN Format could be "DSN=MyDSN;UID=myuser;PWD=myPwd;"
Look this for connection strings
I'm too late to give you a useful answer to your question, but I came here because I wanted to see if StaCkOverflow has a better answer than the code I'm currently using to test ADODB connections.
...It turns out that the answer is 'No', so I'll post the code for reference: someone else will find it useful.
Coding notes: this isn't a generic answer: it's a method from a class encapsulating the ADODB.Connection object, and it assumes the existence of object 'm_objConnect'.
TestConnection: a VBA Class method for publishing debugging information for an ADODB.Connection object
This prints out the connection string, the current status, a list of ADODB errors (if any) and a full listing of the onnection's named properties.
Public Sub TestConnection()
On Error GoTo ErrTest
Dim i As Integer
If m_objConnect Is Nothing Then
Debug.Print "Object 'm_objConnect' not instantiated."
Else
Debug.Print m_objConnect.ConnectionString
Debug.Print "Connection state = " & ObjectStateString(m_objConnect.State)
Debug.Print
If m_objConnect.Errors.Count > 0 Then
Debug.Print "ADODB ERRORS (" & m_objConnect.Errors.Count & "):"
For i = 0 To m_objConnect.Errors.Count
With m_objConnect.Errors(i)
Debug.Print vbTab & i & ":" _
& vbTab & .Source & " Error " & .Number & ": " _
& vbTab & .Description & " " _
& vbTab & "(SQL state = " & .SqlState & ")"
End With
Next i
End If
Debug.Print
Debug.Print "CONNECTION PROPERTIES (" & m_objConnect.Properties.Count & "):"
For i = 0 To m_objConnect.Properties.Count - 1
Debug.Print vbTab & i & ":" _
& vbTab & m_objConnect.Properties(i).Name & " = " _
& vbTab & m_objConnect.Properties(i).Value
Next i
End If
ExitTest:
Exit Sub
ErrTest:
Debug.Print "Error " & Err.Number & " raised by " & Err.Source & ": " & Err.Description
Resume Next
End Sub
Private Function ObjectStateString(ObjectState As ADODB.ObjectStateEnum) As String
Select Case ObjectState
Case ADODB.ObjectStateEnum.adStateClosed
ObjectStateString = "Closed"
Case ADODB.ObjectStateEnum.adStateConnecting
ObjectStateString = "Connecting"
Case ADODB.ObjectStateEnum.adStateExecuting
ObjectStateString = "Executing"
Case ADODB.ObjectStateEnum.adStateFetching
ObjectStateString = "Fetching"
Case ADODB.ObjectStateEnum.adStateOpen
ObjectStateString = "Open"
Case Else
ObjectStateString = "State " & CLng(ObjectState) & ": unknown state number"
End Select
End Function
Share and enjoy: and watch out for line-breaks, helpfully inserted where they will break the code by your browser (or by StackOverflow's formatting functions).
There no magic function that will test this without actually connecting and trying an operation.
If you feel bad about the random query part - you can query the system tables
For Access
SELECT TOP 1 NAME FROM MSysObjects
For SQL Server
SELECT TOP 1 NAME FROM sysobjects
If you merely have to test that the database server is actually available, this can be done, despite what is being said here that it cannot.
In that case, you can attempt to open a TCP connection to the specific server and port.
The default instance of SQL Server, for example, listens on TCP port 1433. Attempting a simple TCP connection in VBA will tell you if it succeeds or not. Only if that is successful I would query using the ODBC connection.
This is a lot more graceful and efficient. It would remove any "gross" error from your ODBC test code. However, as I said, it is only applicable if you need to test for the mere existence/availability of the database server instance.