How to restarting server from an IIS process running on Azure? - c#

We're running a WCF service on Azure and we want to be able to restart the machine from code.
I've attempted the following methods:
Method 1 - Using Process.Start("shutdown.exe")
http://msdn.microsoft.com/en-us/library/vstudio/system.diagnostics.process.start
Problem with this method - IIS 7 has security by the application pool, and manually changing permissions/etc on Azure resets and can't be trusted.
I've attempted using icacls (http://technet.microsoft.com/en-us/library/cc753525.aspx) to give IIS permission to run shutdown.exe but unfortunately it seems that it doesn't work on files inside the system32 folder.
Method 2 - Calling RoleEnvironment.RequestRecycle
http://msdn.microsoft.com/en-us/library/microsoft.windowsazure.serviceruntime.roleenvironment.requestrecycle.aspx
We've used this function, it works well - however we require a full server restart and not just a role instance recycle.
Method 3 - Using Azure's REST API
http://msdn.microsoft.com/en-us/library/azure/gg441298.aspx
This so far looks the most promising method of achieving this, I was able to get this to work from my dev machine by generating a certificate, uploading it as a management certificate on the Azure portal, however, for the life of me I couldn't get the management certificate from the Azure instance itself.
So - If anyone can think of a way to make method 1 or 3 work is great, or if you can think of another option - it would be greatly appreciated.

Another option would be to use Azure Powershell cmdlets(http://azure.microsoft.com/en-us/documentation/articles/install-configure-powershell/).
You can then run Restart-AzureVM(http://msdn.microsoft.com/en-us/library/dn495199.aspx) + many other other management commands

I ended up using Method 3 (Using Azure's Management Libraries), and I used the base64 encoded management certificate inside the Publish settings file (which can be downloaded here https://windows.azure.com/download/publishprofile.aspx).
Inside there was the base64 string of the management certificate attached to my subscription.
Not the prettiest solution, but it works.

Related

Azure.Identity.VisualStudioCredential with IIS appPoolIdentity

I'm in my way to use Always Encrypted on an existing .Net Framework 4.8 WebApi codebase. The solutions runs locally (for development) on IIS on ApplicationPoolIdentity (Windows 10).
I've set up a sql query which accesses a SQL Server database with an encrypted column.
I'm using VisualStudioCredential locally to access the key vault.
Running the same code from a simple console app works, but when running on IIS VisualStudioCredential cannot access the token provider file under C:\WINDOWS\system32\config\systemprofile\AppData\Local.IdentityService\AzureServiceAuth\tokenprovider.json.
Indeed this file does not exists, it does exists in C:\Users\<my-username>\AppData\Local.IdentityService\AzureServiceAuth.
It tried running the pool under my own identity, but then it search the file C:\WINDOWS\system32\config\systemprofile\AppData\Local.IdentityService\AzureServiceAuth\tokenprovider.json which does not exists.
Any suggestion on how to get it to work would be appreciated.
[Edit]
I have tried pretty much all the TokenCredential implementation available under Azure.Identity with no success. I think VisualStudioCredential is the way to go, but I'm open to other suggestions. Even an interactive prompt would be OK for me since it is for development purpose, but InteractiveBrowserCredential fails on the worker process.
The link posted by #LexLi in the comments explains the problem.
Azure.Identity.VisualStudioCredential cannot be used with ApplicationPoolIdentity on IIS. The pool must run under the developer's name.
I ended up configuring an application in azure AD for dev environments and using clientId/clientSecret.

Update Exchange Server Certificate in C#

My goal is to update the Certificate for Exchange Servers from within a C# app, just like the Enable-ExchangeCertificate PS Cmdlet does.
I've already written an updater for IIS, which uses Microsoft.Web.Administration to access and manipulate IIS Sites and Bindings. I've searched through Google and VS Libraries for Exchange API tools, but without any luck. I can only find References to EWS (Exchange Web Services), which can't update the Server Certificate AFAIK.
Is there any API that can be used? How does Enable-ExchangeCertificate provide the functionality? I'm also thinking about just using the PS Cmdlet if all else fails, but I'd like to have a standalone app to rely on. No remote server management needed, localhost-only is fine.
tl;dr How to update a local Exchange Server Certificate in C#?
EDIT I'll look further into the EWS API (https://github.com/OfficeDev/ews-managed-api/blob/master/README.md), it looks like it might do the job. It provides Assemblies to access EWS data, but I haven't found any API Calls exclusively for Certificate Management.
There are multiple parts in MS Exchange which aren´t covered by an API. Mostly this is due to security reasons or as it´s quite complex and therefore no API needed (e.g. Exchange Schema update).
The normal Microsoft way included only two steps:
Make a Backup of the current configuration & SSL cert (Optional)
Import the certificate
Import-ExchangeCertificate -FileData ([Byte[]]$(Get-Content -Path
c:\certificates\YOUR_CERTIFICATE.cer -Encoding byte -ReadCount 0))
But some use MMC and that's working as well (so you might check for an API for MMC for this part).
Enable it
Enable-ExchangeCertificate -Thumbprint
1234ae0567a72fccb75b1d0198628675333d010e -Services POP,IMAP,SMTP,IIS
I would assume that there is no such API as its not really needed to have one. Normally an SSL certificate is valid for 3 years. So you need to run the command above 1x every 3 years and a 3rd party access to this part wouldn´t make any sense as it wouldn´t be often used and therefore Microsoft haven´t build one.
To give you more infos here. The SSL certificate information for Microsoft is saved in two locations. One in the local Regestry and one in Microsoft Active Directory (see here: uses the local instance of Active Directory Lightweight Directory Services (AD LDS) to read and write data). Dealing with changes to the ActiveDirectory without the way Microsoft supports might be VERY risky and would mean that Microsoft do not offer any support if that caused a problem. So I would use the powershell approach Enable-ExchangeCertificate in your app.
P.S. I would never ever run an unknown plugin on my Exchange server which do replace an SSL certificate which I can do via a simple powershell command. The plugin could cause a lot of other issues and can contain a lot of stuff which isn´t so "nice". So before you wast your time into that project think if there is really an audience for it.

Cannot programmatically access network path through VPN

I'm trying to use a network path (create directory, write and read files) from a Web Service in ASP.NET.
Everything works fine from my office where the network path is in the same LAN of my laptop, but when I try to connect to the network path through a VPN, the creation of a directory fails with "Access to path is denied" error.
The strange thing is that from Windows Explorer I can perfectly access such path, given my VPN credentials, that I stored in Windows Credentials Wallet.
I also tried to set my IIS App Pool Identity to 'Network Service' but no luck.
Can you help me please?
Thank you very much
EDIT:
When I try to execute a statement like
Directory.CreateDirectory(#"\\my\network\path");
from a simple console application project in my Visual Studio 2010 it works perfectly and the directory is created.
The problem is when I hit such a statement inside the business logic of my web service that is running under local IIS (and which I'm connected to via "Attach Process..." debug tool in VS2010)
I may not have all the details of what you're asking straight, but if you're running this service via Visual Studio and VPN, take a look at this great article, at CodeBetter.
runas /netonly /user:domain\username “C:\ProgramFiles\Path\to\your\visualstudio”
I don't have the computer I have this on in front of me, but I recall that I created a batch file and ran it to start VS and Sql Server Management Studio, and it works like a charm.
If I've misunderstood the issue, sorry for the noise.
Sounds like when you are running locally, your local domain account is the context under which everything is being ran. When running the console app, it is still running under your user context since you initiated the application. When running in IIS, you are correct in that the app-pool account is being used, and the networkservice account has some pretty low privileges.
Instead of using a highly privileged account (such as yours), would impersonation solve your issue? Any work that needs to be done over the VPN can "wrapped" in a context the appropriate permissions. Here is another SO article on using impersonation, which I have implemented for related things:
How do you do Impersonation in .NET?
See Matt Johnson's answer where he creates a custom Impersonation class. Use that in a using block, then do your network stuff. It uses the advapi32.dll with p/invoke to do this kind of user account voodoo. He put together a NuGet package as well which may save you some time:
https://www.nuget.org/packages/SimpleImpersonation

How does one Reset IIS/Run Batch files via an ASP.NET MVC 4 Web Application Remotely?

I am trying to make a web service for my MVC C# app that will allow administrators to perform an iis reset by triggering a batch file with all the commands we use.
The website is hosted on a remote machine so this is not local. Security is in place for the web service to prevent this being triggered maliciously.
How would I go about doing this? I've tried
System.Diagnostics.Process.Start(#"c:\iisresetTest.bat");
This gave no errors, but it did not perform the reset.
I've also tried the directions here: http://labs.ratchet.com/566/running-command-line-bat-files-from-web-page-asp-net-c/
But that gave an error that I need to be an admin to run the command. I'm assuming the first line of code worked, but since it wasn't an admin it probably just closed down command prompt.
You can run a bat file as administrator using the scheduled task work around http://www.sevenforums.com/general-discussion/307201-how-run-batch-bat-flle-administrator.html I couldnt find the better page for that but you might find it googling. You can also go in the registry and turn UAC off but that could be dangerous.

How to start process from ASP.NET Web Service (and allow to it to do everything what it wants to do)?

There is a Web Service installed on Amazon Server. Exposed WebMethod should start an executable. But, it seems that process (executable) started by WebMethod has not permissions to finish its job. If a WebMethod is called locally (using IE on Amazon VM) I can trace some events into log file placed on the path: C:\\LogFiles. But, if it is called from remote machine, there is no even log files. Locally, on my machine all works fine.
The question: is there any way or settings in IIS7 to allow to my WebService to create process that can do everything I want to do? In web.config file I added a line:
<identity impersonate="true" userName="USERNAME" password="password"/>
(userName and password are, of course, written correctly in the file).
Also, I tried to use impersonization as it is explained here, but there is no result. My process can't do its job, it cannot even trace actions into log file. Locally, on my machine, everything works fine.
Any idea how to change settings or whatever into IIS7?
EDIT: In addition to the main question: my WebService is not able even to create log files on the path: C:\\LogFiles - although it is able if it started locally, but remotely there is no simple log file that contains some string. How to allow it to create simple text files?
If all else fails, you may start such a process separately and make it wait for a signal. You can supply a signal in many ways — via an IP socket, via a mailslot, via a named pipe. The web service will post requests to the command pipe (or queue), and the 'executor' process will pop commands, execute them, and wait for more commands.
You should avoid trying to start external processes from ASP.NET - if anything, because your application will then be running under the context of the ASP.NET account. (Yes, you could use impersonation to launch into another account, but, lets not go there)
Instead, install a Windows Service which can receive a signal* to launch the executable you wish.
This has the advantage that you can customise what account the service runs under, without putting passwords inside your code.
(*) Signalling could be achieved through a number of means:
WCF Service Call (using a WCF Service being hosted by the Windows service)
Monitoring for a filesystem change to a known directory.
If you were using Linux, I would have given you the smartest solution ever, setting SUID flag, which is not possible in Windows.
The problem with impersonation is that it works as soon as you have some control over the server machine, more than having appropriate credentials.
You mentioned Amazon VM: I'm pretty certain that they won't allow, for security reasons, to perfrom impersonation. [Add] Or, better, they won't allow anybody to write in C:\
Option 1
Switch to Mono/Linux, set SUID bit using chmod from console and rock!!
Option 2
If you can run the executable other way than ASP.NET (ie. you have a Remote Desktop, SSH*) as privileged account (note: privileged doesn't mean Administrator) then you can redesign your application to have ASP.NET invoke services from your daemon process using WCF, Web Services or Remoting. But, in this case, you have to redesign your executable to be a stand-alone server.
[Add] None of the solution fix if your hosting provider doesn't allow you to write in paths such as C:\, but only allows you to write under your home directory.
*It works on Windows too!!!! And I mean the server!!!

Categories