I have an unusual situation in which I need a SharePoint timer job to both have local administrator windows privileges and to have SHAREPOINT\System SharePoint privileges.
I can get the windows privileges by simply configuring the timer service to use an account which is a member of local administrators. I understand that this is not a good solution since it gives SharePoint timer service more rights then it is supposed to have. But it at least allows my SharePoint timer job to run stsadm.
Another problem with running the timer service under local administrator is that this user won't necessarily have SHAREPOINT\System SharePoint privileges which I also need for this SharePoint job. It turns out that SPSecurity.RunWithElevatedPrivileges won't work in this case. Reflector shows that RunWithElevatedPrivileges checks if the current process is owstimer (the service process which runs SharePoint jobs) and performs no elevation this is the case (the rational here, I guess, is that the timer service is supposed to run under NT AUTHORITY\NetworkService windows account which which has SHAREPOINT\System SharePoint privileges, and thus there's no need to elevate privileges for a timer job).
The only possible solution here seems to be to run the timer service under its usual NetworkService windows account and to run stsadm as a local administrator by storing the administrator credentials somewhere and passing them to System.Diagnostics.Process.Run() trough the StarInfo's Username, domain and password.
It seems everything should work now, but here is another problem I'm stuck with at the moment. Stsamd is failing with the following error popup (!) (Winternals filemon shows that stsadm is running under the administrator in this case):
The application failed to initialize properly (0x0c0000142).
Click OK to terminate the application.
Event Viewer registers nothing except the popup.
The local administrator user is my account and when I just run stsadm interactively under this account everything is ok. It also works fine when I configure the timer service to run under this account.
Any suggestions are appreciated :)
I'm not at work so this is off the top of my head, but: If you get a reference to the Site, can you try to create a new SPSite with the SYSTEM-UserToken?
SPUserToken sut = thisSite.RootWeb.AllUsers["SHAREPOINT\SYSTEM"].UserToken;
using (SPSite syssite = new SPSite(thisSite.Url,sut)
{
// Do what you have to do
}
The SharePoint Timer jobs runs with the SharePoint Firm Admin credentials since, the information get into the SharePoint Config Database. Thus the application pool will not have the access.
For testing the timer job in dev environment, we can temporarily change the application pool account to the application pool account being used for Central Administration.
Other applications if run this way (i.e. from a timer job with explicit credentials) are failing the same way with "The application failed to initialize propely". I just worte a simple app which takes a path of another executable and its arguments as parameres and when run from that timer job it fails the same way.
internal class ExternalProcess
{
public static void run(String executablePath, String workingDirectory, String programArguments, String domain, String userName,
String password, out Int32 exitCode, out String output)
{
Process process = new Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
StringBuilder outputString = new StringBuilder();
Object synchObj = new object();
DataReceivedEventHandler outputAppender =
delegate(Object sender, DataReceivedEventArgs args)
{
lock (synchObj)
{
outputString.AppendLine(args.Data);
}
};
process.OutputDataReceived += outputAppender;
process.ErrorDataReceived += outputAppender;
process.StartInfo.FileName = #"C:\AppRunner.exe";
process.StartInfo.WorkingDirectory = workingDirectory;
process.StartInfo.Arguments = #"""" + executablePath + #""" " + programArguments;
process.StartInfo.UserName = userName;
process.StartInfo.Domain = domain;
SecureString passwordString = new SecureString();
foreach (Char c in password)
{
passwordString.AppendChar(c);
}
process.StartInfo.Password = passwordString;
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
exitCode = process.ExitCode;
output = outputString.ToString();
}
}
AppRunner basically does the same as the above fragment, but without username and password
Related
I want to call an executable file from a web application hosted within IIS 10.
When I run my application locally with IIS Express everything works fine, but after deploying on the production server, I only get the exit code -1073741819.
On the product server I gave full rights for the user of the application pool in the folder, where the exe file is located, but that did not work as well.
Do I have to set other, special rights to the user?
This is my code ...
ProcessStartInfo procStartInfo = new ProcessStartInfo(libreExecutable.FullName, argument);
procStartInfo.CreateNoWindow = true;
procStartInfo.UseShellExecute = false;
procStartInfo.WorkingDirectory = workingDirectory;
procStartInfo.RedirectStandardInput = true;
procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardError = true;
// This is empty with code -1073741819
process.StandardError.ReadToEnd();
-1073741819 is 0xC0000005, that means ERROR_ACCESS_DENIED. IIS doesn't have permission to call the .exe file.
I gave full rights for the user of the application pool in the folder
I don't know how you do. But it is better to add IIS APPPOOL\pool name in folder security property and set it full control permission.
If it still report this error, please try to change the application pool identity. Administrator has the highest authority, try to change identity to administrator.
I have created a simple console project with the following code:
using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var farm = SPFarm.Local;
Console.WriteLine(SPFarm.Local);
Console.ReadLine();
}
}
}
The SP2013 Server is installed in a virtual server from Cloudshare. There is another vm for the SQL Server 2012 and another one for the Active Directory 2012 (domain is AD2012.loc).
When I open the project using the AD2012.loc/Administrator account, it works perfect. But when I open it using my account (which is in AD2012.loc and in the Administrators group) SPFarm.local is null.
I know is a permission thing but since I have to rely on this SPFarm.Local object to use in another project, that will be executed in several servers where I don't have access to and I can't be sure they will executed as the Administrator, is there anything I can do to maybe impersonate the code to run as the SPFarm admin or something?. I have tried runned with the SPSecurity.RunWithElevatedPrivileges with no luck.
UPDATE
I've tried running the above code impersonating the SPAdmin user but still getting null.
I can't just give access to the user because this will run in client machines, and I can't tell them to give access to the SPConfig db. So I need a way to do it in the code, impersonating or something.
I am not sure about this will work or not
i will give you two links hopw any one will work for you.
SPFarm.Local is return null
OR
http://blogs.msdn.com/b/ekraus/archive/2009/11/13/sp2010-spfarm-local-is-null-or-web-application-could-not-be-found.aspx
I Want to create a website in IIS using powershell script.I write this code in a window service.
protected override void OnStart(string[] args)
{
string sitename = "rajesh";
//To create a New site
//Powershell script
string script = "cd\\\n" + "import-Module WebAdministration \n" + "IIS:\n" + "New-item iis:\\Sites\\rajesh -PhysicalPath C:\\inetpub\\wwwroot\test -bindings #{Protocol='http';bindingInformation='*:8080:" + sitename + "'}" + "\n add-content C:\\Windows\\System32\\drivers\\etc\\Hosts '127.0.0.1 " + sitename + "'";
string s = RunScript(script);
}
private static string RunScript(string scriptText)
{
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(scriptText);
pipeline.Commands.Add("Out-String");
Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
return stringBuilder.ToString();
}
But when i try to start this window service in services listing...It throws an error.. The services on locat computer start and stopped..... When i change the powershell script to Create a folder or some small task then this window service is working but when i try to create a website through this powershell..it throws an error and window service can't be started.This powershell script is working in powershell.But not in window service..
The error produced would be helpful.
Sitename isn't a variable either, is that atypo here or in the code?
You could try replacing the \n with ; as well, powershell doesn't use that as new line, though i guess the C# is.
There's a couple of things to note here and I think you maybe don't understand some aspects of Windows Services:
OnStart is not the place to be putting any kind of logic. This event is there so you can initialise the service. For example starting a background worker thread that would run the main logic of the service and respond to external requests. For example - starting a TCP listener or initialising .NET Remoting or WCF.
OnStart is only called once when the service starts.
OnStart must return within 30 seconds although your initialisation code can request additional time.
You're calling out to PowerShell and the WebAdministration add-in to create websites. Whilst this is doable, it's clunky, perhaps you should consider calling directly into the IIS7 Managed API's:
Microsoft.Web.Administration Namespace
Here's an example of creating a site using the managed API's:
using (ServerManager serverManager = new ServerManager())
{
Site site = serverManager.Sites.Add("My Web Site", "C:\\inetpub\\wwwroot\test", 80);
site.Bindings.Clear();
site.Bindings.Add("*:8080:", "http");
serverManager.CommitChanges();
}
It should also be noted that any configuration tasks performed on IIS require that the account doing this have elevated privileges i.e. be an Administrator or if it's a service run under the SYSTEM account.
Warning: I'm an asp.net developer taking my first steps in SharePoint.
So, i'm writing a console application that connects to a SharePoint Server 2007 site on the same machine, but it seems that something goes wrong during the call to SPSite() constructor. Here's the simplified code:
using (SPSite siteCollection = new SPSite("http://server/AwesomeSite"))
{
//when i set a breakpoint on this line and inspect the siteCollection object,
//most of it's properties (for example siteCollection.AllWebs.Names) throw an
//exception, which leads me to the conclusion that something went wrong during
//the constructor above.
SPWebCollection site = siteCollection.AllWebs;
SPWeb web = site[""];
SPList list = web.Lists["AwesomeList"]; //exception occurs here
}
The SPException text:
Operation aborted (Exception from HRESULT: 0x80004004 (E_ABORT))
I followed the advice of Sharepoint SPSite and checked that:
The user is a server farm administrator.
The user has Read and Write permissions on the content database.
The user is a site collection administrator.
The user has permissions to access the Windows SharePoint Services site or the SharePoint Server 2007 site through which the code iterates.
And they are all correct. What else could be causing this to happen?
In my experience, the SPSite() constructor is highly dependent on the Alternate Access Mappings configuration of your site. Make sure that the URL you are using in the constructor appears in the list of mappings (e.g., http vs. https, machine vs. FQDN).
You need to get more debug information.
Using Visual Studio
Try setting the debugger to break on all exceptions. Go to Debug, Exceptions and tick Common Language Runtime Exceptions. Then go to Tools, Options, Debugging and untick Enable Just My Code. Finally attach to w3wp.exe. Try running your console application now and you should find that it triggers an exception in w3wp.exe. Check the stack trace and see if that gives you more information.
Using dump files
You could also try working from a crash dump. This is admittedly significantly more hard-core but should give you the detail you are otherwise lacking. The tool ProcDump will can be attached to w3wp.exe (provided the -s switch isn't used) and will create a dump if an unhandled exception occurs. If you have trouble with ProcDump, try ADPlus which does something similar.
From the created dump file, use this KB article to set up WinDbg and get started. There is an example case of how to use WinDbg on Tess Ferrandez's blog (Strategy #2).
Have you tried to run the code with elevated privileges?
Does the IIs have some kind of funky settings regarding authentication? (Try Windows auth. only)
Unfortunately, there are hundreds of ways to generate this error. Just ask Google.
You might consider using SPTraceView to get a better description of the error. Here's a description of the tool and an example working an issue with it.
Good luck!
I have similar (not equals) problem. I've solved it with this piece of code:
using( SPSite site = ConnectToSharepointAsSystem() ) {
// now should be all ok
}
// somewhere in helper class ->
public static SPUserToken GetSystemToken(SPSite site) {
SPUserToken token = null;
bool tempCADE = site.CatchAccessDeniedException;
try {
site.CatchAccessDeniedException = false;
token = site.SystemAccount.UserToken;
}
catch (UnauthorizedAccessException) {
SPSecurity.RunWithElevatedPrivileges(() => {
using (SPSite elevSite = new SPSite(site.ID))
token = elevSite.SystemAccount.UserToken;
});
}
finally {
site.CatchAccessDeniedException = tempCADE;
}
return token;
}
public static Microsoft.SharePoint.SPSite ConnectToSharepoint() {
string urlSharepointSite;
var ret = ConnectToSharepoint(out urlSharepointSite);
return ret;
}
public static Microsoft.SharePoint.SPSite ConnectToSharepoint(out string urlSharepointSite) {
urlSharepointSite = "http://www.domain.org";
var site = new Microsoft.SharePoint.SPSite( urlSharepointSite );
return site;
}
public static Microsoft.SharePoint.SPSite ConnectToSharepointAsSystem() {
string urlSharepointSite;
Microsoft.SharePoint.SPUserToken userToken = null;
using (var tmpSite = CSharepointNastroje.PripojitNaSharepoint( out urlSharepointSite )) {
userToken = GetSystemToken(tmpSite);
}
var site = new Microsoft.SharePoint.SPSite(urlSharepointSite, userToken);
return site;
}
This is a question for a WSS/SharePoint guru.
Consider this scenario: I have an ASP.Net web service which links our corporate CRM system and WSS-based intranet together. What I am trying to do is provision a new WSS site collection whenever a new client is added to the CRM system. In order to make this work, I need to programmatically add the managed path to the new site collection. I know that this is possible via the Object Model, but when I try it in my own web service, it fails. Sample code extract below:
Dim _ClientSiteUrl As String = "http://myintranet/clients/sampleclient"
Using _RootWeb As SPSite = New SPSite("http://myintranet")
Dim _ManagedPaths As SPPrefixCollection = _RootWeb.WebApplication.Prefixes
If Not (_ManagedPaths.Contains(_ClientSiteUrl)) Then
_ManagedPaths.Add(_ClientSiteUrl, SPPrefixType.ExplicitInclusion)
End If
End Using
This code fails with a NullReferenceException on SPUtility.ValidateFormDigest(). Research suggested that this may be due to insufficient privileges, I tried running the code within an elevated privileges block using SPSecurity.RunWithElevatedPrivileges(AddressOf AddManagedPath), where AddManagedPath is a Sub procedure containing the above code sample.
This then fails with an InvalidOperationException, "Operation is not valid due to the current state of the object."
Where am I going wrong?
One workaround I have managed to do is to call out to STSADM.EXE via Process.Start(), supplying the requisite parameters, and this works.
Update: whilst developing the web service, I am running it using the built-in Visual Studio 2005 web server - what security context will this be running under? Can I change the security context by putting entries in web.config?
Update: I think the problem is definitely to do with not running the web service within the correct SharePoint security context. I decided to go with the workaround I suggested and shell out to STSADM, although to do this, the application pool identity that the web service runs under must be a member of the SharePoint administrators.
Update
I think you have proved that the issue is not with the code.
SPSecurity.RunWithElevatedPrivileges: Normally the code in the SharePoint web application executes with the privileges of the user taking the action. The RunWithElevatedPrivileges runs the code in the context of the SharePoint web application pools account (i think)
The description on MSDN could go into the details a tiny bit more.
The issue with the call may be that the web service is not actually running the code within a SharePoint process, so explaining why it cannot elevate (wild guess alert).
Have a crack at changing the user of your web services application pool and see if that gives any joy.
It is likely to be a permissions issue.
Maybe try:
Dim clientSiteUrl As String = "http://myintranet/clients/sampleclient"
Using SPSite = new SPSite(clientSiteUrl)
webApp As SPWebApplication = SPWebApplication.Lookup(new Uri(clientSiteUrl));
If Not (webApp.Prefixes.Contains(clientSiteUrl)) Then
webApp.Prefixes.Add(clientSiteUrl, SPPrefixType.ExplicitInclusion)
End If
End Using
This is not exact code.
Since the above code is not the exact code, here is the exact working code for a Web Application scopped feature in the Feature Activated event:
On feature activation at the Mange web application features page, activate feature will create a new Explicit managed path in the specified web application (I want to replace the hard coding, maybe with Properties.Feature.Parent, or something similar.)
using (SPSite site = new SPSite("http://dev-moss07-eric/PathHere")) {
SPWebApplication webApp = SPWebApplication.Lookup(new Uri("http://dev-moss07-eric"));
if (webApp.Prefixes.Contains("PathHere"))
{
//
}
else
{
webApp.Prefixes.Add("PathHere", SPPrefixType.ExplicitInclusion);
}
}
Code can probably be improved, but its my attempt at converting the above code.
If you want to create a managed path (explicit) and a site collection at that path, do the following:
using (SPSite site = new SPSite("http://dev-moss07-eric")) {
SPWebApplication webApp = SPWebApplication.Lookup(new Uri("http://dev-moss07-eric"));
if (webApp.Prefixes.Contains("ManagedPathHere"))
{
//
}
else
{
webApp.Prefixes.Add("ManagedPathHere", SPPrefixType.ExplicitInclusion);
}
using (SPWeb web = site.OpenWeb())
{
SPWebApplication webApplication = web.Site.WebApplication;
try
{
webApplication.Sites.Add("ManagedPathHere","Site Title Here","This site is used for hosting styling assets.", 1033, "STS#1", "6scdev\\eric.schrader", "Eric Schrader", "eric.schrader#6sc.com");
}
catch (Exception ex)
{
//ex.ToString;
}
}
}