Exception raised while connecting remotely to Exchange only in IIS hosted application - exchange-server

I hope somebody can help me, I have the following function to do remote calls to a powershell server:
private static string DoCall()
{
string resultPs = string.Empty;
string serverName = "myserver.com";
string SHELL_URI = "http://schemas.microsoft.com/powershell/Microsoft.Exchange";
System.Uri serverUri = new Uri(String.Format("http://{0}/powershell?serializationLevel=Full", serverName));
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(serverUri, SHELL_URI, (PSCredential)null);
//connectionInfo = new WSManConnectionInfo(serverUri, SHELL_URI, PSCredential.Empty);
//connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
try
{
using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
PowerShell powershell = PowerShell.Create();
powershell.Runspace = runspace;
runspace.Open();
powershell.AddScript("Get-DatabaseAvailabilityGroup");
Collection<PSObject> results = powershell.Invoke();
if (powershell.Streams.Error.Count > 0)
{
foreach (ErrorRecord err in powershell.Streams.Error)
{
resultPs += (err.ErrorDetails.Message != null ? err.ErrorDetails.Message : "");
}
}
foreach (PSObject result in results)
{
foreach (PSPropertyInfo propertyInfo in result.Properties)
{
resultPs += "Property:" + propertyInfo.Name + " Value:" + propertyInfo.Value;
}
}
powershell.Runspace.Close();
}
}
catch (Exception ex)
{
resultPs = ex.Message + " " + ex.StackTrace + " innerException: " + (ex.InnerException != null ? (ex.InnerException.Message ?? "") : "");
}
return resultPs;
}
}
If I run this code within Visual Studio in a console application, my credentials are used and the exchange call is done as expected, however, if I publish this code in a WCF service and set the application pool to use my credentials I receive the following exception
"An internal error occurred. \0 at System.Management.Automation.Remoting.Client.WSManClientSessionTransportManager.Initialize(Uri connectionUri, WSManConnectionInfo connectionInfo)\r\n at System.Management.Automation.Remoting.Client.WSManClientSessionTransportManager..ctor(Guid runspacePoolInstanceId, WSManConnectionInfo connectionInfo, PSRemotingCryptoHelper cryptoHelper)\r\n at System.Management.Automation.Remoting.ClientRemoteSessionDSHandlerImpl..ctor(ClientRemoteSession session, PSRemotingCryptoHelper cryptoHelper, RunspaceConnectionInfo connectionInfo, URIDirectionReported uriRedirectionHandler)\r\n at System.Management.Automation.Remoting.ClientRemoteSessionImpl..ctor(RemoteRunspacePoolInternal rsPool, URIDirectionReported uriRedirectionHandler)\r\n at System.Management.Automation.Internal.ClientRunspacePoolDataStructureHandler..ctor(RemoteRunspacePoolInternal clientRunspacePool, TypeTable typeTable)\r\n at System.Management.Automation.Runspaces.Internal.RemoteRunspacePoolInternal..ctor(Int32 minRunspaces, Int32 maxRunspaces, TypeTable typeTable, PSHost host, PSPrimitiveDictionary applicationArguments, RunspaceConnectionInfo connectionInfo)\r\n at System.Management.Automation.Runspaces.RunspacePool..ctor(Int32 minRunspaces, Int32 maxRunspaces, TypeTable typeTable, PSHost host, PSPrimitiveDictionary applicationArguments, RunspaceConnectionInfo connectionInfo)\r\n at System.Management.Automation.RemoteRunspace..ctor(TypeTable typeTable, RunspaceConnectionInfo connectionInfo, PSHost host, PSPrimitiveDictionary applicationArguments)\r\n at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(RunspaceConnectionInfo connectionInfo, PSHost host, TypeTable typeTable, PSPrimitiveDictionary applicationArguments)\r\n at TestingRemote.Service.DoCall() in "
I have checked several blogs about passing the credentials but I haven't found someone with the same exact issue and that has solved mine. I know I can use an overloaded method for initializing the Credentials, but I want to use the ones in the app pool.

Related

Connecting to RETS Servers with UserAgent Requirement

I am hoping there is someone here who is familiar with a Real Estate data standard known as RETS. The National Association of Realtors provides a dll for interfacing with their services called libRETS, but it is not being supported like it once was and recent events have prompted us to create our own as a replacement. For logistics reasons, we can't do this in Core and are using the current C#.Net 4.7.2.
There are 2 or 3 different "security levels" for connecting to a RETS Server, with the method being a per case basis from one MLS to the next. We can successfully connect to those who only require a login and password, but are hitting a wall on those who also require what is called a UserAgent and UserAgentPassword, which must passed somehow using Md5 encryption. The server is returning:
The remote server returned an error: (401) Unauthorized.
private WebResponse GetLoginBasicResponse()//*** THIS ONE WORKS ***
{
try
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var request = (HttpWebRequest)WebRequest.Create(new Uri(_cred.loginUri));
request.Method = "GET";
request.Headers.Add("RETS-Version", _retsVersion);
request.Credentials = new NetworkCredential(_login, _password);
return request.GetResponse();
}
catch (Exception ex)
{
string ignore = ex.Message;
return null;
}
}
private WebResponse GetLoginWithUserAgentResponse()//*** THIS ONE DOES NOT WORK ***
{
try
{
// ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var request = (HttpWebRequest)WebRequest.Create(new Uri(_cred.loginUri));
request.Method = "GET";
request.Headers.Add("RETS-Version", _retsVersion);
if (!string.IsNullOrEmpty(_cred.userAgent))
{
request.UserAgent = Md5(_cred.userAgent + ":" + _cred.userAgentPassword);
//request.Headers.Add("RETS-UA-Authorization", "Digest " + Md5(_cred.userAgent + ":" + _cred.userAgentPassword));
}
request.Credentials = new NetworkCredential(_login, _password);
return request.GetResponse();
}
catch (Exception ex)
{
string ignore = ex.Message;
return null;
}
}
public string Md5(string input) //*** Borrowed this from from .NET Core Project and presume it works
{
// Use input string to calculate MD5 hash
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
{
byte[] inputBytes = Encoding.ASCII.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// Convert the byte array to hexadecimal string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("X2"));
}
return sb.ToString();
}
}
Page 20 of this document describes how to build the UA header: https://www.ranww.org/documents/resources/rets_1_8.pdf
There’s a few other fields you need to include.
We were not able to solve the issue in .NET but found a .NET Core project in GitHub that we are using instead. https://github.com/CrestApps/RetsConnector
This case can be closed
Not seeing an option to "Mark as Answer". Have tried both MS Edge and Google Chrome

Catch incoming emails and send them to a web service (rather than just to a mail server)

I would like to catch incoming emails and send them a web service (rather than just to a mail server).
--
After some searching I found a way of getting new emails via polling - see below: This may be of some help to others. Is there a way to receive messages by SMTP? Perhaps by ISAPI ???
using Limilabs.Mail;
using Limilabs.Client.IMAP;
public ActionResult checkIMAPmail()
{
string rval = "not a sausage";
using (Imap imap = new Imap())
{
imap.Connect(<mail server>);
imap.Login(<username>, <password>);
imap.SelectInbox();
List<long> uids = imap.Search(Flag.Unseen);
foreach (long uid in uids)
{
byte[] ourBytes = imap.GetMessageByUID(uid);
IMail email = new MailBuilder().CreateFromEml(ourBytes);
rval = email.Subject + " [" + email.From + "][" + email.Text + "]";
}
imap.Close();
}
return Content(rval, "text/html");
}
See also http://stackoverflow.com/questions/670183/accessing-imap-in-c-sharp
for other IMAP packages, although note the change to using byte[], above.
Given that Limilabs.Mail is a paid service, I finally used MailKit:
using MailKit;
public int checkIMAPmail()
{
int numEmails = 0;
try {
using (var client = new MailKit.Net.Imap.ImapClient())
{
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
client.Connect(ourSmtpClient);
// disable the XOAUTH2 authentication mechanism.
client.AuthenticationMechanisms.Remove("XOAUTH2");
client.Authenticate(ourSmtpAdminUser, ourSmtpAdminUserPwd);
// The Inbox folder is always available on all IMAP servers...
var inboxFolder = client.Inbox;
var savedFolder = client.GetFolder("saved");
inboxFolder.Open(FolderAccess.ReadWrite);
for (int ii = 0; ii < inboxFolder.Count; ii++)
{
var query = MailKit.Search.SearchQuery.NotSeen;
foreach (var uid in inboxFolder.Search(query))
{
var thisMsg = inboxFolder.GetMessage(uid);
string thisDate = notNullString(thisMsg.Date);
string thisSubject = notNullString( thisMsg.Subject);
string thisBody = notNullString(thisMsg.GetTextBody(0)); // plain text
string thisFromName = "";
string thisFromEmail = "";
if ( thisMsg.From != null)
{
// just get the first
foreach( var mb in thisMsg.From.Mailboxes)
{
thisFromName = notNullString( mb.Name);
thisFromEmail = notNullString( mb.Address);
break;
}
}
numEmails += 1;
// move email to saved
inboxFolder.MoveTo(uid, savedFolder);
}
}
client.Disconnect(true);
}
}
catch (Exception exc)
{
log2file("checkIMAPmail Error: " + exc.ToString());
}
return numEmails;
}

AD with LDAP connection error

Im trying to use a .net application but the application cant find the server in my local network.
Im using LdapExploreTool 2 with the following settings:
the base DN is "DC=exago,DC=local", the Ip address "192.168.1.250" and the server name "exago.local"
The connection is successful and this is the result:
Inputing the values:
Examining the code, i get the exception when "Bind to the native AdsObject to force authentication":
"The specified domain either does not exist or could not be contacted."
public bool IsAuthenticated(string domain, string ldapPath, string username, string pwd, string userToValidate)
{
string domainAndUsername = domain + #"\" + username;
if (string.IsNullOrEmpty(ldapPath))
SetLdapPath(domain);
else
_path = ldapPath;
App.Services.Log.LogUtils.WriteLog(Log.LogLevel.INFO, "IsAuthenticated_DirectoryEntry:" + _path + "," + domainAndUsername + "," + pwd);
DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);
//check if domain is valid
int domainId = AppDomains.GetDomainIdByName(domain);
if (domainId == int.MinValue)
{
return false;
}
AppDomains d = AppDomains.GetRecord(domainId);
List<AppDomainQueries> lQueries = new List<AppDomainQueries>(AppDomainQueries.GetArray());
lQueries = lQueries.FindAll(delegate(AppDomainQueries dq) { return dq.DomainId == domainId && dq.Status == 'A'; });
string queryString = string.Empty;
try
{
// Bind to the native AdsObject to force authentication.
Object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
string ldapAndQuerie = string.Empty;
//base account search
queryString = "(SAMAccountName=" + userToValidate + ")";
if (username != userToValidate)
{
if (lQueries.Count == 1)
ldapAndQuerie = lQueries.FirstOrDefault().QueryString;
if ((ldapAndQuerie != string.Empty) && (ldapAndQuerie != "*") && (ldapAndQuerie != "(objectClass = user)"))
queryString = "(&(SAMAccountName=" + userToValidate + ")" + ldapAndQuerie + ")";
}
search.Filter = queryString;
App.Services.Log.LogUtils.WriteLog(Log.LogLevel.INFO, "LDAP=" + queryString);
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if (null == result)
{
return false;
}
// Update the new path to the user in the directory
_path = result.Path;
_filterAttribute = (String)result.Properties["cn"][0];
}
catch (Exception ex)
{
App.Services.Log.LogUtils.WriteLog(Log.LogLevel.ERROR, "App.Services.Core.LdapAuthentication.IsAuthenticated() Exception - (LDAP=" + queryString + ")" + ex.Message, ex);
return false;
}
return true;
}
How can i establish a connection?
The problem was the LDAP connection string,
it seems that it missed the actual location(IP + port) in the network.
LDAP://192.168.1.250:389/DC=exago,DC=local

Why ServiceStack.Redis throw error instead of trying to connect to another read instance?

I successfully installed Redis on two machines and made then work as Master-Slave.
I tested some code to check if replication work and everything is ok.
My client manager looks like
var manager = new PooledRedisClientManager(new[] { "MasterIP:6379" }, new[] { "MasterIP:6379", "SlaveIP:6379" });
But now i shutdown my master instance and when i test my code again i get an error like client cant connect to Master server.
p.s For read i use GetReadOnlyCacheClient();
I repeated my code and i notice that client first is getting Master (error cant connect), then when i run my code again client is getting Slave, then again when i run my code client is getting master and so on.
I downloaded source code on ServiceStack.Redis client. I just wanted to check when that error happens and here is the code.
private void Connect()
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
SendTimeout = SendTimeout,
ReceiveTimeout = ReceiveTimeout
};
try
{
if (ConnectTimeout == 0)
{
socket.Connect(Host, Port);
}
else
{
var connectResult = socket.BeginConnect(Host, Port, null, null);
connectResult.AsyncWaitHandle.WaitOne(ConnectTimeout, true);
}
if (!socket.Connected)
{
socket.Close();
socket = null;
return;
}
Bstream = new BufferedStream(new NetworkStream(socket), 16 * 1024);
if (Password != null)
SendExpectSuccess(Commands.Auth, Password.ToUtf8Bytes());
db = 0;
var ipEndpoint = socket.LocalEndPoint as IPEndPoint;
clientPort = ipEndpoint != null ? ipEndpoint.Port : -1;
lastCommand = null;
lastSocketException = null;
LastConnectedAtTimestamp = Stopwatch.GetTimestamp();
if (ConnectionFilter != null)
{
ConnectionFilter(this);
}
}
catch (SocketException ex)
{
if (socket != null)
socket.Close();
socket = null;
HadExceptions = true;
var throwEx = new RedisException("could not connect to redis Instance at " + Host + ":" + Port, ex);
log.Error(throwEx.Message, ex);
throw throwEx;
}
}
I really dont understand this code, couze project is really big, but i think there is no If this server fails, then try to get from another host in read only server list if any other exist
I can make some kind of mine custom logic to check if fail to try to get another read only instance..but isnt this client supported to be ready about this issue?

Print to a network printer in C#

I am attempting to print to a network servia via C# in VS2010 but have run into difficulties getting it to work. If I use the "print" Verb insted it prints fine but only to the default printer. I am using the PrintTo Verb to try and specify a printer. In my case using print verb I successfully can print to the same network printer that I am trying to print to using the printto verb after I change my default printer to a different printer. Here is the code I am currently using. Any help would be greatly appreciated.
private string FindPrinter(string printerName)
{
string query = string.Format("SELECT * from Win32_Printer WHERE Name LIKE '%{0}'", printerName);
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
ManagementObjectCollection printers = searcher.Get();
foreach (ManagementObject printer in printers)
{
if (!String.IsNullOrEmpty(printer.Properties["PortName"].Value.ToString()))
{
return printerName = string.Format(#"\\{0}\{1}", printer.Properties["PortName"].Value.ToString(), printerName);
}
}
return printerName;
}
private void Print(string fileName, string printerName)
{
PrinterSettings ps = new PrinterSettings();
ps.PrinterName = printerName;
if (ps.IsValid)
{
try
{
ProcessStartInfo processStartInfo = new ProcessStartInfo(fileName);
using (PrintDialog pd = new PrintDialog())
{
pd.ShowDialog();
printerName = this.FindPrinter(pd.PrinterSettings.PrinterName);
if (printerName.IndexOf(#"\\") == 0)
{
processStartInfo.Verb = "PrintTo";
processStartInfo.Arguments = printerName;
}
else
{
processStartInfo.Verb = "print";
}
}
processStartInfo.CreateNoWindow = true;
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process printProcess = new Process();
printProcess.StartInfo = processStartInfo;
bool printStarted = printProcess.Start();
MessageBox.Show(string.Format("{0} printed to {1}", fileName, printerName), "Report Print", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Report Print", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else
{
MessageBox.Show(string.Format("{0} printer does not exist. Please contact technical support.", printerName), "Report Print", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
only use verb PrintTo and
use the double quotes to quote the printerName
processStartInfo.Verb = "PrintTo";
processStartInfo.Arguments = "\"" + printerName + "\"";

Resources