Trigger .exe upon receiving email from sender - c#

I've written a C# application with .net framework. The purpose is to request data from an online spreadsheet app, do stuff with it, then send back updated data.
I think the best way to trigger the exe would be to use webhooks/callbacks, but I gather this would require runnning my program on a web sever with an external IP address.
Rather than periodically polling the spreadsheet app I would like the app to send emails to a specified account upon certain data changes. Upon receiving the email, VBA code checks that the email is from the app then runs the executable.
To run exe on receipt of email:
Private Sub Application_NewMail()
Dim path As String
Dim shl As Variant
path = "C:\Users\***\Desktop\SmartPlugin.exe"
shl = Shell(path, 1)
End Sub
How do I check the sender? The examples I found online loop through all emails but what I'm after is a method of returning the last email received.

Use Application.NewMailEx event instead - it passes the entry id of the new message as the parameter. Use that entry id to call Application.Session.GetItemfromID.

Got it working.
Private Sub Application_NewMail()
Dim objN As NameSpace
Dim objF As MAPIFolder
Set objN = GetNamespace("MAPI")
Set objF = objN.GetDefaultFolder(olFolderInbox)
Set mlItems = objF.Items
mlItems.Sort "CreationTime", True
Set mlItem = mlItems.Item(1)
Dim path As String
Dim shl As Variant
Dim sndString As String
sndString = CStr(mlItem.SenderName)
If InStr(1, sndString, "SmartSheet", vbTextCompare) > 0 Then
path = "C:\Users\Alex Rose\Desktop\SmartPlugin.exe"
shl = Shell(path, 1)
End If
End Sub

Related

Outlook calendars send and receive

Is there a way to synchronize Outlook local shared calendars with their Exchange vesion programatically?
I tried Namespace.SendAndReceive() but it seems it doesn't affect calendars...
Is there something I miss or is it just impossible ?
I would like to perform a "send" from my local shared calendar folder to his server folder.
(I know it is possible to work directly on the server version by unchecking "Download shared calendar" as showed here but I can't do this way)
EDIT :
Why do I try to force sync?
In my add-in, users create new appointments in a shared calendar, and then lauch a function that makes a HTTP request to a script working with EWS to get this exchange calendar. But as the new appointments aren't sent, the script communicating with EWS don't get new appointments.
I found out the "update folder" button in Send/Receive sends the folder to exchange server but looking at the folder object I don't find how to do it programatically...
I finally found a way to synchronize Outlook application's locally shared calendars with the exchange server version (actually it does a "send").
The VB.NET code below progratically opens each shared calendar and then simulate the click on "update calendar" button.
Dim app As New Outlook.Application
Dim ns As Outlook.NameSpace
Dim objExpl As Outlook.Explorer
Dim recip As Outlook.Recipient
Dim olPane As Outlook.NavigationPane
Dim olModule As Outlook.NavigationModule
Dim olGroup As Outlook.NavigationGroup
Dim navFoldersCount As Integer
ns = app.GetNamespace("MAPI")
objExpl = app.ActiveExplorer
For k = 1 To ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar).Folders.Count
Try
'Try catch allows to exclude non-shared calendars to work only with share ones
recip = ns.CreateRecipient(ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar).Folders.Item(k).Name)
recip.Resolve()
If recip.Resolved Then
objExpl.CurrentFolder = ns.GetSharedDefaultFolder(recip, Outlook.OlDefaultFolders.olFolderCalendar)
'accessing to the shared calendars creates their "Calendar - xxx#xxx.xxx" clone.
If Not objExpl Is Nothing Then
'Simulate the click on "UpdateFolder button
objExpl.CommandBars.ExecuteMso("UpdateFolder")
End If
End If
Catch
End Try
Next
olPane = ns.Application.ActiveExplorer.NavigationPane
olModule = olPane.Modules.GetNavigationModule(Outlook.OlNavigationModuleType.olModuleCalendar)
olGroup = olModule.NavigationGroups.GetDefaultNavigationGroup(Outlook.OlGroupType.olPeopleFoldersGroup)
'Removing calendar clones from the navigation pane
navFoldersCount = olGroup.NavigationFolders.Count
For i = navFoldersCount To 1 Step -1
If (olGroup.NavigationFolders.Item(i).DisplayName.Contains("Calendar - ")) Then
olGroup.NavigationFolders.Remove(olGroup.NavigationFolders.Item(i))
End If
Next

No return value of the PS command "net file" while accessing the powershell remotely with .NET

I've built a Sub to interact with PowerShells on other servers within my domain. I never needed any return values of the PS console so far. As I want to control the Computer Management on my FileShare I need the list of all open file-sessions (net file) as you need the session ID to close it with net file "ID" /close.
This is the modified Sub:
Public Sub remoteMSPowershell(ByVal Script As String)
Dim shellUri As String = "http://schemas.microsoft.com/powershell/Microsoft.PowerShell"
Dim newCred As PSCredential = DirectCast(Nothing, PSCredential)
Dim connectionInfo As WSManConnectionInfo = New WSManConnectionInfo(False, "SVR2012r2-file", 5985, "/wsman", shellUri, newCred)
Using Runspace As Runspace = RunspaceFactory.CreateRunspace(connectionInfo)
Runspace.Open()
Dim pipeline As Pipeline = Runspace.CreatePipeline(Script)
Dim results = pipeline.Invoke()
For Each outputItem As PSObject In results
Console.WriteLine(outputItem.Members("Path").Value)
Console.WriteLine(outputItem.Members("Id").Value)
Next
Console.ReadLine()
End Using
End Sub
While outputItem.BaseObject.ToString() gives you 1:1 the same output as you see on the PS console, I only need the Attributes "Path" and "Id".
If I run this Sub on commands like Get-Command, Get-Service and so on it'll form a column with the values of the specified attribute. However if I run it on net file the script fails with a NullReferenceException. The only thing that I can imagine is that .NET is only capable of filtering to members (attributes) of Cmdlets, but I didn't find any reference on that.
EDIT (24.05.16): It doesn't work for all the NET.exe - commands.. Is there another way to read the return values out or even another method to get the return values using PS or .NET?
EDIT (26.05.16): I've been working on two work-arounds.. Both seem to be a dead end though:
Unify the results from outputItem.BaseObject.ToString() and form Arrays of the "Id" and "Path" column. This won't work as the only indicator to split the rows into attributes are (blancs). You can imagine what happens if the File-Path contains a blanc..
A more clean work-around would be to query the desired attributes already in PowerShell like the answers to this SO question. However none of the given answers works for me as you can't query NET commands. See example:

Process not working when called from a web service VB.NET

I'm writing a program that moves docs from one app to another in ApplicationXtender (AX). The AX full-featured client already has such a program (Migration Wizard) that can handle the task, so I created a function that launches it using Process.Start() and supplying the arguments necessary to automate it. When I call the function from a console app or windows form app, the Migration Wizard works perfectly. But the process must be initiated by an event in a web-based workflow project, so I wrote a web service that contains the same function, and then I use an invoke web service control in the workflow to start it. When I consume the function from the web service, the process doesn't complete. I can see it hanging in the task manager. I'm pretty sure it has to do with the user settings in IIS, but I'm not familiar enough with IIS to make any significant difference. I've configured the anonymous authentication's user identity in IIS to launch with a specific user with full rights to AX, and set the DefaultAppPool to run as Local System, but neither worked. I'm thinking I may need to impersonate the user, but I don't know how to do that. Any suggestions?
For reference, here is my code:
Consume Service Code-
Sub Main()
Dim dbName As String
Dim appName As String
Dim preSalesNum As String
Console.WriteLine("Database: ")
dbName = Console.ReadLine
Console.WriteLine("")
Console.WriteLine("Application")
appName = Console.ReadLine
Console.WriteLine("")
Console.WriteLine("Pre-Sales Number:")
preSalesNum = Console.ReadLine
Console.WriteLine("")
MoveDocs.MoveDocs(dbName, appName, preSalesNum)
End Sub
MoveDocs Function (inside of a separate class)-
Public Shared Function MoveDocs(ByVal dbName As String, ByVal appName As String,
ByVal preSalesNum As String) As String
Try
Dim sourceApp As String
If appName = "PRE_SALES_PROJECTS" Then
sourceApp = "PROJECTS"
Else
sourceApp = "LOOSE-FURNITURE"
End If
Dim argsString As String = "/SD " & dbName & " /SU username /SP password /SA
" & appName & " /DD " & dbName & " /DU username /DP password /DA " &
sourceApp & " /S " & """" & preSalesNum & """" & " /A"
Dim procProp As New System.Diagnostics.ProcessStartInfo
With procProp
.FileName = "C:\Program Files (x86)\XtenderSolutions\Content
Management\MigrateWiz32.exe"
.Arguments = argsString
End With
Dim proc As System.Diagnostics.Process =
System.Diagnostics.Process.Start(procProp)
Return argsString
Catch ex As Exception
Return ex.ToString()
End Try
End Function
The MoveDocs() function in the service.asmx file is identical to the one above, minus the 'shared' modifier in the declaration. The app works, the web service doesn't.
ProcessStartInfo has properties for username, password and domain. There's more info on MSDN -
http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.password.aspx

Getting Dynamic Data in Lua

I have built an Instrumentation Cluster with the NVIDIA UI Composer Studio.
To control animations it uses the Lua Scripting Language. Now I'm really new to Lua and my question is the following:
I've got the following Code sequence in Lua which controls my Speedometer:
self.vehicleSpeedData = {} -- A lot of Values are put in here
function self.speedSim( inFrame, theController )
local timeInSec, dummy
timeInSec, dummy = getElapsedTime()
-- data based on 60fps
actualFrameNumber = math.floor(timeInSec * 60)
local theSample = ((actualFrameNumber-1) % #self.vehicleSpeedData) + 1
theController.value = self.vehicleSpeedData[theSample] *0.06
end
The array in this example is empty. So as you can see, the function reads out the Values of the Array.
But what I need is, that I can get this Data from an external Source (Such as RS232 or CAN Simulation) ... What I want to try is, if I can put Data from C# for example to that Lua Script.
It is hard do explain what I exactly want. My idea is that this Lua Script above listens and reads Data which I dynamically read in C# from my Data Source.
Thanks a lot for your help. This work is for my Bachelors Degree and I'm stuck at this point a long time and I'm nearly out of ideas.
It all kind of depends on what that Nvidia thing exposes to the user (in terms of API, and Lua base libraries).
Assuming it is available, you can use io.read to read in a datafile (say a csv) from another source, then parse it yourself into your table. If you can preprocess the file to have a valid Lua syntax (eg prepend a return {, have values separated by , , and end with a }, you could directly load the string with loadstring).
If they allow you to, you could use external libraries for interfacing with RS232, Excel, sockets, whatever.
PS: it's Lua not LUA (not an acronym, but the Portuguese noun for Moon ;))
Edit: example mkfifo
so in Linux it goes like this: make a fifo with mkfifo fff and feed it something echo ' '> fff to prevent Lua from blocking.
In Lua:
fh=io.open('fff','rb')
while true do
res = fh:read()
if res then
print(res)
end
end
Whatever cat into fff (eg cat 10 > fff) will come out in Lua. this way you can read out any available values and use them at each run of your function.
Another option is using standard input, but I'm not sure whether this composer thing lets you.
I hope your Bachelor's Degree turned out alright, what with this response being 1.5 years too late. :) Nonetheless:
As a member of the UI Composer team and a fellow Lua scripter, one technique I use often for streaming external data and events asynchronously into the runtime is to use the Lua Socket library. I have written an abstraction layer on top of it as a UIC behavior.
-- Expected message structure:
-- "<numbytes>,<optionaltag>\n<bytesofmessage>"
-- e.g. "11,simple\nHello World"
-- e.g. "40,\nThis has no tag,\nbut does have a newline"
local ok,socket = pcall(require,'socket')
if not ok then
output("Error loading socket: "..socket)
else
local output = output or print
local sscallbacks = {} -- indexed by simplesocket instance, then tag
SimpleSocket = {}
local SSMeta = {}
SSMeta.__index=SSMeta
function SimpleSocket:server(port,ip,timeout)
return self:create('server',port,ip,timeout)
end
function SimpleSocket:client(port,ip,timeout)
return self:create('client',port,ip,timeout)
end
function SimpleSocket:create(kind,port,ip,timeout)
if not port then port = 51423 end
if not ip then ip = '*' end
if not timeout then timeout = 10 end
local ss = setmetatable({
kind = kind,
ip = ip,
port = port,
timeout = timeout/1000,
queue = {}
},SSMeta)
sscallbacks[ss] = {}
return ss
end
function SSMeta:destroy()
if self.socket then self.socket:close() end
callbacks[self] = nil
end
function SSMeta:onData(callback,tag)
self:setCallback('handler',callback,tag)
end
function SSMeta:toEncode(callback,tag)
self:setCallback('encoder',callback,tag)
end
function SSMeta:toDecode(callback,tag)
self:setCallback('decoder',callback,tag)
end
function SSMeta:setCallback(type,callback,tag)
if not tag then tag = "" end
if not sscallbacks[self][tag] then sscallbacks[self][tag] = {} end
sscallbacks[self][tag][type] = callback
end
function self:onUpdate()
self:sendQueuedMessages()
self:receiveMessages()
end
function SSMeta:createSocket()
output("Creating new "..self.kind.." socket to "..self.ip..":"..self.port)
if self.kind=='server' then
self.socket = assert(socket.bind(self.ip,self.port))
self.socket:settimeout(self.timeout)
else
self.socket = assert(socket.connect(self.ip,self.port))
end
end
-- Attempts to send all messages from the queue
function self:sendQueuedMessages()
for ss,_ in pairs(sscallbacks) do
while ss.queue[1] do
if ss:sendMessage(message[1]) then
table.remove(ss.queue,1)
else
-- don't attempt any later messages, since ordering may be important
return
end
end
end
end
function self:receiveMessages()
for ss,callbacks in pairs(sscallbacks) do
if ss.kind=='client' then
if not ss.socket then ss:createSocket() end
ss.socket:settimeout(0) -- non-blocking for first byte
local char1, err = ss.socket:receive(1)
ss.socket:settimeout(ss.timeout) -- go back to blocking
if not char1 then
-- probably just timed out
else
local header, err = ss.socket:receive('*l')
if not header then
output(err)
else
header = char1..header
local comma = header:find(',')
local bytes = tonumber(header:sub(1,comma-1))
local tag = header:sub(comma+1)
local data,err = ss.socket:receive(bytes)
if not data then
output(err)
else
if callbacks[tag] and callbacks[tag].decoder then
data = callbacks[tag].decoder(data)
elseif callbacks[true] and callbacks[true].decoder then
data = callbacks[true].decoder(data)
end
if callbacks[tag] and callbacks[tag].handler then
callbacks[tag].handler(data)
elseif callbacks[true] and callbacks[true].handler then
callbacks[true].handler(data)
end
end
end
end
end
end
end
function SSMeta:send(data,tag)
return self:sendMessage(self:encodeMessage(data,tag))
end
function SSMeta:ensureSend(data,tag)
local message = self:encodeMessage(data,tag)
if not self:sendMessage(message) then
table.insert(self.queue,message)
end
end
-- Internal only; use send() or ensureSend()
function SSMeta:sendMessage(formattedMessage)
if not self.socket then self:createSocket() end
if not self.client then self.client = self.socket:accept() end
if self.client then
local lastbyte,err = self.client:send(formattedMessage)
if lastbyte then
-- TODO: verify that all bytes were sent
return true
else
output(err)
self.client:close()
self.client = nil
end
else
-- No client connected before the timeout
end
end
function SSMeta:encodeMessage(data,tag)
data = tostring(data)
local callbacks = sscallbacks[self]
if callbacks[tag] and callbacks[tag].encoder then
data = callbacks[tag].encoder(data)
elseif callbacks[true] and callbacks[true].encoder then
data = callbacks[true].encoder(data)
end
return tostring(#data)..","..(tag or "").."\n"..data
end
end
This allows multiple different systems to communicate on the same socket, with different tagged communication, and possibly different encoders/decoders to serialize/deserialize the data.
On the receiving end this is used for example like this:
local ss = require 'SimpleSocket'
local client = ss:client()
client:onData(function(d) print("Client got *: "..d) end,true)

How to change the name of a NetworkAdapter in c#?

People claim the following VB script works for changing network adapter names. However I am having a decidedly difficult time trying to convert this to a c# appliaction that can do the same thing. The problem I seem to be facing is that calls to the NetworkInterface.Name is readonly.
Option Explicit
Const NETWORK_CONNECTIONS = &H31&
Dim sOldName= WScript.Arguments(0)
Dim sNewName= WScript.Arguments(1)
Dim objShell, objFolder, colItems, objItem
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.Namespace(NETWORK_CONNECTIONS)
Set colItems = objFolder.Items
For Each objItem in colItems
If objItem.Name = sOldName Then
objItem.Name =sNewName
End If
Next
I found this which explains it a bit more: http://blogs.technet.com/b/heyscriptingguy/archive/2005/05/11/how-can-i-rename-a-local-area-connection.aspx.
Ok, so there are special folders where the NIC names are stored and you access those folders by binding to the them via the SHELL. How then do you do something like this in c#?
You can change the name of a NIC easily through the registry if you know how the registry structure works.
You will need the NetworkAdapters GUID in order to locate which path to open. To get the network adapter GUID I recommend first querying the WMI "Win32_NetworkAdapter" class. There is a GUID property along with all the other properties needed to identify specific adapters.
You will notice this GUID in the registry path: {4D36E972-E325-11CE-BFC1-08002BE10318}Visit link for information on it:
http://technet.microsoft.com/en-us/library/cc780532(v=ws.10).aspx
string fRegistryKey = string.Format(#"SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\{0}\Connection", NIC_GUID);
RegistryKey RegistryKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, #"\\" + Server.Name);
RegistryKey = RegistryKey.OpenSubKey(fRegistryKey, true); //true is for WriteAble.
RegistryKey.SetValue("Name", "<DesiredAdapterName>");
By design the windows UI will not allow for duplicate NIC names. However, you can force duplicate NIC names via the registry. We have done tests, there seem to be nothing critically effected by having duplicate names. Windows seems to still function fine. You just want to be wary about scripting against NIC names if you don’t incorporate anti-duplicate name logic.
To create uniqueness you can use the adapter index property associated with the WMI query.
You can use the System.Management assembly and use this class.
Follow the sample here - http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/727c8766-8189-4ad6-956d-958e52b97c05/
You can also create a VB.NET dll with the functionality you need and reference and call it from your C# code.
Here is a console app demonstrating the code (I tested and it works :)
Option Explicit On
Module Module1
Sub Main()
Const NETWORK_CONNECTIONS = &H31&
Dim sOldName = "Local Area Connection"
Dim sNewName = "Network"
Dim objShell, objFolder, colItems, objItem
objShell = CreateObject("Shell.Application")
objFolder = objShell.Namespace(NETWORK_CONNECTIONS)
colItems = objFolder.Items
For Each objItem In colItems
Console.WriteLine(objItem.Name)
If objItem.Name = sOldName Then
objItem.Name = sNewName
End If
Console.WriteLine(objItem.Name)
Next
End Sub
End Module
It prints out:
Local Area Connection
Network

Categories

Resources