In our code, we have to give the users a list of printers to choose from. The user then chooses a printer and it is checked to verify it is valid before printing. On a windows 2003 server with IIS 6, this works fine. On a windows 2008 server with IIS 7, it fails each time impersonate is set to true.
PrinterSettings printerSetting = new PrinterSettings();
printerSetting.PrinterName = ddlPrinterName.SelectedItem.Text;
if (!printerSetting.IsValid)
{
lblMsg.Text = "Server Printer is not valid.";
}
else
{
lblMsg.Text = "Success";
}
Each time this code is run, the "Server Printer is not valid" displays, only if impersonate is set to true. If impersonate is set to false, the success message is displayed.
The impersonation user has full rights to the printer.
Is there a way to catch the actual reason the printer is not valid?
Is there some other 2008 setting I should check?
update
I found that IsValid fails when the IIS7 application pools has "Enable 32-bit applications" is checked. This must be checked b/c we are using a 3rd party tool to print with, and it is a 32-bit application. It is not currently part of this test, so right now it is not causing this error.
IIS 7.0 is really locked down. It sounds like the server is not impersonating properly. The printer profiles are stored in the HK_CURRENT_USER hive of the user or if it is a locally connected printer in the HK_LOCAL_MACHINE.
I would use PROCMON from SYSINTERNALS to see the calls the IIS process is making.
You can try by querying the System using WMI. A way to achive this may be the following:
using System.Management;
private List<string> GetPrinters()
{
List<string> printerNames = new List<string>();
System.Management.ObjectQuery oquery =
new System.Management.ObjectQuery("SELECT * FROM Win32_Printer");
System.Management.ManagementObjectSearcher mosearcher =
new System.Management.ManagementObjectSearcher(oquery);
System.Management.ManagementObjectCollection moc = mosearcher.Get();
foreach (ManagementObject mo in moc)
{
System.Management.PropertyDataCollection pdc = mo.Properties;
foreach (System.Management.PropertyData pd in pdc)
{
if ((bool)mo["Network"])
{
printerNames.Add(mo[pd.Name]);
}
}
}
return printerNames;
}
After that, in a similar way, you may find other printer informations as if the printer is ready.
Find more here:
https://stackoverflow.com/a/1622931/2791580
Regards
Applications Pool
Advanced Setting
Process Model
Change Identity to User Administrators
oPD.PrinterSettings.PrinterName = \\10.10.1.1\myprintertnetwork;
I've had exactly the same problem, and I was able to solve it by temporarily leaving the impersonation context. Adapting your example, the following code:
PrinterSettings printerSetting = new PrinterSettings();
printerSetting.PrinterName = ddlPrinterName.SelectedItem.Text;
using (var wic = WindowsIdentity.Impersonate(IntPtr.Zero))
{
if (!printerSetting.IsValid)
{
lblMsg.Text = "Server Printer is not valid.";
}
else
{
lblMsg.Text = "Success";
}
// Do the remainder of your printing stuff here, but beware that
// your user context is different.
}
should yield the success message. (Credit for this solution goes to Jon Saffron.)
try set a default printer on [ control panel - devices and printers right click on one the ready printers and set as default it ]
Related
Is there any way to get the information about Launching identity of DCOM application programmatically. See the picture attached to understand what i mean.
I tried to use WMI
ManagementObjectSearcher s = new ManagementObjectSearcher(new ManagementScope(#"\\.\root\cimv2"), new ObjectQuery(
"select * from Win32_DCOMApplicationSetting where AppID='{048EB43E-2059-422F-95E0-557DA96038AF}'"))
ManagementObjectCollection dcomSett = s.Get();
var value = dcomSett.Cast<ManagementObject>().ToArray()
[0].Properties["RunAsUser"].Value;
but "RunAsUser" property was empty.
Also tried Interop.COMAdmin
COMAdmin.COMAdminCatalogClass catalog = (COMAdmin.COMAdminCatalogClass)new COMAdmin.COMAdminCatalog();
(COMAdmin.COMAdminCatalogCollection)catalog.GetCollection("Applications")
in this way i managed to get applications which are listed under the "COM+ Applications" node in the "Component Services" snap-in of MMC:
I'm new in COM, DCOM, COM+ stuff and sure that i missed something important.
After a while i found out why i used to get NULL in the first approach (ManagementObject).
You will receive:
NULL if identity is currently set to The launching user
"Interactive User" in case of "The interactive user"
some string with username in case of third option (see the first picture)
But still i need a way to change identity for items like Microsoft PowerPoint Slide under DCOM Config node in MMC.
In the DCOM config, if you are using a specific user for the identity and you want to update the password via code, you need to update it in the Local Security Authority (LSA). This is possible with Windows API calls. MS has some sample code for a utility called dcomperm that does it, and you can see how they implemented in C++. You could make the same calls in C#. See the SetRunAsPassword method here. They are using the method LsaOpenPolicy to get a handle to the policy and calling LsaStorePrivateData to update the password. Then they are adding "login as a batch job" access to the account (but that shouldn't be necessary if you are only changing the password).
This sample code on pinvoke.net looks like it is making the requisite calls, except for the optional part about granting the login as a batch job permission. Note the "key" in the LSA is in the format SCM:{GUID-of-DCOM-object} Example: SCM:{00000000-0000-0000-0000-000000000000}
Oh, and I should mention as an aside that if you wanted to change the RunAs user itself (i.e. the username), you'd need to also update that in the windows registry directly (AFAIK that's the only way to do it). DCOM entries are stored under HKLM\SOFTWARE\Classes\AppID. You can do that with WMI or just use the Registry classes in .NET.
This is very simple , you can get APPId from
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{048EB43E-2059-422F-95E0-557DA96038AF}
using
(RegistryKey dcomPPTIdentity = Registry.LocalMachine.OpenSubKey("Software\\Classes\\AppID\\{048EB43E-2059-422F-95E0-557DA96038AF}"))
{
if (dcomPPTIdentity != null)
{
Registry.SetValue(dcomPPTIdentity.ToString(), "RunAs", "userName");
}
}
I am using COMAdmin DLL successfully. Try something like this:
COMAdminCatalog catalog = new COMAdminCatalog();
COMAdminCatalogCollection applications = catalog.GetCollection("Applications");
applications.Populate();
for (int i = 0; i < applications.Count; i++)
{
COMAdminCatalogObject application = COMAppCollectionInUse.Item[i];
if (application.Name == "Your COM+ application name")
{
application.Value["Identity"] = "nt authority\\localservice"; // for example
}
}
This works for me on my development server. Keep in mind, it is run against the server directly on the server
using COMAdmin;
using System;
namespace ComComponents
{
class Program
{
static void Main(string[] args)
{
COMAdminCatalog catalog = new COMAdminCatalog();
COMAdminCatalogCollection applications = catalog.GetCollection("Applications");
applications.Populate();
for (int i = 0; i < applications.Count; i++)
{
COMAdminCatalogObject application = applications.Item[i];
Console.WriteLine(application.Name);
Console.WriteLine(application.Value["Identity"]);
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}
Hi i am working with sharepoint 2007 , and the requirement is to stop all workflows on sharepoint lists in progress after an IISreset.
How do i Programatically find the last IISReset time using C#.
The SCM or Service Control manager logs this. You need to open up the system log in Event Viewer and look in there.
EventLog eventLog = new EventLog();
eventLog.Log = "System";
eventLog.Source = "Service Control Manager"; //Not 100% sure thats correct
eventLog.MachineName = "IIS Server name";
foreach (EventLogEntry log in eventLog.Entries)
{
Console.WriteLine("{0}\n",log.<Property you need for info>);
}
I would say figure out what the event ID would be and key off that instead of just matching Error text or anything along those lines. Just off a quick search I believe its 3203. Below is a WMI solution as well I would suggest do some performance testing on Both. There is another method that is EventLogReader which requires you to have windows vista or 7 or windows server 2008 or higher that you can use as well.
var query = new ObjectQuery("Select * from Win32_NTLogEvent
where LogFile='Application'");
var searcher = new ManagementObjectSearcher(query);
var result = searcher.Get(); // Result is your Collection of Event Log entries
foreach(var eventEntry in result)
{
//access properties in this fashion would suggest try parse
int id = int.Parse(eventEntry["Event ID Property Name"].ToString());
}
A line similar to the following threw the above exception:
PrintServer ps = new PrintServer(#"\\prntsrv");
When I use "Run..." on Windows the address above does work and take me to the list of print jobs so why does the line of code not work?
Apparently, the address \\prntsrv was a DNS alias to \\prntserv and the PrintServer constructor was unable to deal with it. To get around this issue I used the following code (I could also use just the code in the catch block instead and it would work, but preferred not to):
try
{
// Create object to monitor the printer queue
PrintServer printServer = new PrintServer(serverPath);
mPrintQueue = printServer.GetPrintQueue(printerName);
}
catch (PrintServerException ex)
{
// If the problem might be creating the server because the name is an alias
if (ex.Message.Contains("printer name is invalid."))
{
string actualServerHostname = "\\\\" + Dns.GetHostEntry(serverPath.TrimStart('\\')).HostName;
// Create object to monitor the printer queue
PrintServer printServer = new PrintServer(actualServerHostname);
mPrintQueue = printServer.GetPrintQueue(printerName);
// Write to log about the use of a different address
}
else
{
throw;
}
}
hey i was facing similar issue, this is what i observed and made following changes, just try and let me know.
This issue was occuring due to windows feature/role "Print and Document service" is missing on the system. This role is required for managing multiple printers or print servers and migrating printers to and from other windows servers.
To add the role Go To Control Panel->Turn windows feature on or off->click on check box "Print and Document Service"->install.
See with network administrator for installing this rule if you unable to add it.
After adding the role you can able to create print server object and get the all the printqueues on respective server.
i am trying to get my application to be allowed through firewall, as I have to do ftp in active and passive mode is not an option as servers are not configured for that. so i tried the below code which compiles fine, I exexcute it using:
MyApp.Classes.INetFwMgr mgr = new MyApp.Classes.INetFwMgr();
mgr.AuthorizeApplication(Application.ProductName, Application.StartupPath,
NET_FW_SCOPE_.NET_FW_SCOPE_ALL,
NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY);
And the class which does the job:
private const string CLSID_FIREWALL_MANAGER =
"{304CE942-6E39-40D8-943A-B913C40C9CD4}";
private static NetFwTypeLib.INetFwMgr GetFirewallManager()
{
Type objectType = Type.GetTypeFromCLSID(
new Guid(CLSID_FIREWALL_MANAGER));
return Activator.CreateInstance(objectType)
as NetFwTypeLib.INetFwMgr;
}
private const string PROGID_AUTHORIZED_APPLICATION =
"HNetCfg.FwAuthorizedApplication";
public bool AuthorizeApplication(string title, string applicationPath,
NET_FW_SCOPE_ scope, NET_FW_IP_VERSION_ ipVersion)
{
// Create the type from prog id
Type type = Type.GetTypeFromProgID(PROGID_AUTHORIZED_APPLICATION);
INetFwAuthorizedApplication auth = Activator.CreateInstance(type)
as INetFwAuthorizedApplication;
auth.Name = title;
auth.ProcessImageFileName = applicationPath; //Getting Access Denied Exception Here
auth.Scope = scope;
auth.IpVersion = ipVersion;
auth.Enabled = true;
NetFwTypeLib.INetFwMgr manager = GetFirewallManager();
try
{
manager.LocalPolicy.CurrentProfile.AuthorizedApplications.Add(auth);
}
catch (Exception ex)
{
return false;
}
return true;
}
using above code, but i get Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) c# exception on line
auth.ProcessImageFileName = applicationPath;
any ideas what to do ?
Edit1: How would i run this as an admin using code?
Edit2: I also tried Putting <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> in manifest did not make a difference
P.S.This programs execution context can be Win 7, vista, xp
Firewall management is a system level security feature and has to be done outside of user mode application code. Configuration must be done by an administrator.
It is bad practice to write the code that you wrote and assume that your application will be run as administrator. Even if it is run by an administrator, you now have an application that "does FTP stuff" and "does firewall stuff". No application has ever been written like this.
You can write code that interacts with the system firewall, and that code must be run with elevated permissions. Typically such "helper applications" are never even created however as Windows (and every other OS) has all the necessary management tools shipped with the OS (i.e. wf.msc).
i have observed that if i change the order of ftp download statements to following windows dialog appears asking that do you want to allow this program access through firewall; if i click allow access the code works perfectly.
requestDownload = (FtpWebRequest)WebRequest.Create(uri);
requestDownload.UsePassive = false;
requestDownload.KeepAlive = false;
requestDownload.UseBinary = true;
requestDownload.Method = WebRequestMethods.Ftp.DownloadFile;
requestDownload.Credentials = new NetworkCredential(ftpInfoDownload[3], ftpInfoDownload[4]);
responseDownload = (FtpWebResponse)requestDownload.GetResponse();
Stream ftpStream = responseDownload.GetResponseStream();
Try opening the FTP ports in the firewall -- ports 20 and 21 -- and see if that solves your issue.
For running as a different user:
Run Code as a different user (C#)
As for getting through the firewall, have you talked to the person/group responsible for the firewall security? They may have some rules in place that you could use.
I've written a piece of software that uses an USB 3G Dongle to connect to the internet if a connection doesn't already exist.
When the software loads, it detects whether the internet is available and if not, then creates a dial up connection (via RAS) and then dials it.
If this happens for the first time, the network location dialog comes up asking the user to select whether it's home, work or public.
Is there anyway, I can either programatically set the network location of a connection, or even tell windows not to show the dialog and automatically set the location to public?
Cheers
Gavin
Edit: For ScottM
public bool Connect(bool monitorSignalUpdates)
{
RasPhoneBook rpb = new RasPhoneBook();
rpb.Open(true);
if (!rpb.Entries.Contains("3G Connection"))
{
rpb.Entries.Add(RasEntry.CreateBroadbandEntry("3G Connection", RasDevice.GetDeviceByName("HUAWEI Mobile Connect - 3G Modem", RasDeviceType.Modem), true));
}
_rd = new RasDialer();
_rd.EntryName = "3G Connection";
_rd.PhoneNumber = "*99#";
try
{
_rd.Dial();
if (monitorSignalUpdates)
{
_queryPort.DataReceived += new SerialDataReceivedEventHandler(_queryPort_DataReceived);
}
return true;
}
catch (Exception ex)
{
int i = 99;
}
return false;
}
This registry entry controls whether Windows will prompt for ("Home/Work/Public"):
HKLM\System\CurrentControlSet\Control\Network\NewNetworkWindowOff
http://technet.microsoft.com/en-us/library/gg252535%28v=ws.10%29.aspx
You can always "“Turn off Notification on New Networks” from system tray :)
And if you can do that, I'm sure there's a registry hack and/or a PowerShell API for doing the same:
http://technet.microsoft.com/en-us/library/cc725831%28v=ws.10%29.aspx