The following code is throwing Exception. I don't get what mistake I am making in the code. Can somebody help me figure out please. I think it is of some security rights issue. If so, how can I give the security rights to any user or application to access this windows service programmatically?
Dim sc As New ServiceController
sc.ServiceName = "DataLoad"
If sc.Status = ServiceControllerStatus.Stopped Then
sc.Start()
Else
sc.Stop()
End If
Exception:
System.InvalidOperationException: Cannot open DataLoad service on computer '.'. --->
System.ComponentModel.Win32Exception: Access is denied --- End of inner exception stack trace --- at
System.ServiceProcess.ServiceController.GetServiceHandle(Int32 desiredAccess) at
System.ServiceProcess.ServiceController.Start(String[] args) at
System.ServiceProcess.ServiceController.Start() at
WEBSITE.DataLoad.Submit1_ServerClick(Object sender, EventArgs e) in C:\Inetpub\wwwroot\WEBSITE\a\DataLoad.aspx.vb:line 46
Thank you!
You can use the subinacl tool for that
SUBINACL /SERVICE \\MachineName\ServiceName /GRANT=[DomainName\]UserName[=Access]
To be specfic for your case:
subinacl /service DataLoad /GRANT=YOURDOMAIN\[User in appdomain for WEBSITE]=TO
Where TO means
T : Start Service
O : Stop Service
all options for [Access] are:
F : Full Control
R : Generic Read
W : Generic Write
X : Generic eXecute
L : Read controL
Q : Query Service Configuration
S : Query Service Status
E : Enumerate Dependent Services
C : Service Change Configuration
T : Start Service
O : Stop Service
P : Pause/Continue Service
I : Interrogate Service
U : Service User-Defined Control Commands
See Method 3 in this kb article
I found a solution to this problem by providing the machine name of the machine which is currently executing the service in the ServiceController overloaded constructor that takes 2(two) arguments i.e.
public ServiceController(/my service's name string/, System.Environment.MachineName/this machine which is executing the service/)
The version of .Net this solution was tested on was 4.5, hope this helps anyone still looking for a solution.
Here is what you need to do in code:
ServiceController serviceController = new ServiceController("myServiceName", System.Environment.MachineName);
GetServiceHandle requires some access rights. If it works when you run it as an Admin user, but not as a normal user, then maybe this article can help.
It clearly shows you how to manually give a Windows User rights to start and stop services (or set other permissions):
http://thommck.wordpress.com/2011/12/02/how-to-allow-non-admins-to-start-and-stop-system-services/
In my case, I determined that I needed to adjust the security on my service to allow it be be restarted by a separate "watchdog" service if my service fails.
First, open mmc.exe, then add the "Security Configuration and Analysis" and Security Templates" snap-ins.
Then create a new blank security template from the "Security Templates" item, give it a name, and hit OK to save it on your local disk drive somewhere convenient.
Then open "Security Configuration and Analysis" and choose "Open Database...", give it a name, and save it in the same directory as the previous step. When an "Import Template" window appears, open the *.inf file in the same directory.
Next, right-click "Security Configuration and Analysis" and choose "Analyze Computer..." The following will appear:
Double-click on "System Services", locate and double-click on your service, then click the checkbox "Define this policy in the database" and click on the "Edit Security" button.
This is where it becomes different than what is described in the link #JOG posted since I am using Windows 8.1--I enabled "start, stop and pause" for "INTERACTIVE" and "SERVICE"
FYI, I performed the above by following this guide as #JOG suggested: https://thommck.wordpress.com/2011/12/02/how-to-allow-non-admins-to-start-and-stop-system-services/
If you are already having the Service user as LocalSystem(the high privilage user) the problem is not security. Also I had that problem before and its the status vrs starting it again or stopping it when already commande to stop().
You see the service status its not changed on demand, so even if you coded
//this will start the process but the
//sc status will take some time to change
//when that happens and you try to start
//the already started service it will give you
//your error
servicec.start();
Soo you need to do this:
msdn ServiceController.waitforstatus
Dim sc As New ServiceController
sc.ServiceName = "DataLoad"
If sc.Status = ServiceControllerStatus.Stopped Then
sc.Start()
// this makes it wait for the status to change
// and no it wont slow down anything at all.
sc.waitforstatus(ServiceControllerStatus.started)
Else
sc.Stop()
sc.waitforstatus(ServiceControllerStatus.stopped)
End If
This will solve your problem like it did mine.
Related
goal
Change IIS bindings and swap virtual directories on a per request basis. A simple application will open, replace and commit, using the Microsoft.Web.Administration. Following is a simplified flow:
code
ServerManager = New ServerManager()
config = ServerManager.GetApplicationHostConfiguration()
SiteList = config.GetSection("system.applicationHost/sites")
SitesCollection = SiteList.GetCollection()
_site = SitesCollection.FirstOrDefault(Function(f) f.GetAttributeValue("name").ToString() = "XXX")
_bindings = _site.GetCollection("bindings")
_bind As ConfigurationElement = _bindings.CreateElement("binding")
_bind("protocol") = "http"
_bind("bindingInformation") = String.Format("*:80:{0}", "www.zzz.yyy")
_bindings.Add(_bind)
ServerManager.CommitChanges()
problem
This code run on an administrator authenticated web page, and before the call, the thread is impersonated to make sure the privileges are in place. I'm allowed to read the .config but not to write! I also confirmed that, before any call, the thread is running as Administrator. I also tried using a LocalService pool but again, no luck.
the error
Filename: \\?\C:\Windows\system32\inetsrv\config\applicationHost.config
Error: Cannot write configuration file due to insufficient permissions
hresult: 0x80070005
at Microsoft.Web.Administration.Interop.AppHostWritableAdminManager.CommitChanges()
After some checking and experiment I find out that the way to make it work was
Do not use authentication on the application.
Do not use impersonation.
LocalService does not work.
Run it on a pool with enough privileges (administrator)
Looks like using impersonation breaks it again.
This is NOT the setting I wanted but I think I can survive and move the app to this unsecure pool, work the changes and the move it back to a generic ApplicationPoolIdentity.
My desktop name is DOMAIN\MY-DESK. So the error is regard as to my desktop rather than my Windows credential.
I searched the web most of them are related to DOMAIN\UserName issue. The local report url is http://localhost/WebAdminOrion/Administrative/Reports
The report page is in a asp.net web application. I have the following code in the report page.
ReportParameter[] prm = new ReportParameter[Request.QueryString.Keys.Count - 1];
ReportViewer1.ServerReport.SetParameters(prm);
I get the error at the line of setting parameters.
By this, I think that the solution might be to configure the file. However the file C:\Program Files\Microsoft SQL Server\MSRS12.MSSQLSERVER\Reporting Services\ReportServer\rsreportserver.config has 292 lines. One section is
<Authentication>
<AuthenticationTypes>
<RSWindowsNTLM />
</AuthenticationTypes>
<RSWindowsExtendedProtectionLevel>Off</RSWindowsExtendedProtectionLevel>
<RSWindowsExtendedProtectionScenario>Proxy</RSWindowsExtendedProtectionScenario>
<EnableAuthPersistence>true</EnableAuthPersistence>
Not sure how to configure it.
Resolved it and shamed. The permissions granted to user 'servername/iusr-username' are insufficient for performing this operation. (rsAccessDenied)
You need to go into your SSRS ReportManager and configure the security settings.
Through Properties
-> Security -> New Role Assignment-> Then add the appropriate domain group. For my case, it needs to add by desk name as "DOMAIN\DESK$".
ASP.NET site hosted on Azure VM. ApplicationInsights Status Monitor installed on VM. Default ApplicationInsights.config created by "Add AppInsights" menu in Visual Studio, only custom initializer added instead of ikey:
<Add Type="WebSite.WebSiteTelemetryInitializer, WebSite" />
Code:
public class WebSiteTelemetryInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
TelemetryConfiguration.Active.InstrumentationKey = WebConfigurationManager.AppSettings["ikey"];
telemetry.Context.User.Id = Environment.UserName;
telemetry.Context.Session.Id = Guid.NewGuid().ToString();
telemetry.Context.Component.Version = typeof(WebSiteTelemetryInitializer).Assembly.GetName().Version.ToString();
}
}
All works as expected, but there is no performance data (Cpu, memory). After adding apppool user to Performance Monitor Users group:
$group = [ADSI]"WinNT://$Env:ComputerName/Performance Monitor Users,group"
$ntAccount = New-Object System.Security.Principal.NTAccount("IIS APPPOOL\DefaultAppPool")
$strSID = $ntAccount.Translate([System.Security.Principal.SecurityIdentifier])
$user = [ADSI]"WinNT://$strSID"
$group.Add($user.Path)
there is no data for dependency calls.
UPDATE
There are 3 repeating trace logs:
AI (Internal): Complete creating shadow copy of extension,
extensionBaseDirectory: C:\inetpub\wwwroot\site\bin, extensionName:
Microsoft.ApplicationInsights.Extensions.Intercept with error System.UnauthorizedAccessException: Access to the path 'C:\Windows\system32\config\systemprofile' is denied.
AI (Internal): Extension attach failure, unable to attach, baseFolder: C:\inetpub\wwwroot\site\bin, nativeExtensionName: Microsoft.ApplicationInsights.Extensions.Intercept
AI (Internal): [msg=RemoteDependencyModule failed];[msg=System.InvalidOperationException: Failed to attach extension, hresult: 2147500037
Remote dependencies:
Ok, so that is what is preventing ApplicationInsights from collecting dependencies:
AI (Internal): Complete creating shadow copy of extension, extensionBaseDirectory: C:\inetpub\wwwroot\site\bin, extensionName: Microsoft.ApplicationInsights.Extensions.Intercept with error System.UnauthorizedAccessException: Access to the path 'C:\Windows\system32\config\systemprofile' is denied.
C:\Windows\system32\config\systemprofile is what is set as a temp folder for your process. You need to change temp folder for the process and make sure that your application can write there. (ApplicationInsights is coping native binaries there that are used by profiler. Temp folder is also used when you have temporary internet access issues. It saves events that were not sent and sends them when connection is restored.)
Performance counters:
In order to collect performance counters the user that application pool runs under (usually it's ApplicationPoolIdentity) should be a member of Performance Monitor Users group on the box. Ensure that it's added there and you should do iisreset after adding the user to the group otherwise changes will not take effect.
Described here at the bottom:
http://blogs.msdn.com/b/visualstudioalm/archive/2014/12/11/updated-application-insights-status-monitor-to-support-12-and-later-application-insights-sdk.aspx
Just to add, you can change the temp folder that Application Insights writes to by editing the end of applicationsinsights.config file and adding the location of temp folder. Here's what I've done:
<TelemetryChannel Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.ServerTelemetryChannel, Microsoft.AI.ServerTelemetryChannel">
<StorageFolder>D:\AITempFolder</StorageFolder>
Hope this helps someone else too.
I have a Windows 2003 server running IIS 6 and have some scripts that do automated setup and creation of websites. They are not working on a new server I cam commissioning (they already work happily on 3 other W2K3 servers). The problem appear to boil down to WMI security on the IIS provider. The ASP code below represents the problem (although it is not the original code that causes the problem - this is a simplified demonstration of the problem).
Set wmiProvider = GetObject("winmgmts:\\.\root\MicrosoftIISv2")
If wmiProvider is Nothing Then
Response.Write "Failed to get WMI provider MicrosoftIISv2<br>"
End If
Response.Write "Querying for IISWebService...<br>"
Set colItems = wmiProvider.ExecQuery("Select * From IISWebServer",,0)
Response.Write "Error: " & Hex(Err.Number) & " (" & Err.Description & ")<br>"
If I run this in my browser, I get an access denied error reported after the ExecQuery call. I have set WMI access for the IUSR_ user from the Root branch all the way down. In fact, I can query for IP address information using the CIMV2 provider quite happily. If I put the IUSR user in the machine admins group it all works, but I don't really want to do that.
This must be a DCOM/WMI security problem, but I can't work out what else there is. Can anyone shed any light?
After reading G. Stoynev's comment asking if any events were logged in the Windows Logs, I checked the event logs on the server to which I'm attempting to access IIS remotely via WMI, and lo and behold I found an event with the following text:
Access to the root\WebAdministration namespace was denied because the namespace is marked with RequiresEncryption but the script or application attempted to connect to this namespace with an authentication level below Pkt_Privacy. Change the authentication level to Pkt_Privacy and run the script or application again.
See the code in this answer to the related SO question c# - "Access is denied" Exception with WMI.
Here's some example C# code that I added that seemed to resolve this issue for me:
ConnectionOptions options = new ConnectionOptions();
options.Authentication = AuthenticationLevel.PacketPrivacy;
ManagementScope managementScope = new ManagementScope(#"\\remote-server\root\WebAdministration", options);
// ...
If this is something that you intend to run as a tool for yourself or your admin (as opposed to the unwashed anonymous masses), here is a way I have used in the past (YMMV):
Set up a new directory in your website (e.g. /SiteCreate) and place your WMI scripts there
Configure a Windows user that has appropriate rights (probably admin in this case but you should use whatever is pertinent to your app)
Turn off the anonymous access to the directory you created in step 1 and then set the security to allow access only to the user you created in step 2 (turn on the authentication for that directory)
Now, when you navigate to that directory in your browser, you should get a login prompt. When you enter the username/password you created in step 2 your script will have the appropriate rights to perform your WMI requests.
Not a DCOM issue, more so a WMI security and encryption issue. Try changing the GetObject moniker to include impersonation and pktPrivacy, eg:
Set wmiProvider = GetObject("winmgmts:{impersonationLevel=impersonate;authenticationLevel=pktPrivacy}!\root\MicrosoftIISv2")
Refer to the follow MS article for more info:
http://msdn.microsoft.com/en-us/library/aa393618(v=vs.85).aspx
I'm having a problem getting access to a database which lives on a remote server.
I have a ASP.NET 2.0 webpage that is trying to connect to a database.
The database is accessed via a virtual folder (which I set up in IIS).
The virtual folder points at a remote share which contains the database.
The virtual folder (in the web apps root directory) is pointing at a share on a remote server via a UNC path:
\\databaseServerName\databaseFolder$\
The virtual folder has 'read' and 'browse' permissions set to 'true'.
I store the connection string in the 'appSettings' section of the web.config:
<add key="conStrVirtual" value="Provider=Microsoft.Jet.OleDb.4.0;Data Source=http://webAppServerName/virtualFolderName/databaseName.MDB;Jet OLEDB:Database Password=dumbPassword;"/>
The connection object is declard on my .aspx page:
Dim objConnVirtual As New OleDbConnection(ConfigurationManager.AppSettings("conStrVirtual"))
Here is the code that tries to use the connection object:
Public Sub Test()
If objConnVirtual.State <> ConnectionState.Open Then
objConnVirtual.Open()
End If
Dim cmd As OleDbCommand = New OleDbCommand("SELECT * FROM TableName", objConnVirtual)
objDR = cmd.ExecuteReader()
If objDR.Read() Then
response.write("Shazaam! Data shows up here")
End If
objDR.Close()
objConnVirtual.Close()
End Sub
When I run the above code I get the following error (on this line of the code 'objConnVirtual.Open()':
Exception Details: System.Data.OleDb.OleDbException: Not a valid file name.
I have checked the database name and it is correct (even copy/pasted it to make sure)
If I put the 'Data Source' section of the connection string into the address bar of my browser I can successfully see the contents of the share on the remote server.
Not sure if this is a problem with permissions or with the code.
I have googled the crap out of this but have not been able to find a solution.
Any help is much appreciated.
When accessing a remote Access MDB database, you have to specify a UNC path like \\remoteMachine\Share\test.mdb.
Make sure your application pool identity has the right permissions to connect to the remote share. By default on IIS 6 you are working with the Network Service account, which is by default not allowed to access a remote share.
The best way is to let the AppPool run with a dedicated service user.
What is the account being used on your server when your web app tries to read the db file? Whatever this user account is, it needs to have permissions to read that folder/file. In IIS6 you can configure the virtual folder to use any user account... on the Directory Security tab there's an Edit button under Authentication and access control.
It seems likely that your error message is just a generic error message, and the permissions problem is your real issue.
make sure the two servers have internal access to each other and also specify the ip & port of db server in your connection string .
Update
I should also mention that it works on my machine (but not once loaded up to the production box) if I declare the connection string in the 'appSettings' section of the web.config like this:
<add key="conStrVirtual" value="Provider=Microsoft.Jet.OleDb.4.0;Data Source=\\databaseServerName\databaseFolder$\databaseName.MDB;Jet OLEDB:Database Password=dumbPassword;"/>
This leads me to think that it could be an issue with needing to use domain credentials other than the local IUSER account.
UPDATE
First up, thank you to everyone who submitted answers.
However, we ended up not using the 'connect to remote database via virtual folder' method because the complexity of the permissions needed to get this to work was causing us more problems than it was worth. We put the UNC path back into the connection string, which may not be the best way to do this, but is working for us.