Reporting Services access via Management Studio and a C# application - c#

How do you grant someone access to select Reporting Services from the drop down within Management Studio as per the below image.
Also, I have a colleague who has full admin access to this however when they run the below with the credentials set to DefaultCredentials we seem still be getting an error:
namespace ReportingServicesJobsUtility
{
public class Program
{
public static void Main(string[] args)
{
ListJobSSRS();
}
public static void ListJobSSRS()
{
//create instance of ReportingService2010 called server
server.ReportingService2010 rs = new server.ReportingService2010();
//user credentials running application to be used
rs.Credentials = CredentialCache.DefaultCredentials;
//rs.Credentials = new System.Net.NetworkCredential("","");
//create array of jobs
Job[] jobs = null;
try
{
jobs = rs.ListJobs();
ListRunningJobs(jobs);
}
catch (SoapException e)
{
Console.WriteLine(e.Detail.InnerXml.ToString());
}
Console.ReadLine();
}
//make this a void?
public static bool ListRunningJobs(server.Job[] jobs)
{
int runningJobCount = 0;
Console.WriteLine("Current Jobs");
Console.WriteLine("================================" + Environment.NewLine);
server.Job job = default(server.Job);
foreach (var j in jobs)
{
Console.WriteLine("--------------------------------");
Console.WriteLine("JobID: {0}", job.JobID);
Console.WriteLine("--------------------------------");
Console.WriteLine("Action: {0}", job.JobActionName);
Console.WriteLine("Description: {0}", job.Description);
Console.WriteLine("Machine: {0}", job.Machine);
Console.WriteLine("Name: {0}", job.Name);
Console.WriteLine("Path: {0}", job.Path);
Console.WriteLine("StartDateTime: {0}", job.StartDateTime);
Console.WriteLine("Status: {0}", job.JobStatusName);
Console.WriteLine("Type: {0}", job.JobTypeName);
Console.WriteLine("User: {0}" + Environment.NewLine, job.User);
runningJobCount += 1;
}
Console.Write("There are {0} running jobs. ", runningJobCount);
//returning a true for no reason
return true;
}
}
}
The error message is as follows and we believe this is down to credentials, unless anyone can also shed some light on this?
edit
If I use rs.Credentials = new System.Net.NetworkCredential(#"developmentserver\Administrator","password"); on our development server then this runs with no problems, so it seems that it does not like using DefualtCredentials, either that or mine and my collegue's AD credentials are not sufficient, so back to the original question how do we grant full access to our logons.

Have you tried adding the accounts you want in the Report Manager and setting the role assignment there?

you are asking for advice on two very different issues and i have some idea for the second one only.
you are not describing the layout of the servers involved so i make the assumption that you are on a client machine accessing a webservice that is a bridge to reach a SSRS instance; webservice and SSRS are not on the same machine.
if this is the case then check if you are running into the double hop issue.

Related

C# How to access a shared outlook/exchange mailbox programmatically from a C# console application to move emails from inbox to another folder

I need to write a console application that essentially will:
Access a group/shared mailbox's inbox.
Select all emails older than n minutes.
Move the selected emails to another folder "AgedEmails".
So far the program I wrote works well connecting to my email account, even not passing credentials.
The challenge is to access the shared emailbox not mine. The program will run in a server on a frequency set in Windows task scheduler. I have read many postings where the problem is the same I have, but could not find a solution that works.
I have tried the nameSpace.Logon method but it always connects to my employee's email account.
These are the many ways I tried to login to the shared email account (none work):
outlookNameSpace.Logon("mailboxname#company.com", "", true, true);
outlookNameSpace.Logon("mailboxname#company.com", "theRealPassword");,
and this is how I try to get a handle into the inbox:
inboxFolder = outlookNameSpace.Folders["mailboxname#company.com"].Folders["Inbox"];
I am looking for some one to put me in the right direction to achieve the goal. This application will run unattended.
Thanks in advance for your support. Here is the source code:
static async Task MoveEmailsAsync()
{
StreamWriter logFile = new StreamWriter(path, append: true);
Application outLookApplication = null;
NameSpace outlookNameSpace = null;
MAPIFolder inboxFolder = null;
MAPIFolder sourceFolder = null;
MAPIFolder testFolder = null;
Items mailItems = null;
string sSourceFolder = ConfigurationManager.AppSettings["SourceFolder"];
string destinationFolder = ConfigurationManager.AppSettings["DestinationFolder"];
try
{
int minutesAged = Convert.ToInt16(ConfigurationManager.AppSettings["MinutesAged"]);
DateTime age = DateTime.Now;
outLookApplication = new Application();
outlookNameSpace = outLookApplication.GetNamespace("MAPI");
inboxFolder = outlookNameSpace.GetDefaultFolder(OlDefaultFolders.olFolderInbox);
sourceFolder = inboxFolder.Folders[sSourceFolder.ToString()];
testFolder = inboxFolder.Folders[destinationFolder.ToString()];
mailItems = sourceFolder.Items;
string from = null;
string subject = null;
int counter = mailItems.Count;
int i = 0;
for (int k = counter; k >= 1; k--)
{
try
{
i++;
if (true) //this condition will be removed
{
from = null;
subject = null;
Microsoft.Office.Interop.Outlook.MailItem mailitem = (Microsoft.Office.Interop.Outlook.MailItem)mailItems[k];
TimeSpan ts = DateTime.Now - mailitem.ReceivedTime;
if (ts.TotalMinutes > minutesAged)
{
if (!((mailitem.SenderEmailAddress == null) || (mailitem.SenderEmailAddress == "")))
{
from = mailitem.SenderEmailAddress.ToString();
}
if (!((mailitem.Subject == null) || (mailitem.Subject == "")))
{
subject = mailitem.Subject;
}
await logFile.WriteLineAsync(i + ". From: " + from + " - Subject: " + subject);
mailitem.Move(testFolder);
}
}
}
catch (Exception e)
{
await logFile.WriteLineAsync("Exception caught: " + e.ToString());
}
}
await logFile.WriteLineAsync(DateTime.Now.ToString() + " - End of Job.");
}
catch (Exception e)
{
await logFile.WriteLineAsync("Exception caught: " + e.ToString());
}
logFile.Flush();
logFile.Close();
}
}
Firstly, Namespace.Logon takes the name of an existing profile (as shown in Control Panel | Mail | Show Profiles), not an address of a mailbox.
Secondly, to open a folder from another user's mailbox, replace the GetDefaultFolder call with Namespace.CreateRecipient / Namespace.GetSharedDefaultFolder
Answers to your questions don't make any sense due to the following statement:
The program will run in a server on a frequency set in Windows task scheduler.
That is the key statement in your post because MS states the following for such scenarios:
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. Or, you should try to find alternatives that allow at least part of the code to run client-side. If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution.
Read more about that in the Considerations for server-side Automation of Office article.
If you deal with Exchange accounts you may consider using EWS instead, see Explore the EWS Managed API, EWS, and web services in Exchange for more information. In case of Office365 consider using the Graph API, see Use the Microsoft Graph API.

How to save only Excel attachments from outlook in C#?

I have to create a program which saves Excel attachments from the mail inbox.
At the moment I am saving all attachments from incoming mails via an event handler, but it seems like that the event is not always triggered but rather 3 from 4 mails only. I don't know the reason though.
So I was thinking about looping through the inbox mails, look for mails with specific subject title and save the attached Excel files.
But how can I do that? Other solutions shows only via add in, but I want to use a Windows service for that.
So far my code (this doesn't work every time though, maybe someone knows a reason for that?)
public partial class MyService : ServiceBase
{
public string AttachPath = #"[mypath to save attachments]";
public MyService()
{
InitializeComponent();
}
public void RunAsConsole(string[] args)
{
Console.WriteLine("This service is executed as a console application.");
Console.WriteLine("Application active.");
OnStart(args);
Console.WriteLine("Press q to exit.");
string userInput = Console.ReadLine();
while (userInput != "q")
{
userInput = Console.ReadLine();
}
Console.WriteLine("Finished! \nPress any key to exit...");
Console.ReadLine();
OnStop();
}
protected override void OnStart(string[] args)
{
Outlook.NameSpace outlookNameSpace;
Outlook.MAPIFolder inbox;
Outlook.Items items;
Outlook.Application oApp = new Outlook.Application();
outlookNameSpace = oApp.GetNamespace("MAPI");
inbox = outlookNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
items = inbox.Items;
items.ItemAdd +=
new Outlook.ItemsEvents_ItemAddEventHandler(items_ItemAdd);
}
void items_ItemAdd(object Item)
{
string filter = "[myFilter]";
Outlook.MailItem mail = (Outlook.MailItem)Item;
if (Item != null)
{
if (mail.Subject.ToUpper().Contains(filter.ToUpper()))
{
Console.WriteLine(DateTime.Now.ToShortTimeString() + " Mail found!: " + mail.Subject);
if (mail.Attachments.Count > 0)
{
for (int i = 1; i - 1 < mail.Attachments.Count; ++i)
{
Console.WriteLine($#"Saving {mail.Attachments[i].FileName}");
//Console.WriteLine(Path.Combine(AttachPath, mail.Attachments[i].FileName));
string filepath = Path.Combine(AttachPath, mail.Attachments[i].FileName);
mail.Attachments[i].SaveAsFile(filepath);
//if (File.Exists(filepath))
//{
// mail.Delete(); //after saving the file delete the mail
//}
}
}
else
{
Console.WriteLine("No attachments found: execute auto reply...");
Outlook.MailItem replyMail = mail.Reply();
replyMail.HTMLBody = $#"Some answer for reply";
replyMail.Send();
}
Console.WriteLine("Delete mail: " + mail.Subject.ToString());
mail.UnRead = false; //mark as read
mail.Delete();
}
}
}
protected override void OnStop()
{
//nothing
}
}
At the moment, the service can be executed as a console application and a Windows service, so please don't pay too much attention at that point, it's for debugging reasons.
Other Solutions shows only via add in, but I want to use a windows service for that.
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. Or, you should try to find alternatives that allow at least part of the code to run client-side. If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution. Read more about that in the Considerations for server-side Automation of Office article.
As a workaround, you may consider using a low-level API on which Outlook is based on - Extended MAPI or just any wrappers around that API such as Redemption.
If you deal with Exchange only, you may consider using Graph API or EWS, see Start using web services in Exchange for more information.
Please refer to Eugene's answer on the architecture side of things. But from the perspective of extracting the emails with a filter, you can try this code.
Instead of getting items = inbox.Items, try finding the emails with a filter query which returns an Outlook.Table
Then you can iterate on this table to get the emails.
const string PropTag = "http://schemas.microsoft.com/mapi/proptag/";
var filter = "#SQL=" + "\"" + PropTag
+ "0x0037001E" + "\"" + " ci_phrasematch " + "\'" + strFilter + "\'";
Outlook.Table table = inbox.GetTable(filter, Outlook.OlTableContents.olUserItems);
while (!table.EndOfTable)
{
Outlook.Row nextRow = table.GetNextRow();
try
{
Outlook.MailItem mi;
try
{
string entryId = nextRow["EntryID"];
var item = outlookNameSpace.GetItemFromID(entryId);
mi = (Outlook.MailItem)item;
}
catch (InvalidCastException ex)
{
Console.WriteLine("Cannot cast mail item, so skipping. Error: {0}", e);
continue;
}
//Extract the attachments here and archive or reply - put your logic here
}
catch (Exception e)
{
Console.WriteLine("An error occurred: '{0}'", e);
}
}

A piece of code working in WindowsFormApplication but not working in windows service, is there any mistake?

Here the code is
protected override void OnStart(string[] args)
{
Thread thr = new Thread(new ThreadStart(run));
thr.Start();
}
static void run()
{
while (true)
{
StreamWriter str = new StreamWriter("D:\\Sarojini.txt", true);
str.WriteLine();
str.WriteLine("**** List of Apllication*********");
str.WriteLine();
str.WriteLine("Service started on:" + DateTime.Now.ToString());
string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name.ToString();
str.WriteLine();
str.WriteLine("the current user is " + userName);
Process[] processlist = Process.GetProcesses();
foreach (Process process in processlist)
{
if (!String.IsNullOrEmpty(process.MainWindowTitle))
{
str.WriteLine("Process::{0} ID::{1} Title::{2}", process.ProcessName, process.Id, process.MainWindowTitle);
}
}
str.Close();
Thread.Sleep(3600000 / 10);
}
}
protected override void OnStop()
{
StreamWriter str = new StreamWriter("D:\\Sarojini.txt", true);
str.WriteLine();
str.WriteLine("the service has been stopped.");
}
here in this code , a text file is created and first line is written on it but the list of running application is not there , where as when i used this code in in windowsFormApllication it is running perfectly. i dont know what is the problem .
This is most likely due to the account you are running the service under not having the correct permissions to use the Process class. When trying to retrieve process names, IDs etc your application needs to have sufficient rights and the default Local System Account is unlikely to meet this.
When you run this code as a Windows Form Application WindowsIdentity.GetCurrent() will return the user who is currently signed in.
When you run this code as a Windows Service WindowsIdentity.GetCurrent() will return the user who setup under the User Account in the Service Setting.
This will show that they are running with different credentials. So, your service may be running under an account that does not have permission to perform the required actions.
To check this:
Go into Services and double-click your service.
Click on The Log On tab
By default Local System Account is checked but you want to select This Account and set a valid account.

Get closest Domain Controller in current AD site without hard coding information

For instances when Active Directory takes too long to replicate data between sites, I need to ensure that the local AD replica contains the most up to date information.
How can I get a list of DomainControllers for the current site?
I haven't found anything on Codeproject or on StackOverflow
Going to all this trouble is probably wasted effort. Unless you are experiencing issues with the built in logic for finding a domain controller you should just go with the built in method that returns one. According to Microsoft it automatically tries to find the closes one: http://technet.microsoft.com/en-us/library/cc978016.aspx.
Just use the static DomainController.FindOne method and pass in your directorycontext.
Update
Alright, try the code below, let me know how it works for you. It pings each, returns the roundtrip time, if -1 (no connection) it skips it. Flags PDC status if present. Orders by PDC status, followed by ping round trip.
static void Main(string[] args)
{
var dcsInOrder = (from DomainController c in Domain.GetCurrentDomain().DomainControllers
let responseTime = Pinger(c.Name)
where responseTime >=0
let pdcStatus = c.Roles.Contains(ActiveDirectoryRole.PdcRole)
orderby pdcStatus, responseTime
select new {DC = c, ResponseTime = responseTime}
).ToList();
foreach (var dc in dcsInOrder)
{
System.Console.WriteLine(dc.DC.Name + " - " + dc.ResponseTime);
}
System.Console.ReadLine();
}
private static int Pinger(string address)
{
Ping p = new Ping();
try
{
PingReply reply = p.Send(address, 3000);
if (reply.Status == IPStatus.Success) return (int)reply.RoundtripTime;
}
catch { }
return -1;
}
First, I'll answer the question that you actually asked:
System.DirectoryServices.ActiveDirectory.ActiveDirectorySite.GetComputerSite().Servers
But it seems like you're asking how to make sure that you're talking to the closest domain controller possible. Windows doesn't exactly provide this functionality, the best it will do is give you a domain controller in the same site that the code is running from.
I think the first thing to check is that you have your sites and subnets configured correctly. Run Active Directory Sites and Services, and make sure that subnets and domain controllers are assigned to the correct sites.
This MSDN page (and the Technet article in Peter's answer) says that you must be searching by the DNS name for the DC Locator to attempt to find a DC in the current site. I don't know if the Name property of the Domain class is the DNS domain name.
I have to assume that DomainController.FindOne is a wrapper for DsGetDcName. At that link, you can find how to turn on tracing for that function. You can use this if you still have problems, or maybe you should just PInvoke this function.
Here is a code sample that has no hard coding of DCs. Comments and criticism are welcome.
/// <summary>
/// For best results ensure all hosts are pingable, and turned on.
/// </summary>
/// <returns>An ordered list of DCs with the PDCE first</returns>
static LinkedList<DomainController> GetNearbyDCs()
{
LinkedList<DomainController> preferredDCs = new LinkedList<DomainController>();
List<string> TestedDCs = new List<string>();
using (var mysite = ActiveDirectorySite.GetComputerSite())
{
using (var currentDomain = Domain.GetCurrentDomain())
{
DirectoryContext dctx = new DirectoryContext(DirectoryContextType.Domain, currentDomain.Name);
var listOfDCs = DomainController.FindAll(dctx, mysite.Name);
foreach (DomainController item in listOfDCs)
{
Console.WriteLine(item.Name );
if (IsConnected(item.IPAddress))
{
// Enumerating "Roles" will cause the object to bind to the server
ActiveDirectoryRoleCollection rollColl = item.Roles;
if (rollColl.Count > 0)
{
foreach (ActiveDirectoryRole roleItem in rollColl)
{
if (!TestedDCs.Contains(item.Name))
{
TestedDCs.Add(item.Name);
if (roleItem == ActiveDirectoryRole.PdcRole)
{
preferredDCs.AddFirst(item);
break;
}
else
{
if (preferredDCs.Count > 0)
{
var tmp = preferredDCs.First;
preferredDCs.AddBefore(tmp, item);
}
else
{
preferredDCs.AddFirst(item);
}
break;
}
}
}
}
else
{
// The DC exists but has no roles
TestedDCs.Add(item.Name);
if (preferredDCs.Count > 0)
{
var tmp = preferredDCs.First;
preferredDCs.AddBefore(tmp, item);
}
else
{
preferredDCs.AddFirst(item);
}
}
}
else
{
preferredDCs.AddLast(item);
}
}
}
}
return preferredDCs;
}
static bool IsConnected(string hostToPing)
{
string pingurl = string.Format("{0}", hostToPing);
string host = pingurl;
bool result = false;
Ping p = new Ping();
try
{
PingReply reply = p.Send(host, 3000);
if (reply.Status == IPStatus.Success)
return true;
}
catch { }
return result;
}
Here's my approach using powershell but I'm sure it's a simple implementation in c#, etc. If DHCP is setup correctly, the Primary DNS server in your subnet should be the closest Domain Controller. So the following code should grab the first DNS IP and resolve it to the hostname of the closest DC. This doesn't require RSAT or credentials and contains no specific properties of the current domain.
$NetItems = #(Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "IPEnabled = 'True'" -ComputerName $env:COMPUTERNAME)
foreach ($objItem in $NetItems)
{
if ($objItem.{DNSServerSearchOrder}.Count -ge 1)
{
$PrimaryDNS = $objItem.DNSServerSearchOrder[0]
$domain = $objItem.DNSDomain
break
}
}
[System.Net.Dns]::GetHostbyAddress($PrimaryDNS).hostname -replace ".$($domain)",""

p4.net cannot connect Perforce

I am using p4.net API to generate some reports from the metadata.
In one of the reports, I need to generate then number of the changes lines for each changeset report.
As a reporting tool, I am using MS SQL Reporting services 2008, and I have written a custom dll that uses p4.net API to calculate the number of changed lines. it works on the local without any problem. However, when I run the code on the server, it calculates let's say first %20 part then starts throwing Unable to connect to the Perforce Server!
Unable to connect to Perforce! exception.
I try same credentials on the local, it works.. I use commandline with same credentials on the server, it works.
Could anyone help me with that please, if encountered before?
Here is the code I use. If needed
public static class PerforceLib
{
public static P4Connection p4conn = null;
private static void CheckConn()
{
try
{
if (p4conn == null)
{
p4conn = new P4Connection();
p4conn.Port = "address";
p4conn.User = "user";
p4conn.Password = "pwd*";
p4conn.Connect();
p4conn.Login("pwd");
}
else if (p4conn != null)
{
if(!p4conn.IsValidConnection(true, false))
{
Log("Check CONN : Connection is not valid, reconnecting");
p4conn.Login("pwd*");
}
}
}
catch (Exception ex )
{
Log(ex.Message);
}
}
public static int DiffByChangeSetNumber(string ChangeSetNumber)
{
try
{
CheckConn();
P4Record set = p4conn.Run("describe", "-s",ChangeSetNumber)[0];
string[] files = set.ArrayFields["depotFile"].ToArray<string>();
string[] revs = set.ArrayFields["rev"].ToArray<string>();
string[] actions = set.ArrayFields["action"].ToArray<string>();
int totalChanges = 0;
List<P4File> lstFiles = new List<P4File>();
for (int i = 0; i < files.Count(); i++)
{
if (actions[i].ToString() == "edit")
lstFiles.Add(new P4File() { DepotFile = files[i].ToString(), Revision = revs[i].ToString(), Action = actions[i].ToString() });
}
foreach (var item in lstFiles)
{
if (item.Revision != "1")
{
string firstfile = string.Format("{0}#{1}", item.DepotFile, (int.Parse(item.Revision) - 1).ToString());
string secondfile = string.Format("{0}#{1}", item.DepotFile, item.Revision);
P4UnParsedRecordSet rec = p4conn.RunUnParsed("diff2", "-ds", firstfile, secondfile);
if (rec.Messages.Count() > 1)
{
totalChanges = PerforceUtil.GetDiffResults(rec.Messages[1].ToString(), item.DepotFile);
}
}
}
GC.SuppressFinalize(lstFiles);
Log(string.Format("{0} / {1}", ChangeSetNumber,totalChanges.ToString() + Environment.NewLine));
return totalChanges;
}
catch (Exception ex)
{
Log(ex.Message + Environment.NewLine);
return -1;
}
}
}
your help will be appreciated
Many thanks
I have solved this issue. we identified that the code is circling through the ephemeral port range in around two minutes. once it reaches the maximum ephemeral port, it was trying to use same port again. Due to each perforce command creates a new socket, available ports were running out after it processed about 1000 changesets.
I have set the ReservedPorts value of HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters default(1433,143) that gave me larger range of ephemeral port.
and also implemented singleton pattern for P4Conn which helped as I dont close the connection. I only check the validity of the connection, and login if the connection is not valid.
Please let me know if any of you guys needs any help regarding this

Categories

Resources