I have a VS 2012 MVC 4 web role project and I successfully call a powershell script from the bin directory of the role, after I run Set-ExecutionPolicy Unrestricted
from a startup cmd. The script contains some azure cmdlets and when I run the project locally the script works perfectly. However when I publish the project on Azure, the same azure cmdlets in the script do not run. For example:
param([string]$websiteName="itudkcloudqwerdfs", [string]$serverLogin="user", [string]$serverPass="paSS123!@#", [string]$location="North Europe")
# Create new Website
#
$website = New-AzureWebsite -Location $location -Name $websiteName
if ($website -eq $null)
{
throw "Website creation error"
exit
}
creates an Azure website successfully when run locally but throws and exits when published and run from the cloud service.
Of course I googled around for a solution and I found that I have to pre-install Azure Powershell to the Web Role in order to run Azure cmdlets there. To do that, I installed the web platform installer 4.5, copied its command line tool executable with the Microsoft.Web.PlatformInstaller dll and my Azure publishsettings file to my Web Role's bin folder and I created a cmd that installs the Azure Powershell from webpicmd to a special folder in the Web Role's bin directory and imports my publishsettings file on Web Role startup:
md "%~dp0appdata"
cd "%~dp0appdata"
cd..
reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" /v "Local AppData" /t REG_EXPAND_SZ /d "%~dp0appdata" /f
"%~dp0\WebpiCmd.exe" /Install /AcceptEula /Products:WindowsAzurePowershell /log:%~dp0WindowsAzurePowershell.log
reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" /v "Local AppData" /t REG_EXPAND_SZ /d %%USERPROFILE%%\AppData\Local /f
powershell Import-AzurePublishSettingsFile
exit /b 0
It still didn't work, so I remotely logged in to the instance to see for myself what could be wrong. I tried to run the cmd script above and it required the .NET Framework 3.5 feature enabled, which looks weird to me since the instance already has the .NET 4.5 feature enabled by default (Windows Server 2012). Anyway, I enabled it from the server manager and the script ran successfully with no errors. I opened the powershell and I tested some Azure cmdlets and they worked. However, even after that, when I invoke the script again from the web app, it still doesn't run the azure cmdlets and exits.
What am I missing? And why does webpicmd requires the .NET 3.5 feature? Is there an alternative solution to this?
Update: After Gaurav's comment, I added this into my servicedefinition.csdef under the WebRole tag to run the webrole in an elevated execution context but the azure cmdlets are still not running in the script:
<Runtime executionContext="elevated" />
Update: Here's the C# code that invokes the script
//create command
string path = HttpContext.Server.MapPath("/bin/InitializeResources.ps1");
PSCommand cmd = new PSCommand();
cmd.AddCommand(path);
cmd.AddParameter("websiteName", websiteName);
cmd.AddParameter("serverLogin", username);
cmd.AddParameter("serverPass", password);
cmd.AddParameter("location", location);
//set the command into a powershell object and invoke it
Runspace runspace = RunspaceFactory.CreateRunspace();
PowerShell ps = PowerShell.Create();
ps.Commands = cmd;
try
{
runspace.Open();
RunspaceInvoke runSpaceInvoker = new RunspaceInvoke(runspace);
runSpaceInvoker.Invoke("Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force");
ps.Runspace = runspace;
Collection<PSObject> commandResults = ps.Invoke();
//save results
WebsiteInfo websiteInfo = new WebsiteInfo();
foreach (PSObject result in commandResults)
{
websiteInfo.Connectionstring = (string)result.Members["ConnectionString"].Value;
websiteInfo.WebsiteURL = (string)result.Members["WebsiteUrl"].Value;
websiteInfo.ftpUrl = (string)result.Members["SelfLink"].Value;
websiteInfo.ftpUrl = websiteInfo.ftpUrl.Substring(8);
int index = websiteInfo.ftpUrl.IndexOf(":");
if (index > 0)
websiteInfo.ftpUrl = websiteInfo.ftpUrl.Substring(0, index);
websiteInfo.ftpUrl = websiteInfo.ftpUrl.Replace("api", "ftp");
websiteInfo.publishUsername = (string)result.Members["Repository"].Value + "\\" + (string)result.Members["PublishUsername"].Value;
websiteInfo.publishPassword = (string)result.Members["PublishPassword"].Value;
}
runspace.Dispose();
runspace = null;
ps.Dispose();
ps = null;
}