I have a console app written in C# that uses MS Fax (FAXCOMEXLib) to send faxes. If I run the application manually or from a command prompt it works as expected. If I schedule the application with Task Scheduler or try to run from a service with a timer, it fails when calling the ConnectedSubmit2 on the FaxDocument object. The application runs as expected, gets the data, creates the pdf, connects to Fax Service, fills the FaxDocument properties, but bombs on ConnectedSubmit2. It feels like a security issue. The windows account the TaskScheduler runs under belongs to the administrator group.
This same application has worked on another Server 2008 (not R2) computer without issue with Task Scheduler.
The server in question is running Microsoft Server 2008 R2.
Recap: The application will work if run manually, fails if run from another process like Task Scheduler.
Any suggestions would be most appreciated. Thank you.
C# Code:
FAXCOMEXLib.FaxServer faxServer = new FAXCOMEXLib.FaxServer();
FAXCOMEXLib.FaxDocument faxDocument = new FAXCOMEXLib.FaxDocument();
ArrayList al = new ArrayList();
al.Add(orderPdfFilePath);
if (facesheetPdfFilePath != "")
al.Add(facesheetPdfFilePath);
if (write) Console.WriteLine("Preparing to Connect to Fax Server...");
sbLog.Append("Preparing to Connect to Fax Server...\r\n");
faxServer.Connect("");
if (write) Console.WriteLine("Connected.");
sbLog.Append("Connected.\r\n");
// Add Sender Information to outgoing fax
faxDocument.Sender.Name = dr2["FacilityName"].ToString();
faxDocument.Sender.Department = dr2["TSID"].ToString();
faxDocument.Sender.TSID = Truncate(dr2["TSID"].ToString(), 20);
faxDocument.Recipients.Add(dr2["FaxNumber"].ToString(), dr2["Pharmacy"].ToString());
faxDocument.Bodies = al.ToArray(typeof(string));
faxDocument.Subject = order;
if (write) Console.WriteLine("Attempting submit to fax server...");
sbLog.Append("Attempting submit to fax server...\r\n");
// attempt send...
try
{
object o;
faxDocument.ConnectedSubmit2(faxServer, out o);
if (write) Console.WriteLine("Fax sent successfully " + DateTime.Now.ToString());
sbLog.Append("Fax sent successfully " + DateTime.Now.ToString() + ".\r\n");
}
catch (Exception ex)
{
if (write) Console.WriteLine("SEND FAILED! " + order + " " + DateTime.Now.ToString() + " " + ex.Message);
sbLog.Append("SEND FAILED! " + order + " " + DateTime.Now.ToString() + ".\r\n" + ex.Message + "\r\n" + ex.InnerException + "\r\n");
error = true;
}
Errors in Event Log:
System.Runtime.InteropServices.COMException (0x80070102): Operation failed.
at FAXCOMEXLib.FaxDocumentClass.ConnectedSubmit2(IFaxServer pFaxServer, Object& pvFaxOutgoingJobIDs)
System.UnauthorizedAccessException: Access denied. at FAXCOMEXLib.FaxDocumentClass.ConnectedSubmit2(IFaxServer pFaxServer, Object& pvFaxOutgoingJobIDs) at ElementsTransmission.Program.Main(String[] args)
See
http://blogs.msdn.com/b/dougste/archive/2011/08/30/system-runtime-interopservices-comexception-0x80070102-operation-failed-trying-to-send-a-fax-from-and-asp-net-application.aspx
Bill
Related
I am trying to change IIS App Pool Identity (user) remotely using C# and getting an error
System.Runtime.InteropServices.COMException (0x800706BA): The RPC server is unavailable.
I am able to do it properly if I allow all RPC dynamic port (in the range of 49152 to 65535) from firewall for all services on a remote machine.
I just want to know the exact service or process name used by the remote system to complete the process so that I can allow the ports for that service only.
public static bool ChangeAppPoolUser(string ip, string machineName, string username, string password, string applicationPoolName)
{
try
{
var metabasePath = "IIS://" + ip + "/W3SVC/AppPools";
// Get list of appPools at specified metabasePath location
using (DirectoryEntry appPools = new DirectoryEntry(metabasePath, username, password))
{
if(appPools==null)
{
Helper.PrepareDebugLog("appPools is null");
}
Helper.PrepareDebugLog("metabasePath:" + metabasePath + " username:" + username + " password:" + password);
// From the list of appPools, Search and get the appPool
using (DirectoryEntry AppPool = appPools.Children.Find(applicationPoolName, "IIsApplicationPool"))
{
Helper.PrepareDebugLog("in");
if (AppPool != null)
{
AppPool.InvokeSet("AppPoolIdentityType", new Object[] { 3 });
// Configure username for the AppPool with above specified username
AppPool.InvokeSet("WAMUserName", new Object[] { Environment.UserDomainName + "\\" + Environment.UserName });
// Configure password for the AppPool with above specified password
AppPool.InvokeSet("WAMUserPass", new Object[] { CommonProgramVariables.localPassword });
// Write above settings to IIS metabase
AppPool.Invoke("SetInfo", null);
// Commit the above configuration changes that are written to metabase
AppPool.CommitChanges();
return true;
}
}
}
}
catch (Exception e)
{
Helper.PrepareLogWithTimstamp("EXCEPTION WHILE CHNAGE USER: Parameter USED machineName:" + machineName + " username:" + username + " password:" + password + " applicationPoolName:" + applicationPoolName + " LocalPassword:" + CommonProgramVariables.localPassword + " Local User:" + Environment.UserDomainName + "\\" + Environment.UserName);
Helper.PrepareLog("EXCEPTION:", e);
}
return false;
}
Expected: AppPool User should be changed for remote machine AppPool.
Actual result:
System.Runtime.InteropServices.COMException (0x800706BA): The RPC server is unavailable.
The error The RPC server is unavailable. (Exception from HRESULT: 0x800706BA) can occur if RPC / WMI connections are blocked on the target machine due to Firewall restrictions or you entered incorrect hostname / IP address of the target machine.
To resolve this error you could follow the below steps:
1)Open Control Panel, click Security and then click Windows Firewall.
2)Click Change Settings and then click the Exceptions tab.
3)In the Exceptions window, select the check box for Windows Management Instrumentation (WMI) to enable WMI traffic through the firewall.
I'm trying to create a function for an application to automatically copy over specific files during the final stage of a job. The only issue here is that the copy location is a protected share drive and uses a separate login instead of being validated by the active directory so I've got to do a bit of a workaround to get File.Copy() working. My workaround has been to call the built in net.exe utility and passing a command line argument that points to the share drive to open up a connection to the drive then using File.Copy() to get the file where it needs to go then deleting the connection. The issue at hand is that this works great on my computer but when anyone else on the team runs the same program a "Logon failure: unknown user name or bad password" is thrown. I'm at a bit of loss as to why this would happen since the username and password are static and not being changed and everyone on the team has the same network permissions I do. Here is the WPF/C# code I'm using to do this:
try
{
string mrdfDropPath = #"dropPathHere";
string MRDFPath = #"storePath\test.xml";
string command = #"use " + mrdfDropPath + #" /user:CORP\Username Password";
Process.Start("net.exe", command);
File.Copy(MRDFPath, mrdfDropPath + "test.xml");
string command2 = #"use " + mrdfDropPath + #" /delete";
Process.Start("net.exe", command2);
StreamWriter writer = new StreamWriter(#"logPath\log.txt", true);
writer.WriteLine(mrdfDropPath + "test.xml" + "," + File.GetLastWriteTime(MRDFPath).ToString());
writer.Close();
}
catch (Exception e)
{
StreamWriter writer = new StreamWriter(#"logPath\log.txt", true);
writer.WriteLine(e.Message);
writer.Close();
}
Like I said this works as expected during debug and when I run the application, but for anyone else it is throwing the error.
I'm having a really strange problem with an application I wrote a while back. It has worked without issues, but after leaving it alone for a while, it simply stopped functioning. I'll attach the code here:
try
{
using (Process proc = Process.Start(starter))
{
windowHider();
proc.WaitForExit();
DateTime endStamp = DateTime.Now;
endStamp = truncate(endStamp);
TimeSpan diff = endStamp.Subtract(startStamp);
string programSource = "applicationName";
string logLocation = "Application";
string occurance = "Var='" + varName + "' Var2='"+ var2Name + "' Var3='" + var3Name + "' Var4='" + var4Name + "' Var5='" + var5Name + "' Var6='" + var6Name + "'";
try
{
if (!EventLog.SourceExists(programSource))
{
EventLog.CreateEventSource(programSource, logLocation);
}
else
{
EventLog.WriteEntry(programSource, occurance);
}
}
catch (Exception err)
{
string message = "There was an error with usage logging. Please contact IT.";
MessageBox.Show(message);
errorLogger(message, err.ToString(), ((Control)sender).Name);
this.Close();
}
this.Close();
}
}
When the process that was started exits, the program writes to the application log. For some reason, however, I am getting the following error:
Exception: System.ComponentModel.Win32Exception (0x80004005): The
specified path is invalid
It cites this line as the cause:
EventLog.WriteEntry(programSource, occurance);
Any ideas as to what this sudden problem could be?
I figured it out! There was something corrupted in the registry, and there must have been another corrupted component lurking around somewhere. I changed the sourcename, and it worked without any issues.
The original sourcename works on other machines, which makes me think it was definitely just something wonky with the registry.
I´m having a problem whenever i try to use WMI services on a virtual pc running a 2003 Server.
The error message that i get is 'Access Denied'. I have already checked the permissions of the user over the COM components. The curious thing is that i´m running both WMI service and my app as Administrator user, so i don´t think i have trouble with permissions.
Can Anyone help me??
Thanks you very much.
The problem is on this block:
ManagementEventWatcher watcher;
try
{
numeros = devolverRandomicos();
string nros = "";
foreach (int num in numeros)
{
nros = nros + " " + num.ToString();
}
MessageBox.Show(nros);
watcher = new ManagementEventWatcher("root\\OnGuard", dataQry);
watcher.EventArrived += WMIEventArrieved;
watcher.Start();
}
catch (Exception e)
{
MessageBox.Show("ERROR CREANDO EL WATCHER: \n" + e.Message,"CatchToyota",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
The problem at last was in the Domain Users I was using to log in. After getting the machine out of the domain, all started to work just fine.
I guess it was a problem with permissions on domain users.
I'm trying to write simple application in C# which will allow me to backup, zip and send over ftp my SQL Server database.
One problem I have encountered is that I'm not able to create the backup file (.bak) if I try to do it in different location than "C:\Program Files\Microsoft SQL Server\MSSQL.3\MSSQL\Backup" or "C:\Program Files\Microsoft SQL Server\MSSQL.3\MSSQL\Data" folder. I understand that this is a premission problem. Could someone point me to the resources or write here a short snippet how to programmatically add such a permission to any folder on my system.
Regards
Kris
i assume you are running your programm as a scheduled task ... did you give writing permissions to the target folder for the executing user of the task??
edit:
with permissions you can have 2 scenarios:
windows authenification
mixed authentification
if you are using windows authentification, the read and write permissions of the windows user are taken. otherwise the permissions for the sql server service account.
and this behaviour makes sense to me and maybe hits the nail in your scenario!
edit 2:
i don't want to encourage you to do so ... some admins may hate you when you mess up their acl's
but this may do the trick
btw: Magnus Johansson already gave you a "try-this" link
no matter for which method you go - be sure to hand in the correct user (as descriped above!)
(for full history)
...
side-note:
i know this is not the exact answer to your question, but i would recommend you smo to generate backups ...
like
using Microsoft.SqlServer.Management.Smo;
var bdi = new BackupDeviceItem(/* your path inlcuding desired file */);
var backup = new Backup
{
Database = /* name of the database */,
Initialize = true
};
backup.Devices.Add(bdi);
var server = new Server(this.SqlServer);
try
{
backup.SqlBackup(server);
}
catch (Exception ex)
{
// * log or sth
}
you only have to care for the .dll's. take assemblies for the desired server version (some params/properties vary through different server versions)
more info here
Ok Guys, Magnus and dittodhole! Thanks a lot for your help. I have combined Magnus'es link to the article on setting up permisions on the folder together with some more research and finally I've got it :).
So reassuming, I'm using Smo, and to create a folder with proper permissions I have to look for the group instead of win32_Users. Here you go a short snippet if someone finds this post he can find it usefull:
string tempPath = Directory.CreateDirectory("C:\\path_to_your_folder").FullName;
//set permissions
SelectQuery sQuery = new SelectQuery("Win32_Group",
"Domain='" +
System.Environment.UserDomainName.ToString() +
"'");
try
{
DirectoryInfo myDirectoryInfo = new DirectoryInfo("C:\\path_to_your_folder");
DirectorySecurity myDirectorySecurity = myDirectoryInfo.GetAccessControl();
ManagementObjectSearcher mSearcher = new ManagementObjectSearcher(sQuery);
foreach (ManagementObject mObject in mSearcher.Get())
{
string User = System.Environment.UserDomainName + "\\" + mObject["Name"];
if(User.StartsWith("your-machine-name\\SQL"))
{
myDirectorySecurity.
AddAccessRule(new FileSystemAccessRule(User,
FileSystemRights.FullControl,
AccessControlType.Allow));
}
}
myDirectoryInfo.SetAccessControl(myDirectorySecurity);
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
Again thanks everyone for your help! Stackoverflow rocks!
Here is a procedure is use for back up in C#.Hope it helps
public void BackupDatabase (string BackUpLocation, string BackUpFileName, string
DatabaseName, string ServerName )
{
DatabaseName = "[" + DatabaseName + "]";
string fileUNQ = DateTime.Now.Day.ToString() + "_" + DateTime.Now.Month.ToString() + "_" + DateTime.Now.Year.ToString() +"_"+ DateTime.Now.Hour.ToString()+ DateTime.Now .Minute .ToString () + "_" + DateTime .Now .Second .ToString () ;
BackUpFileName = BackUpFileName + fileUNQ + ".bak";
string SQLBackUp = #"BACKUP DATABASE " + DatabaseName + " TO DISK = N'" + BackUpLocation + #"\" + BackUpFileName + #"'";
string svr = "Server=" + ServerName + ";Database=master;Integrated Security=True";
SqlConnection cnBk = new SqlConnection(svr);
SqlCommand cmdBkUp = new SqlCommand(SQLBackUp, cnBk);
try
{
cnBk.Open();
cmdBkUp.ExecuteNonQuery();
Label1.Text = "Done";
Label2.Text = SQLBackUp + " ######## Server name " + ServerName + " Database " + DatabaseName + " successfully backed up to " + BackUpLocation + #"\" + BackUpFileName + "\n Back Up Date : " + DateTime.Now.ToString();
}
catch (Exception ex)
{
Label1.Text = ex.ToString();
Label2.Text = SQLBackUp + " ######## Server name " + ServerName + " Database " + DatabaseName + " successfully backed up to " + BackUpLocation + #"\" + BackUpFileName + "\n Back Up Date : " + DateTime.Now.ToString();
}
finally
{
if (cnBk.State == ConnectionState.Open)
{
cnBk .Close();
}
}
}
Take a look at this article.
Remember to set the permissions for the account that the SQL Server instance is running with.
Although this may not answer your immediate question, I'd advice you to look into SQL Server Integration Services (SSIS). This looks like the exact thing SSIS was created for, and in the 2008 version there's the possibility to use C# code if needed, should the standard components not do what you need (earlier versions used VB.NET).
MSDN SSIS Info Link 1
SSIS 2005 Tutorial Link 2
Take a look at it.