# ****************************** #
# Office logger
# Manages Excel, Word, Powerpoint, Outlook events
# ****************************** #
import sys
sys.path.append('../../') # this way main file is visible from this file
from re import findall
import os
from shutil import rmtree
from itertools import chain
from utils.utils import *
from modules.consumerServer import SERVER_ADDR
from modules import supervision
import utils.config
if utils.utils.WINDOWS:
from win32com.client import DispatchWithEvents
import pythoncom
from win32com import __gen_path__
import ctypes
[docs]class ExcelEvents:
"""
Excel application object events
The parameters in each method of these class are passed automatically by the APIs when the event occurs.
https://docs.microsoft.com/en-us/office/vba/api/excel.application(object)
"""
[docs] def __init__(self):
self.seen_events = {}
self.Visible = 1
# self.mouse = mouse.Controller()
# This variable controls OnSheetSelectionChange, if True an actions is logged every time a cell is selected. It's
# resource expensive, so it's possible to turn it off by setting variable to False
self.LOG_EVERY_CELL = True
def setApplication(self, application):
self.application = application
# ************
# Utils
# ************
[docs] def getWorksheets(self, Sh, Wb):
"""
return list of active worksheet in workbook
:param Sh: worksheet
:param Wb: workbook
:return: list of active worksheet in workbook
"""
if Sh:
return list(map(lambda sh: sh.Name, Sh.Parent.Worksheets))
elif Wb:
return list(map(lambda sh: sh.Name, Wb.Worksheets))
# ************
# Window
# ************
[docs] def OnWindowActivate(self, Wb, Wn):
"""
Triggers when excel windows is opened
:param Wb: workbook
:param Wn: window
:return: openWindow event
"""
self.seen_events["OnWindowActivate"] = None
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} openWindow workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} window id:{Wn.WindowNumber} path: {Wb.Path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "openWindow",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"id": Wn.WindowNumber,
"event_src_path": Wb.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWindowDeactivate(self, Wb, Wn):
"""
Triggers when excel windows is closed
:param Wb: workbook
:param Wn: window
:return: closeWindow event
"""
self.seen_events["OnWindowDeactivate"] = None
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} closeWindow workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} window id:{Wn.WindowNumber} path: {Wb.Path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "closeWindow",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"id": Wn.WindowNumber,
"event_src_path": Wb.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWindowResize(self, Wb, Wn):
"""
Triggers when excel windows is resized
:param Wb: workbook
:param Wn: window
:return: resizeWindow event
"""
x, y, width, height = utils.utils.getActiveWindowInfo('size')
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} resizeWindow workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} window id:{Wn.WindowNumber} size {x},{y},{width},{height} ")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "resizeWindow",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"id": Wn.WindowNumber,
"event_src_path": Wb.Path,
"window_size": f"{x},{y},{width},{height}",
"screenshot": screenshot
# "window_size": f"{Wn.Width},{Wn.Height}"
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
# ************
# Workbook
# ************
[docs] def OnNewWorkbook(self, Wb):
"""
New workbook is created
:param Wb: workbook
:return: newWorkbook event
"""
self.seen_events["OnNewWorkbook"] = None
screenshot = takeScreenshot()
# get excel window size
x, y, width, height = utils.utils.getActiveWindowInfo('size')
print(
f"{utils.utils.timestamp()} {utils.utils.USER} newWorkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {Wb.Path} window_size {x},{y},{width},{height}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "newWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": Wb.Path,
"window_size": f"{x},{y},{width},{height}",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWorkbookOpen(self, Wb):
"""
Workbook is opened
:param Wb: workbook
:return: openWorkbook event
"""
screenshot = takeScreenshot()
path = os.path.join(Wb.Path, Wb.Name)
print(
f"{utils.utils.timestamp()} {utils.utils.USER} openWorkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "openWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWorkbookNewSheet(self, Wb, Sh):
"""
New sheet is created
:param Wb: workbook
:param Sh: worksheet
:return: addWorksheet event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} addWorksheet workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {Wb.Path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "addWorksheet",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": Wb.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWorkbookBeforeSave(self, Wb, SaveAsUI, Cancel):
"""
This is triggered right before a workbook is saved
:param Wb: workbook
:param SaveAsUI: 'save as' dialog box displayed to user
:param Cancel: saving is canceled
:return: beforeSaveWorkbook event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} saveWorkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} saveAs dialog {SaveAsUI}")
if SaveAsUI:
description = "SaveAs dialog box displayed"
else:
description = "SaveAs dialog box not displayed"
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "beforeSaveWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"description": description,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWorkbookAfterSave(self, Wb, Success):
"""
This event is triggered after a workbook has been saved.
:param Wb: workbook
:param Success: boolean value to indicate if saving was succesful
:return: saveWorkbook event
"""
screenshot = takeScreenshot()
savedPath = os.path.join(Wb.Path, Wb.Name)
print(
f"{utils.utils.timestamp()} {utils.utils.USER} saveWorkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {savedPath}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "saveWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": savedPath,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWorkbookAddinInstall(self, Wb):
"""
An AddIn is installed in excel
:param Wb: workbook
:return: addinInstalledWorkbook event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} addinInstalledWorkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {Wb.Path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "addinInstalledWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": Wb.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWorkbookAddinUninstall(self, Wb):
"""
An AddIn is uninstalled in excel
:param Wb: workbook
:return: addinUninstalledWorkbook event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} addinUninstalledWorkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {Wb.Path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "addinUninstalledWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": Wb.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWorkbookAfterXmlImport(self, Wb, Map, Url, Result):
"""
XML is imported into excel
:param Wb: workbook
:param Map:
:param Url:
:param Result: import result
:return: XMLImportWorkbook event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} XMLImportWOrkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {Wb.Path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "XMLImportWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": Wb.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWorkbookAfterXmlExport(self, Wb, Map, Url, Result):
"""
XML is exported from excel
:param Wb: workbook
:param Map:
:param Url:
:param Result: import result
:return: XMLExportWorkbook event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} XMLExportWOrkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {Wb.Path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "XMLExportWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": Wb.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWorkbookBeforePrint(self, Wb, Cancel):
"""
Print action is triggered in a workbook
:param Wb: workbook
:param Cancel: true if print is canceled
:return: printWorkbook event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} printWorkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {Wb.Path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "printWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": Wb.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWorkbookBeforeClose(self, Wb, Cancel):
"""
workbook is closed
:param Wb: workbook
:param Cancel: true if close is canceled
:return: closeWorkbook event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} closeWorkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {Wb.Path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "closeWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": Wb.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWorkbookActivate(self, Wb):
"""
workbook is activated (occurs when excel window is clicked and goes to foreground)
:param Wb: workbook
:return: activateWorkbook event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} activateWorkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {Wb.Path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "activateWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": Wb.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWorkbookDeactivate(self, Wb):
"""
workbook is deactivated (occurs when excel window is not visible anymore)
:param Wb: workbook
:return: deactivateWorkbook event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} deactivateWorkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {Wb.Path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "deactivateWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": Wb.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
def OnWorkbookModelChange(self, Wb, Changes):
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} modelChangeWorkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {Wb.Path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "modelChangeWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": Wb.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWorkbookNewChart(self, Wb, Ch):
"""
A new chart is added to the open workbook
:param Wb: workbook
:param Ch: chart
:return: newChartWorkbook event
"""
print(
f"{utils.utils.timestamp()} {utils.utils.USER} newChartWorkbook workbook: {Wb.Name} Worksheet:{Wb.ActiveSheet.Name} path: {Wb.Path}")
screenshot = takeScreenshot()
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "newChartWorkbook",
"workbook": Wb.Name,
"current_worksheet": Wb.ActiveSheet.Name,
"worksheets": self.getWorksheets(None, Wb),
"event_src_path": Wb.Path,
"title": Ch.Name,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnAfterCalculate(self):
"""
This event occurs after a calculation has been performed
:return: afterCalculate event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} afterCalculate")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "afterCalculate",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
# ************
# Worksheet
# ************
[docs] def filterNoneRangeValues(self, values):
"""
When a range of cells is selected, Target.Value is a Tuple of tuples containing the value of every
selected cell Target.Value = ((None, None, None, None), (None, 'prova', None, None)). I'm
interested only in cells with meaningful value, so I create a single list with all the tuples in
Target.Value (by chaining the tuples using chain.from_iterable(list)) obtaining [None, None, None,
None, None, 'prova', None, None] Now I remove the elements that are None by applying a filter
operator to the previous list
:param values: tuple of values
:return: tuple of values without None values
"""
if values:
try:
# If entire column/row is selected, I consider only the first 10.000 to save memory
# return list(filter(lambda s: s is not None, list(chain.from_iterable(list(values)))))
return [s for s in list(chain.from_iterable(list(values[:8000]))) if s is not None]
except TypeError:
return values
else:
return ""
[docs] def OnSheetActivate(self, Sh):
"""
Occurs when a worksheet is selected
:param Sh: worksheet
:return: selectWorksheet event
"""
screenshot = takeScreenshot()
# to get the list of active worksheet names, I cycle through the parent which is the workbook
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Microsoft Excel selectWorksheet {Sh.Name} {Sh.Parent.Name} {self.getWorksheets(Sh, None)}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "selectWorksheet",
"workbook": Sh.Parent.Name,
"current_worksheet": Sh.Name,
"worksheets": self.getWorksheets(Sh, None),
"event_src_path": Sh.Parent.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSheetBeforeDelete(self, Sh):
"""
Occurs when a worksheet is deleted
:param Sh: worksheet
:return: deleteWorksheet event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Microsoft Excel deleteWorksheet {Sh.Name} {Sh.Parent.Name} {self.getWorksheets(Sh, None)}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "deleteWorksheet",
"workbook": Sh.Parent.Name,
"current_worksheet": Sh.Name,
"worksheets": self.getWorksheets(Sh, None),
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSheetBeforeDoubleClick(self, Sh, Target, Cancel):
"""
Triggered when double clicking on a cell
:param Sh: worksheet
:param Target: cell clicked
:param Cancel: true if event is canceled
:return: doubleClickCellWithValue/doubleClickEmptyCell event
"""
screenshot = takeScreenshot()
event_type = "doubleClickEmptyCell"
value = ""
if Target.Value: # cell has value
event_type = "doubleClickCellWithValue"
value = Target.Value
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Microsoft Excel {event_type} {Sh.Name} {Sh.Parent.Name} {Target.Address.replace('$', '')} {value}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": event_type,
"workbook": Sh.Parent.Name,
"current_worksheet": Sh.Name,
"cell_range": Target.Address.replace('$', ''),
"cell_content": value,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSheetBeforeRightClick(self, Sh, Target, Cancel):
"""
Triggered when right clicking on a cell
:param Sh: worksheet
:param Target: cell clicked
:param Cancel: true if event is canceled
:return: rightClickCellWithValue/rightClickEmptyCell event
"""
screenshot = takeScreenshot()
event_type = "rightClickEmptyCell"
value = ""
if Target.Value: # cell has value
event_type = "rightClickCellWithValue"
value = Target.Value
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Microsoft Excel {event_type} {Sh.Name} {Sh.Parent.Name} {Target.Address.replace('$', '')} {value}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": event_type,
"workbook": Sh.Parent.Name,
"current_worksheet": Sh.Name,
"cell_range": Target.Address.replace('$', ''),
"cell_content": value,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSheetCalculate(self, Sh):
"""
Occurs when a calculation is performed
:param Sh: worksheet
:return: sheetCalculate event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Microsoft Excel sheetCalculate {Sh.Name} {Sh.Parent.Name} ")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "sheetCalculate",
"workbook": Sh.Parent.Name,
"current_worksheet": Sh.Name,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSheetChange(self, Sh, Target):
"""
Occurs when a cell is edited
:param Sh: worksheet
:param Target: edited cell
:return: editCellSheet event
"""
screenshot = takeScreenshot()
# if entire row/column is selected, get only the first 8000 occurrences to save space
value = self.filterNoneRangeValues(Target.Value)
cell_range_number = f"{Target.Column},{Target.Row}"
entireColAddres = Target.EntireColumn.Address
entireRowAddres = Target.EntireRow.Address
cellAddress = Target.Address
event_type = "editCellSheet"
cell_range = cellAddress.replace('$', '')
# can't detect if insertion or removal
# # row inserted/deleted
# if not cellAddress == entireColAddres:
# event_type = "deleteRow"
# cell_range_number = f"{Target.Row},{Target.Row}"
# # column inserted/deleted
# elif not cellAddress == entireRowAddres:
# event_type = "deleteColumn"
# cell_range_number = f"{Target.Column},{Target.Column}"
# filterNoneRangeValues returns a list but if user selected a single cell I get a list of letters like
# ['p', 'y', 't', 'h', 'o', 'n'] so if there is no ':' in selection i join the list to get the word back
if not ':' in cell_range:
try:
value = ''.join(value)
except TypeError:
pass
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Microsoft Excel editCellSheet {Sh.Name} {Sh.Parent.Name} {cell_range} ({cell_range_number}) {value}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": event_type,
"workbook": Sh.Parent.Name,
"current_worksheet": Sh.Name,
"cell_range": cell_range,
"cell_range_number": cell_range_number,
"cell_content": value,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSheetDeactivate(self, Sh):
"""
Occurs when a worksheet is deselected
:param Sh: worksheet
:return: deselectWorksheet event
"""
screenshot = takeScreenshot()
self.seen_events["OnSheetDeactivate"] = None
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Microsoft Excel deselectWorksheet {Sh.Name} {Sh.Parent.Name} {self.getWorksheets(Sh, None)}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "deselectWorksheet",
"workbook": Sh.Parent.Name,
"current_worksheet": Sh.Name,
"worksheets": self.getWorksheets(Sh, None),
"event_src_path": Sh.Parent.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSheetFollowHyperlink(self, Sh, Target):
"""
Occurs when a link is clicked
:param Sh: worksheet
:param Target: cell clicked
:return: followHiperlinkSheet event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Microsoft Excel followHiperlinkSheet {Sh.Name} {Sh.Parent.Name} {Target.Range.Address.replace('$', '')} {Target.Address}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "followHiperlinkSheet",
"workbook": Sh.Parent.Name,
"current_worksheet": Sh.Name,
"cell_range": Target.Range.Address.replace('$', ''),
"browser_url": Target.Address,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSheetPivotTableAfterValueChange(self, Sh, TargetPivotTable, TargetRange):
"""
Occurs when values in a pivot table change.
:param Sh: worksheet
:param TargetPivotTable: target table
:param TargetRange: range modified
:return: pivotTableValueChangeSheet event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Microsoft Excel pivotTableValueChangeSheet {Sh.Name} {Sh.Parent.Name} {TargetRange.Address.replace('$', '')} {TargetRange.Value}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "pivotTableValueChangeSheet",
"workbook": Sh.Parent.Name,
"current_worksheet": Sh.Name,
"cell_range": TargetRange.Address.replace('$', ''),
"cell_content": TargetRange.Value if TargetRange.Value else "",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSheetSelectionChange(self, Sh, Target):
"""
Occurs when a cell or range of cells is selected
:param Sh: worksheet
:param Target: selected range
:return: getCell/getRange event
"""
# value returned is in the format $B$3:$D$3, I remove $ sign
cells_selected = Target.Address.replace('$', '')
cell_range_number = f"{Target.Column},{Target.Row}"
event_type = "getCell"
value = Target.Value if Target.Value else ""
rangeSelected = (':' in cells_selected) # True if the user selected a range of cells
# if a range of cells has been selected
if rangeSelected:
event_type = "getRange"
# Returns values of selected cells removing empty cells
value = self.filterNoneRangeValues(Target.Value)
# If LOG_EVERY_CELL is False and a user selects a single cell the event is not logged
if rangeSelected or self.LOG_EVERY_CELL:
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Microsoft Excel {event_type} {Sh.Name} {Sh.Parent.Name} {cells_selected} ({cell_range_number}) {value}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": event_type,
"workbook": Sh.Parent.Name,
"current_worksheet": Sh.Name,
"cell_range": cells_selected,
"cell_range_number": cell_range_number,
"cell_content": value,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSheetTableUpdate(self, Sh, Target):
"""
Occurs when a table is updated
:param Sh: worksheet
:param Target: table
:return: worksheetTableUpdated event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Microsoft Excel worksheetTableUpdated {Sh.Name} {Sh.Parent.Name} ")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel",
"event_type": "worksheetTableUpdated",
"workbook": Sh.Parent.Name,
"current_worksheet": Sh.Name,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
# Takes filename as input if user wants to open existing file
[docs]def excelEvents(status_queue, filepath=None):
"""
Handle excel events on windows using pythoncom.
Also manages exception in case excel instance fails to launch.
:param status_queue: queue to pring messages on GUI
:param filepath: optional path of excel file to open
"""
try:
# needed for thread
pythoncom.CoInitialize()
# start new instance of Excel
e = DispatchWithEvents("Excel.Application", ExcelEvents)
if filepath:
# open existing workbook
e.Workbooks.Open(filepath)
else:
# create new empty workbook that contains worksheet
e.Workbooks.Add()
runLoop(e)
status_queue.put("[officeEvents] Excel logging started")
if not CheckSeenEvents(e, ["OnNewWorkbook", "OnWindowActivate"]):
sys.exit(1)
except Exception as e:
exception = str(e)
print(f"Failed to launch Excel: {exception}")
# https://stackoverflow.com/q/47608506/1440037
if "win32com.gen_py" in exception:
# https://stackoverflow.com/a/54422675/1440037 Â Deleting the gen_py output directory and re-running the
# script should fix the issue find the corrupted directory to remove in gen_py path using regex (
# directory is in the form 'win32com.gen_py.00020813-0000-0000-C000-000000000046x0x1x9) I should have a
# string like '00020813-0000-0000-C000-000000000046x0x1x9'
dirToRemove = findall(r"'(.*?)'", exception)[0].split('.')[-1]
if not dirToRemove:
# if regex failed use default folder
dirToRemove = '00020813-0000-0000-C000-000000000046x0x1x9'
pathToRemove = os.path.join(__gen_path__, dirToRemove)
print(f"Trying to fix the error, deleting {pathToRemove}")
rmtree(pathToRemove, ignore_errors=True)
if not os.path.exists(pathToRemove):
print("The error should now be fixed, try to execute the program again.")
[docs]def excelEventsMacServer(status_queue, excelFilepath=None):
"""
Handle excel events on macOS using xlwings.
The logging process is different on macOS.
An excel Add-in in javascript is installed on excel and it sends data to a node.js server started by this function.
:param status_queue: queue to print messages on GUI
:param excelFilepath: optional path of excel file to open
:return: openWorkbook event
"""
import xlwings as xw
macExcelAddinPath = os.path.join(utils.utils.MAIN_DIRECTORY, 'extensions', 'excelAddinMac')
# os.system(f"cd {macExcelAddinPath} && npm run dev-server >/dev/null 2>&1") # hide output
if not utils.utils.utils.utils.isPortInUse(3000):
screenshot = takeScreenshot()
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Excel (MacOS)",
"event_type": "openWorkbook",
"event_src_path": excelFilepath if excelFilepath else "",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
if excelFilepath:
app = xw.App(visible=True)
book = xw.Book(excelFilepath)
else:
app = xw.App(visible=True)
book = xw.Book()
print("[officeEvents] Excel logging started")
status_queue.put("[officeEvents] Remember to enable OfficeLogger Add-In by clicking 'Insert > My Add-Ins > "
"OfficeLogger' and then 'Home > Show Taskpane'")
os.system(f"cd {macExcelAddinPath} && npm run dev-server")
else:
print(f"[officeEvents] Could not start Excel logging because port 3000 is in use.")
[docs]class WordEvents:
"""
Application object events
https://docs.microsoft.com/en-us/office/vba/api/word.application
"""
[docs] def __init__(self):
self.seen_events = {}
self.Visible = 1
# ************
# Window
# ************
[docs] def OnWindowActivate(self, Doc, Wn):
"""
Occurs when window is activated
:param Doc: document
:param Wn: window
:return: activateWindow event
"""
screenshot = takeScreenshot()
self.seen_events["OnWindowActivate"] = None
print(
f"{utils.utils.timestamp()} {utils.utils.USER} activateWindow")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Word",
"event_type": "activateWindow",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWindowDeactivate(self, Doc, Wn):
"""
Occurs when window is deactivated
:param Doc: document
:param Wn: window
:return: activateWindow event
"""
screenshot = takeScreenshot()
self.seen_events["OnWindowDeactivate"] = None
self.seen_events["OnWindowActivate"] = None
print(
f"{utils.utils.timestamp()} {utils.utils.USER} deactivateWindow")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Word",
"event_type": "deactivateWindow",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWindowBeforeDoubleClick(self, Sel, Cancel):
"""
Occurs when double clicking on document
https://docs.microsoft.com/en-us/office/vba/api/word.selection#properties
:param Sel: selection
:param Cancel: true if action is canceled
:return: doubleClickWindow event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} doubleClickWindow")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Word",
"event_type": "doubleClickWindow",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWindowBeforeRightClick(self, Sel, Cancel):
"""
Occurs when right clicking on document
:param Sel: selection
:param Cancel: true if action is canceled
:return: rightClickWindow event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} rightClickWindow")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Word",
"event_type": "rightClickWindow",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
# Too much spam
# def OnWindowSelectionChange(self, Sel):
# print(f"{utils.utils.timestamp()} {utils.utils.USER} selectionChangeWindow")
# utils.utils.session.post(SERVER_ADDR, json={
# "timestamp": utils.utils.timestamp(),
# "user": utils.utils.USER,
# "category": "MicrosoftOffice",
# "application": "Microsoft Word",
# "event_type": "selectionChangeWindow",
# })
# ************
# Document
# ************
[docs] def OnNewDocument(self, Doc):
"""
Occurs when a new document is created
:param Doc: document
:return: newDocument event
"""
screenshot = takeScreenshot()
self.seen_events["OnNewDocument"] = None
print(f"{utils.utils.timestamp()} {utils.utils.USER} newDocument")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Word",
"event_type": "newDocument",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnDocumentOpen(self, Doc):
"""
Occurs when a new document is opened
:param Doc: document
:return: openDocument event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} openDocument")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Word",
"event_type": "openDocument",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnDocumentChange(self):
"""
Occurs when a document is changed
:return: changeDocument event
"""
screenshot = takeScreenshot()
self.seen_events["OnDocumentChange"] = None
print(f"{utils.utils.timestamp()} {utils.utils.USER} changeDocument")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Word",
"event_type": "changeDocument",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnDocumentBeforeSave(self, Doc, SaveAsUI, Cancel):
"""
Occurs when a document is saved
:param Doc: document
:param SaveAsUI: true if 'save as' dialog is displayed
:param Cancel: true if event is canceled
:return: saveDocument event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} saveDocument")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Word",
"event_type": "saveDocument",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnDocumentBeforePrint(self, Doc, Cancel):
"""
Occurs when a document is printed
:param Doc: document
:param Cancel: true if event is canceled
:return: saveDocument event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} printDocument")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Word",
"event_type": "printDocument",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
def OnQuit(self):
self.seen_events["OnQuit"] = None
[docs]def wordEvents(filename=None):
"""
Handle word events on windows using pythoncom.
:param filename: optional name of file to open
"""
try:
# needed for thread
pythoncom.CoInitialize()
# start new instance of Excel
e = DispatchWithEvents("Word.Application", WordEvents)
if filename:
# open existing document
e.Documents.Open(filename)
else:
# create new empty document that contains worksheet
e.Documents.Add()
runLoop(e)
print("[officeEvents] Word logging started")
if not CheckSeenEvents(e, ["OnNewDocument", "OnWindowActivate"]):
sys.exit(1)
except Exception as e:
print(e)
[docs]class PowerpointEvents:
"""
Application object events
https://docs.microsoft.com/en-us/office/vba/api/powerpoint.application
"""
[docs] def __init__(self):
self.seen_events = None
self.Visible = 1
self.presentationSlides = dict()
# self.mouse = mouse.Controller()
# ************
# Utils
# ************
def addSlide(self, Sld):
id = Sld.SlideID
dict = self.presentationSlides
if id not in dict:
dict[id] = Sld
def popSlide(self, Sld):
id = Sld.SlideID
dict = self.presentationSlides
if id in dict:
dict.pop(Sld.SlideID)
def getSlides(self):
return [slide.Name for slide in self.presentationSlides.values()]
# ************
# Window
# ************
[docs] def OnWindowActivate(self, Pres, Wn):
"""
Occurs when powerpoint window is activated
:param Pres: powerpoint presentation
:param Wn: window
:return: activateWindow event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint activateWindow {Pres.Name} {Pres.Path} ")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "activateWindow",
"title": Pres.Name,
"event_src_path": Pres.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWindowDeactivate(self, Pres, Wn):
"""
Occurs when powerpoint window is deactivated
:param Pres: powerpoint presentation
:param Wn: window
:return: deactivateWindow event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint deactivateWindow {Pres.Name} {Pres.Path} ")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "deactivateWindow",
"title": Pres.Name,
"event_src_path": Pres.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWindowBeforeRightClick(self, Sel, Cancel):
"""
Occurs on right click on presentation
:param Sel: selection
:param Cancel: true if event is canceled
:return: rightClickPresentation event
"""
screenshot = takeScreenshot()
print(Sel.SlideRange)
print(Sel.TextRange)
print(f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint rightClickPresentation ")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "rightClickPresentation",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnWindowBeforeDoubleClick(self, Sel, Cancel):
"""
Occurs on right click on presentation
:param Sel: selection
:param Cancel: true if event is canceled
:return: doubleClickPresentation event
"""
screenshot = takeScreenshot()
print(Sel.SlideRange)
print(Sel.TextRange)
print(f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint doubleClickPresentation ")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "doubleClickPresentation",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
# ************
# Presentation
# ************
[docs] def OnNewPresentation(self, Pres):
"""
New presentation is created
:param Pres: presentation
:return: newPresentation event
"""
screenshot = takeScreenshot()
self.presentationSlides.clear()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint newPresentation {Pres.Name} {Pres.Path}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "newPresentation",
"title": Pres.Name,
"event_src_path": Pres.Path,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnPresentationNewSlide(self, Sld):
"""
A slide is added to an open presentation
:param Sld: slide
:return: newPresentationSlide event
"""
screenshot = takeScreenshot()
self.addSlide(Sld)
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint newPresentationSlide {Sld.Name} {Sld.SlideNumber} {self.getSlides()}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "newPresentationSlide",
"title": Sld.Name,
"id": Sld.SlideNumber,
"slides": self.getSlides(),
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnPresentationBeforeClose(self, Pres, Cancel):
"""
Occurs when a presentation is closed
:param Pres: presentation
:param Cancel: true if event is canceled
:return: closePresentation event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint closePresentation {Pres.Name} {self.getSlides()}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "closePresentation",
"title": Pres.Name,
"event_src_path": Pres.Path,
"slides": self.getSlides(),
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
self.presentationSlides.clear()
[docs] def OnPresentationBeforeSave(self, Pres, Cancel):
"""
Occurs when a presentation is saved
:param Pres: presentation
:param Cancel: true if event is canceled
:return: savePresentation event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint savePresentation {Pres.Name} {self.getSlides()}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "savePresentation",
"title": Pres.Name,
"event_src_path": Pres.Path,
"slides": self.getSlides(),
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnAfterPresentationOpen(self, Pres):
"""
Occurs when a presentation is opened
:param Pres: presentation
:return: savePresentation event
"""
screenshot = takeScreenshot()
self.presentationSlides.clear()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint openPresentation {Pres.Name} {self.getSlides()}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "openPresentation",
"title": Pres.Name,
"event_src_path": Pres.Path,
"slides": self.getSlides(),
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnAfterShapeSizeChange(self, shp):
"""
Occurs when a shape in a presentation is resized
:param shp: shape
:return: shapeSizeChangePresentation event
"""
screenshot = takeScreenshot()
self.presentationSlides.clear()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint shapeSizeChangePresentation {shp.Type} ")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "shapeSizeChangePresentation",
"description": shp.Type,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnPresentationPrint(self, Pres):
"""
Occurs when a presentation is printed
:param Pres: presentation
:return: printPresentation event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint printPresentation {Pres.Name} {self.getSlides()}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "printPresentation",
"title": Pres.Name,
"event_src_path": Pres.Path,
"slides": self.getSlides(),
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSlideShowBegin(self, Wn):
"""
Occurs when slideshow begins
:param Wn: slideshowview https://docs.microsoft.com/en-us/office/vba/api/powerpoint.slideshowview
:return: slideshowBegin event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint slideshowBegin ")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "slideshowBegin",
"title": Wn.SlideShowName,
"description": Wn.State,
# https://docs.microsoft.com/en-us/office/vba/api/powerpoint.slideshowview.state
"newZoomFactor": Wn.Zoom,
"slides": Wn.Slide.Name,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSlideShowOnNext(self, Wn):
"""
Occurs when next slide is displayed during a slideshow
:param Wn: slideshowview https://docs.microsoft.com/en-us/office/vba/api/powerpoint.slideshowview
:return: nextSlideshow
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint nextSlideshow ")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "nextSlideshow",
"title": Wn.SlideShowName,
"description": Wn.State,
# https://docs.microsoft.com/en-us/office/vba/api/powerpoint.slideshowview.state
"newZoomFactor": Wn.Zoom,
"slides": Wn.Slide.Name,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSlideShowNextClick(self, Wn, nEffect):
"""
Occurs when the next slide in a presentation is clicked during a slideshow
https://docs.microsoft.com/en-us/office/vba/api/powerpoint.effect#properties
:param Wn: slideshowview https://docs.microsoft.com/en-us/office/vba/api/powerpoint.slideshowview
:param nEffect: transition type
:return: clickNextSlideshow event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint clickNextSlideshow ")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "clickNextSlideshow",
"title": Wn.SlideShowName,
"description": Wn.State,
# https://docs.microsoft.com/en-us/office/vba/api/powerpoint.slideshowview.state
"newZoomFactor": Wn.Zoom,
"slides": Wn.Slide.Name,
"effect": nEffect.EffectType,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSlideShowOnPrevious(self, Wn):
"""
Occurs when previous slide is clicked during a slideshow
https://docs.microsoft.com/en-us/office/vba/api/powerpoint.slideshowview.state
:param Wn: slideshowview https://docs.microsoft.com/en-us/office/vba/api/powerpoint.slideshowview
:return: previousSlideshow event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint previousSlideshow ")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "previousSlideshow",
"title": Wn.SlideShowName,
"description": Wn.State,
"newZoomFactor": Wn.Zoom,
"slides": Wn.Slide.Name,
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSlideShowEnd(self, Pres):
"""
Occurs when a slideshow ends
:param Pres: presentation
:return: slideshowEnd event
"""
screenshot = takeScreenshot()
print(
f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint slideshowEnd {Pres.Name} {self.getSlides()}")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "slideshowEnd",
"title": Pres.Name,
"event_src_path": Pres.Path,
"slides": self.getSlides(),
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnSlideSelectionChanged(self, SldRange):
"""
occurs when text selection on a slide changes
:param SldRange: range of slides
:return: SlideSelectionChanged event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Powerpoint SlideSelectionChanged")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Powerpoint",
"event_type": "SlideSelectionChanged",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs]def powerpointEvents(filename=None):
"""
Handle powerpoint events on windows using pythoncom.
:param filename: optional name of file to open
"""
try:
# needed for thread
pythoncom.CoInitialize()
# start new instance of Excel
e = DispatchWithEvents("powerpoint.Application", PowerpointEvents)
if filename:
# open existing document
e.Presentations.Open(filename)
else:
# create new empty document that contains worksheet
e.Presentations.Add()
runLoop(e)
print("[officeEvents] Powerpoint logging started")
if not CheckSeenEvents(e, ["OnNewPresentation", "OnWindowActivate"]):
sys.exit(1)
except Exception as e:
print(e)
[docs]class OutlookEvents:
"""
https://stackoverflow.com/questions/49695160/how-to-continuously-monitor-a-new-mail-in-outlook-and-unread-mails-of-a-specific
"""
[docs] def __init__(self):
self.seen_events = None
# First action to do when using the class in the DispatchWithEvents
# 6 is the inbox folder https://docs.microsoft.com/en-us/office/vba/api/outlook.oldefaultfolders
inbox = self.Application.GetNamespace("MAPI").GetDefaultFolder(6)
messages = inbox.Items
# Check for unread emails when starting the event
for message in messages:
if message.UnRead:
# Or whatever code you wish to execute.
print(message.Subject)
[docs] def OnStartup(self):
"""
Occurs when outlook starts
:return: startupOutlook event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Outlook startupOutlook")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Outlook",
"event_type": "startupOutlook",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnQuit(self):
"""
Occurs when outlook quits
:return: quitOutlook event
"""
screenshot = takeScreenshot()
self.seen_events["OnQuit"] = None
print(f"{utils.utils.timestamp()} {utils.utils.USER} Outlook quitOutlook")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Outlook",
"event_type": "quitOutlook",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
# stopEvent.set() #Set the internal flag to true. All threads waiting for it to become true are awakened
# To stop PumpMessages() when Outlook Quit
# # Note: Not sure it works when disconnecting!!
# ctypes.windll.user32.PostQuitMessage(0)
[docs] def OnNewMailEx(self, receivedItemsIDs):
"""
Occurs when a new mail is received
:param receivedItemsIDs: id of received mail
:return: receiveMail event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Outlook receiveMail")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Outlook",
"event_type": "receiveMail",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
# RecrivedItemIDs is a collection of mail IDs separated by a ",".
# You know, sometimes more than 1 mail is received at the same moment.
for ID in receivedItemsIDs.split(","):
mail = self.Session.GetItemFromID(ID)
subject = mail.Subject
print(subject)
[docs] def OnItemSend(self, Item, Cancel):
"""
Occurs when a new message is sent
:param Item: message
:param Cancel: true if action is canceled
:return: sendMail event
"""
screenshot = takeScreenshot()
print(Item)
print(f"{utils.utils.timestamp()} {utils.utils.USER} Outlook sendMail")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Outlook",
"event_type": "sendMail",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnMAPILogonComplete(self):
"""
Occurs when outlook checks for new mails
:return: logonComplete event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Outlook logonComplete")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Outlook",
"event_type": "logonComplete",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs] def OnReminder(self, Item):
"""
Occurs when there is a new reminder
:param Item: reminder item
:return: newReminder event
"""
screenshot = takeScreenshot()
print(f"{utils.utils.timestamp()} {utils.utils.USER} Outlook newReminder")
json_string={
"timestamp": utils.utils.timestamp(),
"user": utils.utils.USER,
"category": "MicrosoftOffice",
"application": "Microsoft Outlook",
"event_type": "newReminder",
"screenshot": screenshot
}
# Get supervision feature if active, otherwise returns None value
answer = supervision.getResponse(json_string)
json_string["event_relevance"] = answer
utils.utils.session.post(SERVER_ADDR, json=json_string)
[docs]def outlookEvents():
"""
Handle outlook events using pythoncom
"""
try:
# needed for thread
pythoncom.CoInitialize()
# start new instance of outlook
e = DispatchWithEvents("outlook.Application", OutlookEvents)
e.Presentations.Add()
runLoop(e)
print("[officeEvents] Outlook logging started")
if not CheckSeenEvents(e, ["OnNewPresentation", "OnWindowActivate"]):
sys.exit(1)
except Exception as e:
print(e)
def runLoop(ob):
while 1:
pythoncom.PumpWaitingMessages() # listen for events
try:
# Gone invisible - we need to pretend we timed out, so the app is quit.
if not ob.Visible:
print("Application has been closed. Shutting down...")
return 0
# Excel is busy (like editing the cell), ignore
except pythoncom.com_error:
pass
# return 1
def CheckSeenEvents(o, events):
rc = 1
for e in events:
if not e in o.seen_events:
print("ERROR: Expected event did not trigger", e)
rc = 0
return rc
# used for debug
if __name__ == '__main__':
args = sys.argv[1:]
print(f"Launching {args[0]}...")
if "word" in args:
wordEvents()
elif "excel" in args:
excelEvents()
elif "powerpoint" in args:
powerpointEvents()
elif "outlook" in args:
outlookEvents()