Print from Windows Service, no dialog, no user interaction - c#

I would like to print from a Windows Service in C# using Visual Studio 2010. So far, I have only been partially successful by using the code found here:
Print html document from Windows Service without print dialog
The current problem I am experiencing is two fold, which I have only discovered by allowing the service to interact with the desktop:
1) When the URL is entered in as the HTML location, it will request credentials for that location (a network shared IIS web server that I DO NOT have the ability to alter in any way, which requests a username and password to access the information).
2) After I enter credentials, the default printer is ALWAYS the XPS printer, no matter what I do to SetDefaultPrinter (two different ways I have found to do this). I have discovered this is because the printer I want to print to is also a network printer, which the Local System account cannot access (apparently). I have not found a way around this problem.
I would like to get around both of these problems by entering the credentials needed programmatically (this is a network share credential set) and then print to a network printer. In other desktop applications I have successfully printed to each of these network printers even though I do not have each one installed.
Attempting to log in using my credentials instead of the Local System account does not solve either problem. I am using Windows XP.
Assuming I get this to work, I will also need to install the service on another server, so if it is necessary to preinstall each printer I will need to know what steps to take to ensure the Local System account has access to them. The server I will install on will likely be a Windows Server 2003 or 2008, but will have the same network access as the development machine.
EDIT: I attempted a solution of having it Log on as other accounts, all of which should have credentials (and, in fact, if those credentials are entered when it is running as Local System with desktop interaction, those credentials are accepted). Each user that this has been attempted with has had the default printer set to the printer I am trying to test print to, but no print occurs. The only time I know for sure it is trying to use the XPS printer is when it is logged on as Local System with desktop interaction.

Don't run the service as Local System. It doesn't have the rights you need to access network resources. Create a user and run the service under that, if you're in a domain, make sure it's a domain user and not a local one. You will need to log on as that user and install the printers you want to use on the computer where your service runs. Also, if the IIS application is using Windows Authentication, see if the account you're running the service under can be granted permission to access the web application.

I had this issue, this trick solved it
Go to services ---> Double click the required service ---> proceed to logon tab
Supply the Log-in credentials from which printer was installed.
See screen shot below.

Related

IIS; print on shared printer with IUSR-user

I’m trying to print to a shared printer from a IIS Windows 10 server with the IUSR user. So far unsuccessful.
The print job works with every other user, so it must be the authorization. Local printers are no problem.
On the IIS-server PHP starts a little C# application for server side printing an image. The printer is a shared printer on another Windows 10 pc in the (privat) network. There is no domain controller or something like that.
I have tried so far:
Add network service permissions to the IUSR-user:
https://serverfault.com/questions/469944/how-to-add-network-service-to-users-permission-group/469961
Set up the shared printer to a local port:
https://superuser.com/questions/899808/add-network-printer-as-a-local-printer
Switch to other users with other permissions in the c#-print-applikation:
C# How to change user context in app running on system
None of it works. Does anyone have a good idea or workaround?

Get a list of mapped drives as a Windows service.

I'm trying to get a list of mapped drives on my machine as a Windows service. I can get a proper list if I run my code as a normal program, but not as a Windows service. I've seen several posts regarding this topic but none give a clear solution.
I'm running the service on the same account that created the service, and the service has admin rights.
Does anyone know how to properly do this?
It is not possible
please see the following MSDN article
https://msdn.microsoft.com/en-us/library/windows/desktop/ms685143%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
If a service is configured to run under a user account, the system always creates a new logon session for the user and starts the service in that new logon session. Therefore, a service cannot manage the drive mappings established within the user's other sessions.
If you are in Windows 7 with UAC enabled, then the administrative session has different mapped drives then the regular user session. Open an administrative command prompt and run net show and check the mapped drive status.
Update: I have EnabledLinkedConnections set on my Windows 10 workstation so I don't see this issue there.

Stand alone WPF application using a service ID or like

I've been asked to write a C# application to run on a Windows 7 machine to display the time of day, weather, etc.. That I can do. What I'm looking for is guidance to run the application on a Windows7 machine without logging as a user. In essence the machine would simply be a CPU with a screen. No keyboard or mouse. I've seen deployments done on MS-PixelSense (use to be MS-Surface) using a service ID.
If I need to signin, user policies kick in, screen savers enable, etc.. I'm assuming if I use an automatic Service ID, I can let the application override most of the settings keeping the screen on and needed privileges assigned / locked down to the service ID.
Any information / suggestions are appreciated....
First, some background informations:
Accessing a network share
If a process running on your client wants to access a (CIFS) share, it has to be run under a user account (or "Service ID") which has access rights to this share. There is a way (if the client is a member of Active Directory) that the machine name appended with $ (which is in fact the machine account’s name in AD) has to be entered in the ACL (Share / NTFS), but this is not a very "usual" way.
See also https://serverfault.com/questions/41130/network-service-account-accessing-a-folder-share
Windows Service running under a user account (aka technical account or Service ID)
A service running under a user account cannot access the GUI. There are some tricks, and some years ago I wrote a tool which allows a service to start another GUI program, where the GUI is displayed above the Ctrl-Alt-Del dialog. But this does not work under Windows 7 anymore.
But even a service which runs under local system cannot display a GUI on the logon screen.
You would have to write a Credential Provider.
See
Windows service showing a GUI when no user is logged in
https://stackoverflow.com/a/3074040/4547223
Another very deep technically article. It says it is possible to display a GUI on the secure desktop / logon screen. I have not yet tested this myself:
http://calebdelnay.com/blog/2012/01/displaying-a-program-on-the-windows-secure-desktop
Autologon
The most well known way is still the "classic" autologin.
See https://security.stackexchange.com/questions/10170/how-secure-is-windows-auto-logon for some explanations and links.
The medium secure way is to store the password as LSA secret (can be done in C# with P/Invoke or with some tools).
If I need to signin, user policies kick in, screen savers enable, etc.
Yes, but this can be handled, you probably have to create an own AD OU with an own policy for that.
I'm assuming if I use an automatic Service ID, I can let the application override most of the settings keeping the screen on and needed privileges assigned / locked down to the service ID.
A service ID /technical account is basically the same as a normal personal user account.
In some Active Directory enterprise environments a technical account has restrictions that it cannot log on interactively and other restrictions. But it still IS a "user account"
Logonexpert (http://www.logonexpert.com/)
I tested this (trial version). It is a nice, small tool which does it’s job. It is more safe than "normal autologon", however in the end, it is not much different from normal classic autologon. One benefit: it stores the password more recurely, but in theory, some hacker may still decompile the program and find out a way to decrypt it. And more important for you: Beside the more safe password store, it does not gain you much. You still have a user login same as normal autologon.
A few suggestions
Probably you can use a local user account on the client system and use normal autologon mechanism. And then you should consider that the client system does not poll for new data on a network share, but instead another server program (implemented as a service, running under a technical domain account) pushes data on a network share on the client.
Doing it this way, the client code does not need to access network shares, with the benefit, that a malicious attacker also has no access to network shares.
If you really need to access a network share from the local user context, you can probably logon to the server, as explained in my answer here:
https://stackoverflow.com/a/28749093/4547223
You have to to change the registry code part with the access to the CIFS share.
But doing it this way, you again have a password, which you have to encrypt and store. I do not recommend this.
In the end...
Windows does not make it easy what you want to do. If you are not strictly bound to Windows, you can consider using a Raspberry Pi with Raspbian (a Debian derived Linux). You can install Chromium browser, which displays a web page on the server and updates automatically. We use this with great success for some time.

Access to a Sharepoint Remote Folder from C#

I have developed an ASP.NET MVC 3 which must access to a SharePoint Remote Folder.
To do that, during the development, before to run the Visual Studio Development Server, I try to access to the remote folder. Then, I must introduce the credentials of the user who has permission to see the remote resource. After this, using the following code:
string path = #"\\tests.sharepoint.es\folder1";
DirectoryInfo di = new DirectoryInfo(path);
DirectoryInfo[] dis = di.GetDirectories();
The access to the folder is successful. However, this fails when I executed my web application from the IIS, getting the next error:
Access to the path '\tests.sharepoint.es\folder1\' is denied.
Even if I set for the Application Pool the same user that runs the Visual Studio Development Server, it continues failing.
I have identified that the users who runs the World Wide Web Publish Service (W3SVC) is SYSTEM (an account who obviously doesn't have permission to access to the folder) but I can't change this and I am not sure if this causes the problem.
Also, I have read some posts about using SPSecurity.RunWithElevatedPrivileges but I can't use it because my IIS server doesn't have Sharepoint installed (it is in another machine) and therefore, I can't use Microsoft.Sharepoint.dll as far as I know.
UPDATE: When I try to access to the resource using my windows explorer, I have read that OS uses WebDav instead of NetBios. Can IIS use this protocol to access to the resource?
If you really need to access remote resource with Windows permissions from Windows web server (or any other server that impersonates remote client) than you must run such code under account directly signed in on the server box. This is caused by "NTLM one hop" policy - user's credentials can be used only on machine user directly signed in to or machine user directly communicates to (and not on third one that this second machine tries to connect to).
Safest approach is to run process under account that have access to remote resource and run code in that process. You can run IIS process under such account, but you may need to revert impersonation back to process if running code during requests.
You can also directly impersonate particular user but you'll need to have plain text login information. This is most likely against security policy for most companies.
Note: you very well may end up building anonymization proxy - be very careful to understand what it means to access remote resource under account different from actual user's account.
Fortunately, I have found how to resolve the access problem.
I have used the solution described in this post.
My code seems like this:
PinvokeWindowsNetworking.connectToRemote(#"\\tests.sharepoint.es\folder1", "domain\user", "password");
//manage files and folders of my remote resource
//...
PinvokeWindowsNetworking.disconnectRemote(#"\\tests.sharepoint.es\folder1");

Installing a Windows Service as a user

I'm currently in the process of creating a Windows service application which will monitor changes to certain keys made in the HKEY_USERS registry. The way I do this is by collecting the SID of the current user. The issue I'm having is that its returning the administrators SID due to the service currently running as local system.
What I need the system to do is collect and return the SID of the currently logged in user (by this I dont mean the local service, local system or network service but the person whos logged into windows via the GINA), so what I need the service to do is run as that user. This will also allow the service to write back to the users network drive which is the intention of this program.
The issue I'm having is that when I try and install a user service using installutil.exe it asks for a username and password now I've tried my own credentials (I have an admin and non admin account) but it isn't having any of it plus I want the user to change depending on the person logging on and not to be fixed. Is there any way to do this?
The "The current user" assumption is a desktop Windows concept, and with Fast User Switching even that is not true anymore. The Windows services layer is rather common across desktop and server variants, and doesn't really deal well with this. It sits below the interactive sessions layer. One of the ways this manifests itself is in the ability to run services even if there are zero users logged in.
This all seems a bit confused. There can be any number of people logged on via remote desktops etc. If you as a service want to see their registry, you definitely wont get there via HKCU. If you want something like this, you should be using an autorun exe rather than a service. Anything like inspecting sessions and injecting stuff into them to access the loaded registry hive in the session is way overkill and not likely to be clean in any way.
You can find a process that runs with every user like explorer.exe then get the SID of the user that runs the process (you can use WMI like in the function here)

Categories