This is a rather off topic post intended for developers.
Windows family of operating systems has been the primary choice of enterprise users for long time. Even tough Cloud is growing, mobile and BYOD is the trend we seem to continue using PCs for everyday office work in foreseeable future. Macs are wide spread but still a minority and proliferation of desktop Linux has never happened contrary to server Linux. This lefts us with good old Windows with all the goodies like Active Directory and years of (good or bad) experience. This makes MyDLP Endpoint Agent for Windows an indispensable part of MyDLP which we have developed and intended to develop for years. We put serious effort to make it stable and continue to add shiny features onto it with lots off juggling.
If you are developing a system application which is not about a simple application with a window or a simple .Net service, believe me my friend, you are entering a world of pain! It seems every API, every subsystem tries to put you down in a new and creative way. I was thinking about writing this for a long time I forgot about most of the frustration moments, but here are some below.
Restart Manager is the ultimate answer of Microsoft to continuously rebooting Windows machines at each package installation and update. It was introduced with the second most favorite Windows of ours, Windows Vista. Most favorite one is Windows Millennium Edition of course. It has been more than six years and two new Windows version I have not seen slightest improvement in unnecessary reboots.
This smart guy is responsible for automatic shut down of application and services to release used files so we can happily continue installing our MSI packages. It does this automatically before InstallValidate action. The problem with it if your service spawns processes that use files it can not keep track of processes without a Window handle(more on that later) or a Windows service. So it decides that there are critical system applications using files to be changed by installer and displays annoying reboot message dialog. These critical system applications are actually offspring of our service to installed, removed or upgraded. The sad side there is explicit definition of services to be stopped ServiceControl table and if it did honor that settings everything would be okay. We use WIX to author our MSI package, which is a great project but naturally has the limitations of Windows Installer. How we solved it? We disabled the Restart Manager during installation of package of course, there was no other way I can see. There are Erlang VM, Java VM and all other things they also spawn. I should not have to make everything another Windows Service.
Actually above process was not simple as I told you. Another issue was the verbose log of the msiexec command. Restart Manager which has the ability of predicting future and making smart decisions logged the following entry for blocking files: “RESTART MANAGER: Did detect that a critical application holds file[s] in use, so a reboot will be necessary”. It could be kind and at least tell me the process or files which are locked.
Finding Current User
It is simple “$ who”. Sorry our subject is not .nix. If you have a service running with LocalSystem account it is hard to find out who is using the machine if not a black art. If you do not have Terminal Server license there can be only one user actively using a Windows machine, so it should be simple. Wrong!. First approach one can think of is to find logon sessions using LsaEnumerateLogonSessions and determine the current user, which is not possible. Fortunately SECURITY_LOGON_SESSION_DATA structure does have lots of information including LogonTime, LogoffTime(which is not supported before Windows 7 which is a show stopper for backward compatibility). Unfortunately it is useless for this purpose, it shows incorrect time when fast user switching is enabled, or another user RDP suspending current user session. Practically it shows active credentials not the users connected. So we need to find another way. WTSGetActiveConsoleSessionId can be used to find the session but it consistently shows false session ID if someone is connected with RDP. The solution is to WTSEnumerateSessions to get all sessions, check if one of them is active, this unexpectedly shows the correct active session ID contrary to previous function who should do the same thing and use WTSQuerySessionInformation to get the username. But I also needed SID of user so go back to Logon sessions and get the matching user and session with SID information.
Window Handler Fetish
We have a unique and pretty good printer DLP feature in MyDLP. To make it working was not pretty. If you happen to install a printer driver from a service forget about it. DLL to install a printer driver is even named as PrintUI.DLL. It is somehow working properly in Windows 7 from a service but fails miserably on Windows XP. We have a .bat file that needs to manually run on manual installs or triggered via startup script in GPO if you want to use printer DLP features on Windows XP. Printing some document in a service is also very entertaining only working in an undocumented way because almost all printing functions like many other functions in Win32 API or .Net requires an application Window Handle.
If you want to listen some device change event with WM_DEVICECHANGE you need a Window Handle to register a callback. How can a service has right to listen device changes? You have to go through the WMI pooling stuff. Why? I really don’t know.
These were just the recent few issues. If you see any errors above please contact me, I would be happy to correct. If you have any ideas or know better methods checkout MyDLP-EP-Win project source code on GitHub.