SSRS Report Portal Management - c#

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

Related

SharePoint 2013: Why getting 500 error while creating clientContext?

I want to create a IIS webservice which has to write list items to SharePoint on Premise.
I want to use CSOM and try to create a ClientContext.
public string AddListItem()
string result = string.Empty;
string siteUrl = "https://serverUrl";
using (ClientContext context = new ClientContext(siteUrl))
{
context.Credentials = new NetworkCredential("User", "Password", "Domain");
List list = context.Web.Lists.GetByTitle("Test");
context.Load(list);
context.ExecuteQuery();
}
return result;
}
While executing, I get an error at context.ExecuteQuery();
System.Net.WebException: 'The remote server returned an error: (500) Internal Server Error.'
In the Event Log, I see following error:
WebHost failed to process a request.
Sender Information: System.ServiceModel.ServiceHostingEnvironment+HostingManager/41028758
Exception: System.ServiceModel.ServiceActivationException: The service '/_vti_bin/client.svc' cannot be activated due to an exception during compilation. The exception message is: Operation is not valid due to the current state of the object.. ---> System.InvalidOperationException: Operation is not valid due to the current state of the object.
at Microsoft.SharePoint.Administration.SPWebApplication.get_Context()
................................
In debugging, I also see after creating the ClientContext and before context.ExecuteQuery(); following error at some properties of ClientContext, e.g.:
ServerLibraryVersion = 'context.ServerLibraryVersion' threw an exception of type 'Microsoft.SharePoint.Client.PropertyOrFieldNotInitializedException'
Your code seems fine for on-prem SharePoint. I think You should check some settings on the farm that my be the cause of that.
Please check the services on farm server if the IIS Admin Service is on
also on SharePoint CA check the user profile service and the claims to windows token service (both should be on)
... sorry for the lang :)... usually I have access to SharePoint in PL language, but I tried to translate the most important stuff to ang.
Please also check if on IIS the app pools that You try to access are working correctly. I suppose yes, otherwise You would have a lot of other errors, but it's always better to check.
Use CSOM, what to use WCF is not clear:
ClientContextctx = newClientContext("http://gowtham.sharepoint.com");
List oList = ctx.Web.Lists.GetByTitle("Announcements");
ListItemCreationInformationitemCreateInfo = newListItemCreationInformation();
ListItemnewItem = oList.AddItem(itemCreateInfo);
newItem["Title"] = "Test Item!";
newItem["Body"] = "welcome to Gowtham Blog";
newItem.Update();
context.ExecuteQuery();
Try below code
using (ClientContext clientContext = new ClientContext(ServerURL))
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var securePassword = new SecureString();
foreach (char c in password)
{
securePassword.AppendChar(c);
}
clientContext.Credentials = new SharePointOnlineCredentials(your_mail_ID, securePassword);
Web web = clientContext.Web;
var list = web.Lists.GetByTitle("your_list_name");
clientContext.Load(list.RootFolder);
clientContext.ExecuteQuery();
}
Check if the "SharePoint Web Servies Root" application pool was stopped or the "SharePoint Web Services" web application not start in IIS.
Go to IIS Application Pools, find the "SecurityTokenServiceApplicationPool" and click "Advanced Settings" from the action panel, then Scroll to "ProcessModel" section and change the Identity to your SharePoint Farm Account and do IISRESET.
And create a console application with the CSOM C# code to check if it works.
FWIW - I had exactly the same error - CSOM local mode to on-prem SP2016 with a 500 error requesting the list by title.
I had just applied a 10/2019 SharePoint update, but hadn't gone through Product Configuration Wizard and the prompts in Central Admin. Once I did that, CSOM requests worked again.

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;

Impersonation EPM using PSI or CSOM

For a project I have to sync hours from an external program to EPM. There is no requirement to use the Client Side Object Model of EPM 2013 or the PSI. But because Microsoft recommends the CSOM on their website for all new applications I tried to implement it with the CSOM. The first thing I wanted to test is to get all the hours, with the following code: (It isn't the most beautiful code because it is for testing purposes)
private static void GetTimesheets()
{
ProjectContext projContext = new ProjectContext("http://tfspsdemo/PWA/");
projContext.Load(projContext.TimeSheetPeriods);
projContext.ExecuteQuery();
foreach (var period in projContext.TimeSheetPeriods)
{
projContext.Load(period.TimeSheet);
projContext.ExecuteQuery();
Console.WriteLine(period.Name);
try
{
string tempName = period.TimeSheet.Name;
projContext.Load(period.TimeSheet.Lines);
projContext.ExecuteQuery();
Console.WriteLine(period.TimeSheet.Name);
foreach (var line in period.TimeSheet.Lines)
{
try
{
projContext.Load(line);
projContext.Load(line.Work);
projContext.ExecuteQuery();
foreach (var workLine in line.Work)
{
Console.WriteLine(workLine.ActualWork);
}
}
catch (Exception) { }
Console.WriteLine("Total: {0}", line.TotalWork);
}
}
catch (ServerObjectNullReferenceException) { }
}
}
But with above code I get only the code for the current user that is logged in, even if it is a person with rights to see other users hours. But what I want is to see all the hours of all the persons that have booked hours in EPM for a specific project plan. So I can later use this information to sync the hours from an external program to EPM. I thought I can solve this with impersonation but:
ProjectContext projContext = new ProjectContext("http://tfspsdemo/PWA/");
projContext.Credentials = new NetworkCredentials("username", "password");
But this isn't what I want because I have to do this for each user. And also I can't get the passwords of all users.
Does anyone now a solution to solve this problem and/or any suggestions? Solutions with the EPM PSI are also appreciated!
Thanks in advance!
Impersonation is not yet implemented in Project Sever 2016/Project Online. Please vote here: https://microsoftproject.uservoice.com/forums/218133-microsoft-project/suggestions/32981722-impersonation-support-for-csom-to-read-other-user
Thanks,
Werner
There are two modes in Proect server 2013. Proect server and SharePoint mode. I was able to get the above working in SharePoint mode, but alas I cannot read even Timesheet Periods as it says CSOMUnkownUser in Project server mode even after passing in the credentials. What mode are you running in currently on the server
This is probably a little late, but to access that kind of data in a provider/auto hosted app you need to access the sharepoint server through OData. CSOM is only intended to provide data from the current user context.

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