Do Win32_Printer methods work from server against local machine? - c#

I recently made a c# printer management tool that uses a WCF service which contains WMI Win32_Printer methods like AddPrinterConnection and SetDefaultPrinter.
Everything works fine if both the client and the WCF service run on the same machine. But if i try to move the WCF service on another machine, the methods stop working but nothing crashes.
The AddPrinterConnection for example returns 0 which means success but no printer is really added on the local machine. The default printer even if is set to default returns false, etc. The printers list is somehow accesible.
The WCF service behaves the same even if is hosted in IIS with an administrator identity for the application pool or hosted in ASP development server on the server.
But with the same identity on the local machine all is fine. The printer name and local machine address are sent as parameters to the WCF methods.
Is this a rights, delegation or impersonation issue? Is this a limitation of the WMI? Does anyone encountered this problem? I really need a solution for this. Thank you in advance.
EDIT: Here is some code representing the function called on the WCF service that adds a printer.
Note: On both local instalation (client and service local) and remote (client local, service remote) the function returns 0, which means "success" and no error but in the second case nothing is really added.
I tried all kind of impersonations too, and as i said the identity under which the WCF service runs is the same as the user that uses the client. I supose is a thing related to the user context, because it doesn't make much sense. I tried to find some information from Microsoft regarding this but with no luck.
public static string AddPhysicalPrinter(string sPrinterName, string address)
{
try
{
ConnectionOptions options = new ConnectionOptions();
options.Impersonation = ImpersonationLevel.Impersonate;
options.Authentication = AuthenticationLevel.PacketPrivacy;
options.EnablePrivileges = true;
options.Username = "username";
options.Password = "password";
oManagementScope = new ManagementScope(new ManagementPath("\\\\" + address + "\\root" + "\\cimv2"), options);
oManagementScope.Connect();
ManagementClass oPrinterClass = new ManagementClass (new ManagementPath("Win32_Printer"), null);
ManagementBaseObject oInputParameters = oPrinterClass.GetMethodParameters("AddPrinterConnection");
oInputParameters.SetPropertyValue("Name", sPrinterName);
ManagementBaseObject x = oPrinterClass.InvokeMethod("AddPrinterConnection", oInputParameters, null);
foreach(PropertyData p in x.Properties)
{
switch ((UInt32)p.Value)
{
case 0:
return "has been added successfuly";//success
case 5:
return "access denied";//access denied
case 1801:
return "invalid printer name";//invalid printer name
case 1930:
return "incompatible printer driver";//incompatible printer driver
default:
return "unknown error";
}
}
return "unknown error";
}
catch (Exception ex)
{
return "exception caught";
}
}

After some research i found out that it is not possible to do that from a third machine. It must be done with a local logon.

Related

C# connect to remote server using Microsoft Terminal Services Active Client (RDP)

I have a piece of code that should connect to the server. The code is as following:
var rdp = new MsRdpClient8NotSafeForScripting();
rdp.Server = "192.168.0.101"; //adress
rdp.Domain = "localdomain"; //domain
rdp.UserName = "test"; //login
rdp.AdvancedSettings8.ClearTextPassword = "123456";//password
try
{
rdp.Connect();
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.WriteLine(rdp.Connected);
if (rdp.Connected != 0)
{
rdp.Disconnect();
}
Console.ReadLine();
This is supposed to "connect" to my remote server via 3389 port so that I can be able to read a file from my desktop which is called: "min.txt"
So far I have tried specifying the login data of my server but I always just get output of "0" in the console's window, regardless of whether I specify correct or incorrect login data..
My questions here are:
Why is it connecting even with wrong login data (ip, user + password)
How can I, once I've been indeed successfully connected to the server, access the min.txt file on my remote server, which is located at desktop...
Can someone help me out?
Probably you can try specifying the password like below:
MSTSClib.IMsTscNonScriptable secured = (MSTSClib.IMsTscNonScriptable)rdp.GetOcx();
secured.ClearTextPassword = “123456”;
For reference: MSDN link is here
Once connected, you can access the file like a shared network file via UNC.
Example:
System.IO.FileStream stream = System.IO.File.OpenRead("\\servername\sharedname\path\somefile.txt");
Then need to ensure that permissions are in place to access the folder.

LDAP search fails on server, not in Visual Studio

I'm creating a service to search for users in LDAP. This should be fairly straightforward and probably done a thousand times, but I cannot seem to break through properly. I thought I had it, but then I deployed this to IIS and it all fell apart.
The following is setup as environment variables:
ldapController
ldapPort
adminUsername 🡒 Definitely a different user than the error reports
adminPassword
baseDn
And read in through my Startup.Configure method.
EDIT I know they are available to IIS, because I returned them in a REST endpoint.
This is my code:
// Connect to LDAP
LdapConnection conn = new LdapConnection();
conn.Connect(ldapController, ldapPort);
conn.Bind(adminUsername, adminPassword);
// Run search
LdapSearchResults lsc = conn.Search(
baseDn,
LdapConnection.SCOPE_SUB,
lFilter,
new string[] { /* lots of attributes to fetch */ },
false
);
// List out entries
var entries = new List<UserDto>();
while (lsc.hasMore() && entries.Count < 10) {
LdapEntry ent = lsc.next(); // <--- THIS FAILS!
// ...
}
return entries;
As I said, when debugging this in visual studio, it all works fine. When deployed to IIS, the error is;
Login failed for user 'DOMAIN\IIS_SERVER$'
Why? The user specified in adminUsername should be the user used to login (through conn.Bind(adminUsername, adminPassword);), right? So why does it explode stating that the IIS user is the one doing the login?
EDIT I'm using Novell.Directory.Ldap.NETStandard
EDIT The 'user' specified in the error above, is actually NOT a user at all. It is the AD registered name of the computer running IIS... If that makes any difference at all.
UPDATE After consulting with colleagues, I set up a new application pool on IIS, and tried to run the application as a specified user instead of the default passthrough. Exactly the same error message regardless of which user I set.
Try going via Network credentials that allows you to specify domain:
var networkCredential = new NetworkCredential(userName, password, domain);
conn.Bind(networkCredential);
If that does not work, specify auth type basic (not sure that the default is) before the call to bind.
conn.AuthType = AuthType.Basic;

SSRS Report Portal Management

I am working on an C# utility that would help clients publishing SSRS reports on their sites. Here my code:
public void createFolder()
{
ReportingService2010 rs = new ReportingService2010();
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
// Create a custom property for the folder.
Property newProp = new Property();
newProp.Name = "Department";
newProp.Value = "Finance";
Property[] props = new Property[1];
props[0] = newProp;
string folderName = "Budget";
try
{
rs.CreateFolder(folderName, "/", props);
Console.WriteLine("Folder created: {0}", folderName);
}
catch (SoapException e)
{
Console.WriteLine(e.Detail.InnerXml);
}
}
I am getting the following error:
ErrorCode xmlns="http://www.microsoft.com/sql/reportingservices">rsAccessDenied</ErrorCode><HttpStatus xmlns="http://www.microsoft.com/sql/reportingservices">400</HttpStatus><Message xmlns="http://www.microsoft.com/sql/reportingservices">The permissions granted to user 'NT AUTHORITY\NETWORK SERVICE' are insufficient for performing this operation.</Message><HelpLink xmlns="http://www.microsoft.com/sql/reportingservices">https://go.microsoft.com/fwlink/?LinkId=20476&EvtSrc=Microsoft.ReportingServices.Diagnostics.Utilities.ErrorStrings&EvtID=rsAccessDenied&ProdName=Microsoft%20SQL%20Server%20Reporting%20Services&ProdVer=13.0.1601.5</HelpLink><ProductName xmlns="http://www.microsoft.com/sql/reportingservices">Microsoft SQL Server Reporting Services</ProductName><ProductVersion xmlns="http://www.microsoft.com/sql/reportingservices">13.0.1601.5</ProductVersion><ProductLocaleId xmlns="http://www.microsoft.com/sql/reportingservices">127</ProductLocaleId><OperatingSystem xmlns="http://www.microsoft.com/sql/reportingservices">OsIndependent</OperatingSystem><CountryLocaleId xmlns="http://www.microsoft.com/sql/reportingservices">1033</CountryLocaleId><MoreInformation xmlns="http://www.microsoft.com/sql/reportingservices"><Source>ReportingServicesLibrary</Source><Message msrs:ErrorCode="rsAccessDenied" msrs:HelpLink="https://go.microsoft.com/fwlink/?LinkId=20476&EvtSrc=Microsoft.ReportingServices.Diagnostics.Utilities.ErrorStrings&EvtID=rsAccessDenied&ProdName=Microsoft%20SQL%20Server%20Reporting%20Services&ProdVer=13.0.1601.5" xmlns:msrs="http://www.microsoft.com/sql/reportingservices">The permissions granted to user 'NT AUTHORITY\NETWORK SERVICE' are insufficient for performing this operation.</Message></MoreInformation><Warnings xmlns="http://www.microsoft.com/sql/reportingservices" />
Any idea?
Please note that a point of this exercise is not just get it work but knowing that it is going to run on a client side ideally without any tweaking on their part.
Thanks for help.
Your question is a little unclear. It sounds like you're not sure why you're getting a permissions error. The answer is that you need to create a new role. I assume (after your comment) that your question is how you can do that using C#.
You can use the CreateRole() method, which will only work with SSRS Native Mode. If SSRS is installed in SharePoint Integrated mode, there is no supported method other than using the UI.
This method throws an OperationNotSupportedSharePointMode exception
when invoked in SharePoint mode

check status application pool iis7 with csharp (access-denied)

I need to monitor the status of an application in the applications pool of IIS 7 from another machine on the same domain. My monitoring application must be in C# and running as a Windows service.
On my server, I create a user with administration rights and I execute the command aspnet_regiis -ga machine\username which worked successfully.
My problem is when I try to access the application pool I still get COMExcepttion "Access denied".
What did I do wrong or which step did I miss?
I used code from http://patelshailesh.com/index.php/create-a-website-application-pool-programmatically-using-csharp as example.
int status = 0;
string ipAddress = "10.20.2.13";
string username = "username";
string password = "password";
try
{
DirectoryEntry de = new DirectoryEntry(string.Format("IIS://{0}/W3SVC/AppPools/MyAppPoolName", ipAddress), username, password);
//the exception is thrown here.
status = (int)de.InvokeGet("AppPoolState");
switch (status)
{
case 2:
//Running
break;
case 4:
//Stopped
break;
default:
break;
}
}
catch (Exception ex)
{
}
The code you found seems to be for IIS6. Perhaps you will be better off using the new and supported IIS7 management API. You could start by calling ServerManager.OpenRemote to get the ServerManager object.
You might need to mess around with the AuthenticationType, the default starting with 2.0 is Secure but you might need to set SSL. Also, I've seen Access Denied messages from accounts with the "user must change password on next logon" checked.
This works pretty well on Windows 7 and Windows server 2008 (unfortunately not on XP and 2003 Server). I had to add Management Service role in the IIS via the Server Manager in order to enable remote connection.
Here's an short example of how to get the State of an Application Pool.
public ObjectState State
{
get
{
ServerManager server = null;
ObjectState result = ObjectState.Unknown;
try
{
server = ServerManager.OpenRemote(address);
result = server.ApplicationPools[name].State;
}
finally
{
if (server != null)
server.Dispose();
}
return result;
}
}
Thanks to driis.

Change Windows Service user programmatically

I need to change Logon user for a Windows service programmatically. And I am using the following code to do that:
string objPath = string.Format("Win32_Service.Name='{0}'", ServiceName);
using (ManagementObject service = new ManagementObject(new ManagementPath(objPath)))
{
object[] wmiParams = new object[11];
if (PredefinedAccount)
{
wmiParams[6] = "LocalSystem";
wmiParams[7] = "";
}
else
{
wmiParams[6] = ServiceUsername; // provided by user
wmiParams[7] = ServicePassword; // provided by user
}
object invokeResult = service.InvokeMethod("Change", wmiParams);
// handle invokeResult - no error up to this point
}
This code works in 90% of situations, but in some situations service cannot be started due to logon failure. There is usually no error on InvokeMetod but when we try to start the service we get the following error:
System.InvalidOperationException: Cannot start service X on computer
'.'. --> System.ComponentModel.Win32Exception: The service did not
start due to a logon failure.
The workaround solution is simple, we just need to enter the same credentials via Windows interface and problem is solved.
So my question is, has anybody experienced the similar problem with ManagementObject because it seems that in some situation it does not relate Username and password to windows service?
It's because the account has no "Log On as service" privilege. You need to use LsaAddAccountRights to add such privilege to the account.
Do you notice any patterns amongst those failures? Same machine? Same OS? Same user? Does the user have "logon as service" or "logon interactively" rights? Personally, I am not familiar with this method of specifying the user for a service. I would have thought you would have to restart the service, but I guess not if it works 90% of the time.

Categories