Azure start-up task to run after the website is created - iis

I've created a start-up task for an Azure website that does the following:
Creates an AppPool
Converts a Virtual Directory into a Virtual Application
I've created a powershell script that carries out these tasks.
I've set up the startup element in the Service Definition
<Startup>
<Task commandLine="MyStartup.cmd" executionContext="elevated" taskType="simple">
</Task>
</Startup>
All good so far.
However, I've found out, rather late, that:
IIS may not be fully configured during the startup task stage in the
startup process, so role-specific data may not be available.
I take this to mean that the website may not exist on IIS when the powershell script is run. I've tested the script and sure enough it fails because it can't find the virtual directory on IIS.
My question is: Is there a way to ensure the powershell script is run after the website is created on IIS?
Please note, I don't really want to use Microsoft.WindowsAzure.ServiceRuntime.RoleEntryPoint.OnStart if possible.
Thanks in advance.

I followed on from #kwill's suggestion and created the following:
Powershell:
while(!($myWeb = Get-Website -name "*MyWeb*")){
Write-Host "Website not installed. Waiting 30 seconds..."
Start-Sleep 30
}
# Proceed with installation
and configuration
<Task commandLine="MyBackground.cmd" executionContext="elevated" taskType="background">
</Task>
This works.

Check out the role architecture diagram at http://blogs.msdn.com/b/kwill/archive/2011/05/05/windows-azure-role-architecture.aspx. You can see that the startup tasks are executed before IISConfigurator creates the application pool for your website. This means that the only place you can make modifications to the apppool is in OnStart.
I haven't tried this, but you could create a background type startup task which will let the rest of the startup process (ie. running IISConfigurator) proceed while your startup task is still running, and then within that startup just loop until the virtual directory is detected.

Related

Schedule IIS Reset on Azure Cloud Service

I have an Azure Cloud Service that requires some warm up when an application pool comes online (typically 5-10 minutes). Because of this, I like to schedule an IIS\App Pool recycle during off hours. When my recycle takes place mid-day, I get users yelling at me (and I prefer to not get yelled at)
What I've been doing is remoting into the VM, add a cmd file to a local disk and create a scheduled task that runs the cmd file:
net stop "World Wide Web Publishing Service"
net start "World Wide Web Publishing Service"
My problem is, periodically PaaS services get "refreshed", so randomly, any code\files I manually publish to a cloud service VM disappear. I need to remote back into the machines and re-add my cmd and scheduled tasks.
I know cloud services allow you to run startup tasks and the like. Can I do something similar to startup tasks that would allow me to package this cmd file when I publish my app, but schedule these commands externally? If so.. how?
Startup tasks may execute any unattended app/installer you include in your .cspkg. You need to make sure the cmd file in question is bundled properly (e.g add configureSchedule.cmd to project, make sure it's copied to output directory).
Since you're attempting to set up scheduling, you'll likely need to run your cmd in elevated mode:
<Startup>
<Task commandLine="configureSchedule.cmd" executionContext="elevated" taskType="simple" >
<Environment>
<Variable name="MyVersionNumber" value="1.0.0.0" />
</Environment>
</Task>
</Startup>
The better solution is to change the AppPool settings to recycle at a specific time. Do this from a startup script like David Makogan mentioned.
Take a look here:
Set default app pool recycling via command line
Set the recycling time:
https://www.iis.net/configreference/system.applicationhost/applicationpools/add/recycling/periodicrestart
Be sure to uncheck the "regular time interval", otherwise there will be recycle events during the day.
Also, you are stopping the WWW service, a quicker way is to only recycle the application pool. That way a new application pool is started, while the old one handles the last request from users. So there is (almost) no connectivity loss
appcmd recycle apppool /apppool.name: Marketing

Azure COM Objects

I am trying to move a website I am hosting on a server with IIS over to an Azure web site. I'm using a COM object but I'm not sure if I can register this? I found some posts talking about uploading the dll and registering it on start up but the article seems to be missing. Is this possible?
I had this exact problem registering legacy COM Components on Azure. I documented my methodology here:
AspPDF and AspJPEG on Windows Azure
Igorek is correct, you will need to use a Web Role to achieve this. The solution above is based on a single Web Role with a startup script to run regsvr32 as a startup task.
To summarise, there are essentially two parts to achieving this. First create a batch file to run the regsvr32 command:
chcp 1252>NUL
regsvr32 /s .\library\my-com-class.dll
exit /b 0
Then define a startup task in your ServiceDefinition.csdef file:
<Startup>
<Task commandLine="mybatchfile.cmd" executionContext="elevated" taskType="simple" />
</Startup>
This will trigger the command file to run on deployment.
You cannot register a COM object within an Azure Website. You will need to upgrade to Web Roles in order to do this. Registration of com object can happen during the startup scripts then.

Azure configuration with multiple tasks possible?

We have a third party .NET application which comes with its' own deployment tool. This deployment tool generates a custom startup.cmd file. We have an option to modify the CFG file but not the cmd file.
I would like to have my own cmd file. Could someone please confirm whether multiple tasks are allowed in a cloud service definition file?
For example...
<Startup>
<Task commandLine=”thirdpartyPropietryStartup1.cmd” executionContext=”elevated” />
<Task commandLine=”startup\startup2.cmd” executionContext=”elevated” />
</Startup>
Multiple startup tasks should work according to the documentation.
It is not that explicit but it states that
simple tasks are executed synchronously, one at a time, in the order specified in the ServiceDefinition.csdef file.
which would make no sense if multiple tasks would not work.
If there are issues you could always create a combined.cmd which runs thirdpartyPropietryStartup1.cmd and then startup\startup2.cmd (unless your executionContext should be different).

Azure: How to execute a startup task delayed?

I have two Sites within my WebRole and have defined a Startup task.
The first line works fine, it creates a new App pool for me:
%WINDIR%\system32\inetsrv\appcmd.exe add apppool /name:"VCPool" /managedRuntimeVersion:"v4.0" /managedPipelineMode:"Integrated"
Now I would like to change my second to this new created AppPool, but adding another line right after, doesn't help.
%WINDIR%\system32\inetsrv\appcmd.exe set app "WebRole_IN_0_VC/" /applicationPool:"VCPool"
It seems the second site is somehow not yet ready.
How can I delay my task by 30 seconds or delay appcmd.exe slightly?
Unless there is a way to create dependencies for this startup task that it shall only be executed when that second site is up and running?
Any help would be highly appreciated,
Many Thanks,
Is there a way to delay this execution by 30 seconds to make sure the second site is up and can be changed?
Update:
Thanks for the hints. I have made further investigation into this matter. I have found OnStart() event.
1) But since I am using silverlight and simply wrap the existing Web project in the Cloud Roles project, I wouldn't have a WebRole.cs as such. Can I just add it to my Silverlight Web project and use it there? Or is it recommended creating a WebRole project from scratch and make it to replace the Silverlight Web project alltogether?
2) Regarding the <Runtime/> tag in the service definition, do I simply add it like this? Would it have any security implications when the webrole runs elevated?
<WebRole name="WebRole" enableNativeCodeExecution="true" vmsize="ExtraSmall">
<Runtime executionContext="elevated"/>
<Sites>
<Site name="WebRole" physicalDirectory="./WebRole">
...
</Sites>
</WebRole>
3) Last but not least how do I run a cmd file or in fact this line
%WINDIR%\system32\inetsrv\appcmd.exe set site /site.name:"WebRole_IN_0_VC" /[Path='/'].applicationPool:"ASP.NET v4.0" >>Log.txt
in the OnStart() method?
Can you explore using PowerShell scripts for performing these tasks. PowerShell has a way to sleep thread. Something like
Batch file
%WINDIR%\system32\inetsrv\appcmd.exe add apppool /name:"VCPool" /managedRuntimeVersion:"v4.0" /managedPipelineMode:"Integrated"
powershell -command "Set-ExecutionPolicy Unrestricted" 2>> err.out
powershell .\sleep.ps1 2>> err.out
%WINDIR%\system32\inetsrv\appcmd.exe set app "WebRole_IN_0_VC/" /applicationPool:"VCPool"
I have not tried but it should work. See this post to know about Powershell integration.
The site, as you have discovered, is created after the 'Task' section runs. Instead, run your code from the 'OnStart' event. The site will have been created by that point. You may need to update your Service Definition file to run your role 'elevated' This can be done by adding this tag:
<Runtime executionContext="elevated"/>
Edited
To answer your further questions:
1) Whatever project you have, you should just be able to add the RoleEntryPoint class. You may have to do this manually.
2) Adding the runtime tag won't add any significant risk to your deployment.
3) Create a cmd file to put your command in (i.e. OnStart.cmd) and use some code like this:
System.Diagnostics.Process.Start("OnStart.cmd")
More information on starting a process here: http://msdn.microsoft.com/en-us/library/53ezey2s.aspx
For those interested ... I just blogged about how to execute AppCmd startup tasks on Windows Azure configure IIS websites - including finding the site by web role name, and executing it delayed so that the site config is already created by Azure's IISConfigurator.exe.
More here: http://mvolo.com/configure-iis-websites-windows-azure-startup-tasks-appcmd/.
Thanks,
Mike

Getting the full local path of a file in a site node in a webrole within a startup cmd file?

It's been several hours lost now, i just don't get it.
Situation :
- Migrating an ASP.net app to Azure
- IMPORTANT : This is a webrole with several websites, all websites are compiled in a folder "azure.builds" so my sites bindings are like
physicalDirectory="..\azure.builds\www.mywebsite.com"
physicalDirectory="..\azure.builds\cb.mywebsite.com"
and so on
I have a cmd script that works great on my dev machine, which set permission on IIS to execute on an exe file (it has to be called by an html form).
Here is my local code startup.cmd which works against my local IIS :
%windir%\system32\inetsrv\appcmd set config /section:system.webServer/handlers /+"[name='MY_GCI', path='.exe',verb='',modules='CgiModule', scriptProcessor='c:\websites\myproject\azure.builds\cb.mywebsite.com\cgi-bin\mymodule.exe',resourceType='Either']"
On my html form the file is called via action "http://cb.mywebsite.com/cgi-bin/mymodule.exe" and guess what it works.
But in my migration to Azure it doesn't, i'm unable to set permission to this particular file. The problem is i can't figure the full complete path to the EXE files as the example above show.
I tried this (%ROLEROOT%) :
%windir%\system32\inetsrv\appcmd set config /section:system.webServer/handlers /+"[name='MY_GCI', path='.exe',verb='',modules='CgiModule', scriptProcessor='%ROLEROOT%\azure.build\cb.mywebsite.com\cgi-bin\mymodule.exe',resourceType='Either']"
Does not work.
I studied several example involving similar CGI setup (such running PHP) but the difficulty is that the EXE module have to be exposed on http://cb.mywebsite.com/cgi-bin/mymodule.exe wich is not even the main root webiste on my azure webrole, so this is not exactly the same.
Sorry if it is not very clear to understand, let say in short : how to find the full local path of a particular file in a particular site node in a webrole within a startup cmd file ?
It appears you have this value outside of Azure:
scriptProcessor='c:\websites\myproject\azure.builds\cb.mywebsite.com\cgi-bin\mymodule.exe
Now you want the equivalent within Azure. The key for doing this is to use the ROLEROOT environment variable.
It appears you have considered ROLEROOT already, but perhaps there is a little bit off in mapping into your directory structure. I suggest you RDP into the Azure instance and get oriented (look at e:\approot for starters, but you are not guaranteed to always be there, thus the need for using ROLEROOT). RDP: http://msdn.microsoft.com/en-us/library/windowsazure/gg443832.aspx
If your real problem has to do with "...the difficulty is that the EXE module have to be exposed on http://cb.mywebsite.com/cgi-bin/mymodule.exe wich is not even the main root webiste on my azure webrole, so this is not exactly the same." then I am not sure I can help as I am unsure of issue you are describing. But one idea: RDP in (as mentioned above) and try to execute the CGI script by hand in Azure and see how that goes. If that doesn't work, you may have a path or permission problem. If it does work, you still may have a problem related to permissions (since the RDP account will have more power than your default IIS user).
A couple of other things to try: Ensure your Azure Web Role is running with elevated permissions by using the following setting in ServiceDefinition.csdef:
<WebRole name="WebHost">
<Runtime executionContext="elevated"/>
...
And also consider running your startup task elevated, also via ServiceDefinition.csdef:
<Startup>
<Task commandLine="startup.cmd" executionContext="elevated" />
</Startup>
And, finally, some StartUp Task debugging tips:
http://blog.smarx.com/posts/windows-azure-startup-tasks-tips-tricks-and-gotchas

Resources