1
votes

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;
}
2
Can you check the event logs and see if anything's logged under there? Also taking a complete wild guess, could this be related to permissions associated with the user account under which web role is running? You could try running the web role with elevated privileges [Again ... just a guess]Gaurav Mantri
The event logs don't show anything related. As for the powershell script, I invoke it from C# by using a PSCommand object. Isn't the Set-ExecutionPolicy Unrestricted enough to resolve privileges issues? If not how can I programmatically in C# elevate them before I run the script?almamouz

2 Answers

0
votes

I'm facing a similar problem as you can see in this thread I couldn't see any exception in Event Viewer as you, but adding these lines after each shell invoke I could see that my errors comes in the Import-Module line.

if (shell1.Streams.Error.Count > 0)
{
   for (int i = 0; i < shell1.Streams.Error.Count; i++)
   {
       ResultBox.Text += "Error: " + shell1.Streams.Error[i] + "\r\n";
   }
}
0
votes

At the time when we did that project with almamouz, it was not possible to generate resources via Azure REST API nor it was possible to do that via powershell scripts from webrole due to security considerations. We ended up using web and worker roles and the powershell script was running in worker role. It contained all the sensitive server connection info.