Programmatically determine user who last modified file on Windows? - c#

I've been tasked with writing a simple command line utility in C# that will monitor a directory on a server that several users will be accessing to copy/cut/paste/view data. I used FileSystemWatcher to do this but it's lacking a couple features.
Is it possible to determine the user or at least the computer name from where the file is being accessed/modified?
(Note: This doesn't have to be with FileSystemWatcher, I'm looking for ANY way to do this.)

I don't think you'll be able to monitor this from C# directly. Not without the help of the host operating system anyway. Windows and NTFS allow you to audit a particular directory and log the accesses in the Security event log for the host machine (so the server hosting the share would have to audit, not the client).
From KB310399 - How to audit user access of files, folders, and printers in Windows XP
Auditing User Access of Files, Folders, and Printers
The audit log appears in the Security log in Event Viewer. To enable this feature:
Click Start, click Control Panel, click Performance and Maintenance, and then click Administrative Tools.
Double-click Local Security Policy.
In the left pane, double-click Local Policies to expand it.
In the left pane, click Audit Policy to display the individual policy settings in the right pane.
Double-click Audit object access.
To audit successful access of specified files, folders and printers, select the Success check box.
To audit unsuccessful access to these objects, select the Failure check box.
To enable auditing of both, select both check boxes.
Click OK.
Specifying Files, Folders, and Printers to Audit
After you enable auditing, you can specify the files, folders, and printers that you want audited. To do so:
In Windows Explorer, locate the file or folder you want to audit. To audit a printer, locate it by clicking Start, and then clicking Printers and Faxes.
Right-click the file, folder, or printer that you want to audit, and then click Properties.
Click the Security tab, and then click Advanced.
Click the Auditing tab, and then click Add.
In the Enter the object name to select box, type the name of the user or group whose access you want to audit. You can browse the computer for names by clicking Advanced, and then clicking Find Now in the Select User or Group dialog box.
Click OK.
Select the Successful or Failed check boxes for the actions you want to audit, and then click OK.
Click OK, and then click OK.
The process is similar for the server operating systems and Windows Vista/Windows 7. If you go this route, you can have the C# program read the event log (See EventLog class) to look for the data you want.
Note: Starting with vista you must be and (UAC elevated if needed) administrator to read them from code.

Make sure to have WMI installed or enabled on your PC, also make sure to add a reference to System.Management and System.Management.Instrumentation as well. There is also a C# and VB WMI scripting application GUI that you can download to run and test WMI Queries against as well Google that one. Since I work for Dept of Defense there are certain things that I can get to from here in regards to the web other things are blocked out so please forgive me if I don't post certain web links.
Here is something to get you started
ManagementScope mgtScope = new ManagementScope("\\\\ComputerName\\root\\cimv2");
// you could also replace the username in the select with * to query all objects
ObjectQuery objQuery = new ObjectQuery("SELECT username FROM Win32_ComputerSystem");
ManagementObjectSearcher srcSearcher = new ManagementObjectSearcher(mgtScope, objQuery);
ManagementObjectCollection colCollection = srcSearcher.Get();
foreach (ManagementObject curObjCurObject in colCollection)
{
Console.WriteLine(curObjCurObject["username"].ToString());
}
//if you want ot get the name of the machine that changed it once it gets into that Event change the query to look like this. I just tested this locally and it does work
ManagementObjectSearcher mosQuery = new ManagementObjectSearcher("SELECT * FROM Win32_Process WHERE ProcessId = " + Process.GetCurrentProcess().Id.ToString());
ManagementObjectCollection queryCollection1 = mosQuery.Get();
foreach (ManagementObject manObject in queryCollection1)
{
Console.WriteLine("Name : " + manObject["name"].ToString());
Console.WriteLine("Version : " + manObject["version"].ToString());
Console.WriteLine("Manufacturer : " + manObject["Manufacturer"].ToString());
Console.WriteLine("Computer Name : " + manObject["csname"].ToString());
Console.WriteLine("Windows Directory : " + manObject["WindowsDirectory"].ToString());
}

Related

Why is my mapped network drive not appearing in Network Locations?

I'm using Windows 10. Here is my code to map the network drive.
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = true;
p.StartInfo.Verb = "runas";
p.StartInfo.FileName = "net.exe";
p.StartInfo.Arguments = "use Z: " + dPath; //dPath has escaped characters
p.Start();
What I was trying to do was trying to run the command net.exe use Z: DPATH as administrator but the Z drive does not appear in File Explorer but when I run the exact same command using cmd with Admin rights, the Z drive appears correctly.
Proof of mapped drive
My Network drive is mapped as evidenced below (Encountered this error when trying to re-map it manually) just that it wasn't appearing under Network Locations in File Explorer > This PC.
This behaviour is caused by UAC (User Account Control). When logging on to Windows as an admin, there are two sessions created. One with admin rights and one without. When you map the drives programmatically, you are doing it with the session with admin rights.
However, when you use File Explorer to view the Network Locations, you are using standard rights. For mapped drives, the admin and standard rights are not shared. Hence, the admin is not able to view the mapped drive eventhough it was created with admin rights.
Solution 1
Click Start, type regedit in the Start programs and files box, and
then press ENTER.
Locate and then right-click the registry subkey
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System.
Point to New, and then click DWORD Value.
Type EnableLinkedConnections, and then press ENTER.
Right-click EnableLinkedConnections, and then click Modify.
In the Value data box, type 1, and then click OK.
Exit Registry Editor, and then restart the computer.
Solution 2
Run File Explorer as administrator
When making a right click on the Explorer and select "Run as
administrator" it doesn't start the Windows Explorer with admin
rights. The Windows Vista/7/8/10 Explorer includes a special function to
block such requests.
To disable it, start regedit.exe and go to the following key:
HKEY_CLASSES_ROOT\AppID{CDCBCFCA-3CDC-436f-A4E2-0E02075250C2}
make a right click on Permissions and set your user as owner of the key and
give your current user writing permissions.
Next, delete or rename the value RunAs. Now the Elevated-Unelevated
Explorer Factory is disabled and you can start the Explorer with admin
rights.
Solution 3
If the above can't work, disable your UAC (User Account Control) by going into User Account Control Settings and moving the slider to Never notify
Also, if you have Professional, Enterprise, or Ultimate version of windows installed, you need to look into a program in Administrative tools called Local Security Policy and disable all the policies related to UAC in Security Settings > Local Policies > Security Options (Located in the bottom 15 policies of the list)
It helped me restarting explorer.exe with admin rights via Task Manager.

Using C# code to set internet options [duplicate]

Any idea how do I do the following using C#?
Going to Tools -> Internet Options -> Security
Select the Security tab
Click the Custom Level button
In the Miscellaneous section change Display mixed content to Enable
The "cheat" way to do this is to change the value
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet
Settings\Zones\0\1609
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet
Settings\Zones\1\1609
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet
Settings\Zones\2\1609
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet
Settings\Zones\3\1609
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet
Settings\Zones\4\1609
Where 0-4 are Zone identifiers and the value is 0 to Allow, 1 to Prompt, and 3 to Block. Keep in mind that if your code does this on anyone's machine but your own, you're likely to find your code blocked as malware.
The "proper" way to do this is to use the APIs to create an IInternetZoneManager and call SetZoneActionPolicy to adjust the settings for URLACTION_HTML_MIXED_CONTENT in the zones you want to adjust.
You aren't supposed to do this "programmatically". That's why there isn't an API for it. Only the user can change their security settings, and they do it using the built-in interface that you've already discovered.
The poor IE team has been working overtime trying to tighten up the security of their browser. They're not going to throw in something like this that would nullify all of their efforts in a matter of seconds.
Recall that even once this option is selected, there's a confirmation dialog presented. How do you propose to "click" that programmatically? (Hmm, on second thought, don't tell me. That's probably the next question you'll be asking.)
Give up on trying to do this programmatically, and ask the user to do it themselves. Provide a complete help file or other documentation that explains why you're requesting that they make this change, what features will be unavailable if they do not choose to make this change, and what the possible security risks of making such a change are. And, of course, specific instructions on how the change is made.
Or, better yet, redesign your app so that it doesn't require a system-wide modification of IE's security settings. It's hard to imagine a legitimate case for this. A better solution might be asking the user to add your site to their "trusted sites". Remember that local pages have different security settings than remote pages by default.
Also do not forget Group Policies. Most (if not all) IE settings may also be specified in Group Policies.
According to Local group policy setting for IE security page vs Internet options security page
the Group Policy settings override user-defined settings.
So, on my home PC (works without domain controller) I have a choice to define IE settings either via Local Group Policy Editor or via Internet Options. For example, if I run gpedit.msc to open Local Group Policy Editor, select
Computer Configuration\Windows Components\Internet Explorer\Internet Control Panel\Security Page\Internet Zone
change "Display mixed content" setting to "Enabled", then select "Enable" in drop down box, click Apply,
then open Security Settings for Internet Zone in IE - I will see that "Display mixed content" changed to Enable and
the selection is disabled because it is overriden by Policy.
For the entire list of supported policies download WindowsServer2012andWindows8GroupPolicySettings.xlsx
from
http://www.microsoft.com/en-us/download/details.aspx?id=25250
Now back to the question how to change settings programmatically.
EricLaw correctly suggested using SetZoneActionPolicy from IInternetZoneManager.
But it is hard to find samples for calling it from C#.
I ended up copying
http://www.pinvoke.net/default.aspx/Interfaces.IInternetZoneManager
into my code and then doing:
//This will disable "Download signed ActiveX" (IE setting # 0x1001) for Internet Zone (zone #3)
IInternetZoneManager izm = Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("7b8a2d95-0ac9-11d1-896c-00c04Fb6bfc4"))) as IInternetZoneManager;
IntPtr pPolicy = Marshal.AllocHGlobal(4);
Marshal.Copy(new int[] { 3 }, 0, pPolicy, 1);//3 means "Disable"
int result = izm.SetZoneActionPolicy((uint)UrlZone.Internet, (uint)0x1001, pPolicy, 4, (uint)UrlZoneReg.CurrentUserKey);
Marshal.ReleaseComObject(izm);
Marshal.FreeHGlobal(pPolicy);
I also tried changing group policy programmatically.
I used library from
https://bitbucket.org/MartinEden/local-policy
and then:
//This will disable "Download signed ActiveX controls" computer policy for Internet Zone (zone #3)
const string keyPath = #"SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3";
var gpo = new LocalPolicy.ComputerGroupPolicyObject();
using (var machine = gpo.GetRootRegistryKey(LocalPolicy.GroupPolicySection.Machine))
{
using (var terminalServicesKey = machine.CreateSubKey(keyPath))
{
terminalServicesKey.SetValue("1001", 3, Microsoft.Win32.RegistryValueKind.DWord);
}
}
gpo.Save();
After successfully testing the code above on Win7 SP1 with IE 11 I decided to go back to the original suggestion from EricLaw: modify
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\*\1001
directly because this is what Microsoft is recommending. See, for example How to strengthen the security settings for the Local Machine zone in Internet Explorer or Enhanced Browsing Security
I am not sure but I think you can find all these settings in "registry". You need to find out the appropriate key. And to change those values you need to have proper rights. Registry can be accessed from .net code

WPF app writes files/data into "C:\ProgramData" but fails to write into other folders

We have developed WPF application which allows user to select folder path. WPF application writes files/data into this selected path. When we select "C:\ProgramData" as the path, it creates the file and write the data. But when the path is other than "C:\ProgramData", file is generated but data is not written into the file and it seems a permission issue. Can anybody help us in finding out , how we can assign the same kind of permission to selected folder same as "C:\ProgramData" so that it allows to write data into the file. In conclustion what is the extra permission does "ProgramData" has which is not their for other folders?
Note: it only works properly with ProgramData folder.
Whenever your application is launched with standard user rights, it can write to only those folders to which a standard user can write to. E.g. are:
C:\Users\USERNAME\
C:\ProgramData\
D:\
It will not be able to write to folders like:
C:\
C:\Users\SOME_OTHER_USERNAME\
c:\Windows
C:\Windows\System32 etc
For that you either need to disable UAC or launch the application with administrative permissions.
I would suggest that whenever user selects a folder from your application check if you can create a file/ folder in that location before accepting the path.
solution what i can give is let's user select the path after you get the folder path just check whether you can write data to it , see this code
bool HasAccessToWrite(string path)
{
try
{
using (FileStream fs = File.Create(Path.Combine(path, "Access.txt"), 1, FileOptions.DeleteOnClose))
{
}
return true;
}
catch
{
return false;
}
}
#Ganesh is right but you may go with one of the following options:
Run the installer with admin rights, ask user to select target folder during installation and set the permissions to everyone or required groups of users/roles.
If above is not applicable then configure your application to always run under admin account, in that way it will have access to all folder to write data. To configure run as admin user application manifest as explained here:
Turn off UAC, not a recommended approach though.
I had same issue so, I forced installer to be run under admin rights and asked user to create target folders during installation. Used a custom action to set full rights for everyone user group on the target folder. Since security was not issue for us so, it was ok to allow everyone but consider your environment before using this option.

Set write permission on folder create

Hi I have been trying to properly configure IIS 6 to give write permisiosn for about 2 days now and I can't seem to find any good resource on this.I am a bit new to ASP.NET and until now I never had to work with IIS.
What I am trying to do is upload a file to the server.Each user on the server will have his own special folder witch will be created automaticly via C#.Now when I try to upload the file I get this error:
Access to the path 'D:\Projects IDE\Visual Studio\MyWork\Websites\Forum\Images\avatar\userAvatars\aleczandru' is denied
This is my code for creating the folder for each user and saving the file:
private void addImageToApp()
{
string path = "~/Images/avatar/userAvatars/" + User.Identity.Name;
createPath(path);
if( Directory.Exists(HostingEnvironment.MapPath(path)))
{
try {
UploadImage.SaveAs(HostingEnvironment.MapPath(path));
MultiViewIndex.ActiveViewIndex = 0;
}catch(Exception ex)
{
AvatarDetails.Text = ex.Message;
}
}
}
private void createPath(string path)
{
string activeDir = HostingEnvironment.MapPath("~/Images/avatar/userAvatars");
if( !Directory.Exists(Server.MapPath(path)) )
{
string newPath = Path.Combine(activeDir, User.Identity.Name);
Directory.CreateDirectory(newPath);
}
}
All I could find on the internet is that I have to add write permision via folder/properties/security/... while that is all good and fine I can not do this for each folder.
Up to this point I am not really sure that IIS is the one I need to configure I am a bit lost at this.
What do I have to do to give folders write permisions automaticly on folder create?
And if anyone has a good article or tutorial that shows how to do this please share it with me all the info I could find were very basic.
EDIT
I have added the network service account to the Images folder with full permision and have set the application's pool Identity to NetworkService but I still get the same error
EDIT
I have messed around with SQL-SERVER for the last couple of days in order to make this work so I might have missconfigured something form what I understand NETWORK SERVICE is stored in SQL-SERVER master.db database.I seem to be having two network service logins may this be the problem?I remember when I first checked it I had none now I have two:
Simply, when your asp.net application running you can open Task Manager and find process w3wp.
W3wp process like any other has user identity (by default - application pool identity - DefaultAppPool(like application pool name)).
And if it so, you should add write permissions for user named DefaultAppPool. To do it you should open security tab in folder's properties window, then change->add and type IIS AppPool/DefaultAppPool and choose local machine.
This post should help you!
This has nothing to do with IIS, brother. All you need to do is, open your IIS. Go to Application Pool. Right click on the Application Pool your website is running with. Select "Advanced Settings" and see the entry made against IDENTITY. Change it to use NetworkService. This will mean that you will be running your website under NETWORK SERVICE account now on.
Now right-click your root images folder, i.e., "Images". Select PROPERTIES. Select SECURITY. Add user NETWORK SERVICE, and give it FULL RIGHTS permissions on the folder.
Now whenever you create a folder and file under this "Images" folder through your code, it will automatically inherit permissions from its parent and you will allow you to do whatever you want (Add/Delete).
I hope this answers your question. If yes, then please mark it as "answered".

How do I give my windows service admin rights

I have a winform that allows me to enable and disable all my 8 year old's network adapters using this code:
protected override void OnStart(string[] args)
{
//start timer
SelectQuery query = new SelectQuery("Win32_NetworkAdapter","NetConnectionStatus=2");
ManagementObjectSearcher search = new ManagementObjectSearcher(query);
foreach (ManagementObject result in search.Get())
{
NetworkAdapter adapter = new NetworkAdapter(result);
adapter.Disable();
enabled = false;
}
InternetCheckTimer.Start();
}
This code works fine on a win form assuming I am running with admin. I have never written a win service before so the problem might be else where, I am able to install using installutill and attach the debugger to the process, however no break points are hit. I have tried starting and stopping the process and cannot get the debugger to attach so I might be doing that wrong as well... Right now I am assuming that the code is running and I am too stupid to get the debugger working. That said, I think my code requires the service to have admin like the form did in order to work.
Sorry if this is unclear, I will do my best to clear it up if you need more information.
Use user and password for the service, and assure that the user that start the service has all rights needed for the application to run.
An other possibility if you can control the service is to use impersonation, see: http://www.codeproject.com/Articles/4051/Windows-Impersonation-using-C.
You can try couple of options.
Add app.manifest
After installing window service set the service permission to run at Highest Privilege and also you can set the user name and password for the logged in user.
How to Get Full Administrator Rights in Windows 7:
Click Start
Click Computer (you might also find this icon on the desktop).
Right click on the Hard Disk icon where your OS is installed on and click Properties.
Click the Security tab.
Click the Advanced tab.
Click the Change Permissions button located after the Permission Entries list.
A new window will appear on your screen; which contains a list of all the User Accounts
Select the user account you want to give total control over your Windows 7) and click the Edit button.
Now, tick the checkbox labeled "Total Control" and press OK.
You're all done!

Categories