VBScript & Outlook 2010: Cannot save mail item as text file - vbscript

I have an issue with saving an Outlook 2010 email item as a text file using VBScript. I am beginning to think it is a permissions issue, but the VBScript error message is not very helpful:
myscript.vbs(409, 9) (null): Operation aborted
Code looks like this:
' create an object to hold a folder item -
' point it to first item
set olitem = olitems(1)
if err.number <> 0 then
stdout.write("Could not create Outlook Item object - exiting" & vbcrlf)
stdout.write("Err.Number: " & Err.Number & vbcrlf)
wscript.quit(999)
end if
' save the mail item to a text file
olitem.saveas fullpath_src & messagefilename, oltxt
if err.number <> 0 then
stdout.write("Could not save email as a text file - exiting" & vbcrlf)
stdout.write("Err.Number: " & Err.Number & vbcrlf)
wscript.quit(999)
end if
oltxt is defined as a Const of value 0 - the value for a text file.
I get the same error if I try to process an email's body text under Outlook 2010. Under Outlook 2013 - on a different, non-corporate, machine - the code works fine.
I think I read somewhere that some Outlook 2010 functionality may have been crippled under certain circumstances for security reasons - revolving around the presence/absence of antivirus software. If this is true, I have been stopped in my tracks - even though I have corporate grade AV protection.

Related

Shell does not open Excel unless code ends in VBA

I am trying to fetch CR(change request) status from PTC(MKS) using "im exportissues 123456" query in VBA. but it does open status sheet(A new excel sheet which opens up by query) unless my code ends. below is the snippet of my code.
Sub Query_CR_Status()
shell_output = Shell("im exportissues 123456", 1) 'this should open up a new excel sheet containing CRs)
Application.Wait (Now + TimeValue("0:00:20")) 'waiting 20sec
'here: My code which will read information from the above generated excel sheet
End Sub
But My problem here is the new excel sheet donot open unless it reaches to "End Sub"
Application.Wait() will prevent the application from doing anything for the specified amount of time. So if you shell a command that opens a workbook, but the application is in wait mode then it will be delayed.
You can try and get around this by using something like:
Sub Query_CR_Status()
Dim wbC As byte
wbC = Workbooks.Count
shell_output = Shell("im exportissues 123456", 1)
While Workbooks.Count = wbC
DoEvents '// Process pending messages until workbook count changes
Wend
'// Rest of code
End Sub
Alternatively, Chip Pearson created a ShellAndWait function that might be better suited to this.

Activating (bring to foreground) a specific window with vbscript

I'm not even sure where to start with my question, I tried a hundred things and googled for hours but didn't find anything useful. (I'm open to every dirty trick.)
Here's my problem:
I have a .hta-file with a listbox that looks like this:
It lists all sessions/modi of my SAP Gui running.
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
If application.Connections.Count > 0 Then
Set connection = application.Children(0)
If connection.Sessions.Count > 0 Then
Set session = connection.Children(0)
End If
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject application, "on"
End If
Set optGroup = Document.createElement("OPTGROUP")
optGroup.label = "Server"
'count all connected servers
ConnectionCount = application.Connections.Count
If ConnectionCount > 0 Then
Sessionlist.appendChild(optGroup)
Else
optGroup.label = "No connection here."
End If
'count all sessions per server
If ConnectionCount > 0 Then
For Each conn in application.Connections
'Text output connections and sessions
SessionCount = conn.Sessions.Count
whatIsIt = conn.Description
ConnectionFeld.innerhtml = ConnectionFeld.innerhtml & " <br> " & SessionCount & " Sessions auf " & whatIsIt
'fill listbox with all connections
Set objOption = nothing
Set optGroup = Document.createElement("OPTGROUP")
optGroup.label = conn.Description
Sessionlist.appendChild(optGroup)
i = 0
'fill listbox with all sessions
For Each sess In conn.Sessions
i = i + 1
Set objOption = Document.createElement("OPTION")
objOption.Text = "Session " & i & ": " & sess.ID
objOption.Value = sess.ID
SessionList.options.add(objOption)
Next
Next
Else
Exit Sub
End If
My goal: When I doubleclick on one of the entries in that list, the selected instance of my SAP Gui should come to the foreground/get activated.
Unfortunately my taskmanager only lists one task and that is "SAP Logon". One of my opened windows also has the name "SAP Logon", all others have the same name: "SAP Easy Access".
The only way I can see the IDs of the connection (servername) and the IDs of the session is via extracting them with vbscript. (see above)
Is there any way to do that? The only workarounds I could think of after trying a thousand solutions are these two:
extremely ugly workaround:
If sessionID = sess.ID Then
Set objShell = CreateObject("shell.application")
objShell.MinimizeAll
sess.findById("wnd[0]").maximize
End If
It minimizes all windows an then maximizes the selected SAP window. Unfortunately My HTA-GUI also gets minimized which kinda sucks.
Second idea:
Somehow get to these clickable thingies by shortcut and put that in my script or some other ugly way.
By hand you have to do this:
Click on that little arrow, rightclick on the icon and then leftclick on the name.
Is there any way to automate this? It's driving me crazy.
Hope someone can help me, it would be GREATLY appreciated.
PS: I'm sitting on a machine with restricted rights and so I may not be able to tackle this with Windows API-ish solutions.
EDIT concerning comments:
It is not possible:
to change registry entries
create COM objects
work with anything else than VBScript
Similarly, it also works with the following commands:
session.findById("wnd[0]").iconify
session.findById("wnd[0]").maximize
I found it...
The resizeWorkingPane method - for changing the size of a window - also works on windows in the background. If you change the parameters, the window will come to the foreground.
session.findById("wnd[0]").resizeWorkingPane 300,200,false
I have to partially revoke this, because it doesnt work on all windows. I'm still not sure why, but it keeps failing sometimes. Still, it seems to me, that this is the closest you can get.
From Help.
Activates an application window.
object.AppActivate title
object
WshShell object.
title
Specifies which application to activate. This can be a string containing the title of the application (as it appears in the title bar) or the application's Process ID.
I don't know what access to info you have about the window. Some COM objects have a HWnd property. This post gets you how to convert a hwnd to a ProcessID to be used above.
How to find the window Title of Active(foreground) window using Window Script Host
This shows how to convert a process command-line to a ProcessID. To see what properties and methods are available use the command-line tool wmic (wmic process get /? and wmic process call /?)
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From Win32_Process")
For Each objItem in colItems
msgbox objItem.ProcessID & " " & objItem.CommandLine
Next
This is a 100% of the time solution. It's ugly but it works. You can swap out the IQS3 t code for any other one you can confirm the user won't be in and will have access to. Also part of my reasoning for selection of this code is it loads fast.
Set objShell = CreateObject("wscript.shell")
session.findById("wnd[0]/tbar[0]/okcd").text = "/nIQS3"
session.findById("wnd[0]").sendVKey 0
objShell.AppActivate(cstr(session.ActiveWindow.Text))
session.findById("wnd[0]/tbar[0]/btn[3]").press

Response.Write("OK") gives error Object required: "" in VBScript

What should I do to use Response.Write in VBScript?
Everything else works fine up to this statement.
I never used VBScript before...
The code, which is my first in VBScript and is being written incrementally, works OK with exception of these objects:
WScript.Echo Response.Write Print
I have enabled ASP but I couldn't find a way to install these objects on my PC, which acts as a development server. The production website uses VBScript, ASP and SQL Server. Here is the code:
'...
Do While Not Rs.EOF
AllTerms = AllTerms & Rs("Term")
Rs.MoveNext
Loop
MsgBox AllTerms
' # Print AllTerms
' WScript.Echo AllTerms
' Response.Write Rs("Term")
Rs.Close
Are you using ASP? Response is part of the ASP object model. It's not available when running a VBScript under the Windows Script Host.
Edit:
I see you've updated your code and it looks like you are indeed using ASP. Since you're collecting all of the recordset info in a variable named AllTerms, you should be able to display it using the line:
Response.Write AllTerms ' Use this in place of: MsgBox AllTerms
But if you're new to ASP, you may want to just create a simple page just to test your configuration. Something like this should do:
<%
Response.Write "Today is " & Date
%>
Save it with an .asp extension, request the page from the web server, and make sure the output is proper.

how to get email address from messages in outlook 2003

Sub GetALLEmailAddresses()
Dim objFolder As Folders
Set objFolder = Application.ActiveExplorer.Selection
Dim dic As New Dictionary
Dim strEmail As String
Dim strEmails As String
Dim objItem As MailItem
For Each objItem In objFolder.Items
strEmail = objItem.SenderEmailAddress
If Not dic.Exists(strEmail) Then
strEmails = strEmails + strEmail + ";"
dic.Add strEmail, ""
End If
Next
Debug.Print strEmails
End Sub
I use this code to get email address from message body. I'm not prefect in vb. is there any to help how to get email address from messages in outlook 2003?
In that case, I don't think there's anything built in, so I'd suggest that you don't bother with the SenderEmailAddress but instead just get out the Body and then search the text for email addresses. This will get somewhat complicated though since it might be difficult to be able to tell what's part of an email address and what isn't.
The easiest place to start with is to just look for any # in the text, and then search for the next whitespace on either side of the # and get everything between those whitespaces. But there are a lot of issues to think about. What if the user typed # for some other reason, or if the email contains something like The first email is xxx#test.com.The second email is xxx2#test.com (note the missing space between the . and the The), where your app might think that the email should be xxx#test.com.The.
Edited since my answer was based on a complete misunderstanding of the question.

How do I close Word (or other app) if an error occurs in a VBScript?

I wrote a VBScript app to open Word and Excel documents and search and replace blocks of text and various sections, pulling the new text from a plain text file. I purposely avoided any error checking, primarily because I couldn't figure it out at the time (and the script ran reliably anyway). Now months later on my local machine, I am inexplicably getting error messages about Normal.dot being changed and a message box asking what I want to do about it (which requires three more dialogs to finally answer). Of course this kills my ability to run the script and simply walk away, as it causes the script to fail. Currently when this happens, I have to open the Task Manager, find Winword.exe (of which the GUI isn't running) and kill it then re-run my script.
What's a reasonable way of catching the error and successfully shutting down Word (or Excel). Based on this question I'm trying this:
Set objDoc = objWord.Documents.Open(curDir1 + "\docs\template_spec.dot")
If Err.Number <> 0 Then
WScript.Echo "Error in Word Open:" & Err.Description
objWord.Quit
Else
Set objSelection = objWord.Selection
'Do replacement activities'
ReplaceText(objSelection)
objDoc.SaveAs(curDir1 + "\docs\mynewdocument.doc")
objWord.Quit
End If
Set objShell = Nothing
Set objWord = Nothing
Set objExcel = Nothing
Of course, as fate would have it, I cannot replicate the problem, so it works like normal. Does this solution seem reasonable? And a side question: How the heck do I get Word to stop complaining about Normal.dot (or get the script to handle it)? It's as if Word leaves itself open in the background after I have closed the GUI in some cases.
have you considered wrapping everything into an 'On Error Resume Next' statement so that your script ignores all the errors and continues to run as much as possible before calling the objWord.quit regardless of success or fail.
if you want more information on the correct use of 'On Error Resume Next' then go over to the msdn article on it!
Hope this helps!
Paul
I'm afraid that
WScript.Echo "..."
if it ever fires, is going to stall your script. Other than that, everything looks right. I'll play with it when I get home.
Edit: Word does hang out in the background, quite frequently. For one thing, if you use Outlook, and use Word as your Outlook editor, Word won't go away until Outlook is gone.
I'd agree with the use of "on error resume next".
If you really need to forcefully terminate Word, you can use WMI and the Win32_Process class to find and kill the process. This should be a last resort if everything else fails.
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colProcess = objWMIService.ExecQuery("Select * from Win32_Process Where Name = 'winword.exe'")
For Each objProcess in colProcess
objProcess.Terminate()
Next
This was a modified example from:
http://www.computerperformance.co.uk/vbscript/wmi_process_stop.htm
Also, make sure all your references to the Word automation object are closed and/or set to nothing before you terminate the process.
The most reliable way to terminate all ActiveX instances, clean up garbage, and release resources is to put the code for that purpose into Sub Class_Terminate() of a dummy class, created instance of the class allows to handle script quit event.
Option Explicit
Dim objBeforeQuitHandler, objWord
' create a dummy class instance
Set objBeforeQuitHandler = New clsBeforeQuitHandler
' create word app instance
Set objWord = CreateObject("Word.Application")
objWord.Visible = True
objWord.Documents.Add.ActiveWindow.Selection.TypeText "80040000 error was raised. About to terminate the script." & vbCrLf & "Word will be quitted without saving before script termination just you close popped up error message."
' your code here...
' raise an error
Err.Raise vbObjectError
Class clsBeforeQuitHandler
' dummy class for wrapping script quit event handler
Private Sub Class_Terminate()
Dim objDoc
On Error Resume Next ' to prevent errors in case of unexpected word app termination
If TypeName(objWord) <> "Object" Then ' word app has not been closed yet
objWord.DisplayAlerts = False
For Each objDoc In objWord.Documents
objDoc.Saved = True ' to prevent save as dialog popping up
objDoc.Close
Next
objWord.Quit
End If
End Sub
End Class

Resources