0

I'm using Azure File Service to persist some files that a program, installed on a role instance, will access.

I have managed to map a drive, to the file service share, through remote desktop, using a PowerShell script. However, when I try to execute that same script, in the OnStart() of the worker role, it doesn't work. I can't figure out what's wrong.

So, this is what I do:

public override bool OnStart()
{
    ServicePointManager.DefaultConnectionLimit = 12;

    _slsPath = RoleEnvironment.GetLocalResource("StartupLocalStorage").RootPath;

    var settingstring = CloudConfigurationManager.GetSetting("StorageConnectionString");
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(settingstring);

    var blobClient = storageAccount.CreateCloudBlobClient();
    CloudBlobContainer container = blobClient.GetContainerReference("zipfiles");
    ICloudBlob blob = container.GetBlobReferenceFromServer("Program.zip");
     //copy blob from cloud to local gallery
     blob.DownloadToFile(_slsPath + "Program.zip", FileMode.Create);

    // get powershell script for mounting drive
     blob = container.GetBlobReferenceFromServer("mountdrive.ps1");
    blob.DownloadToFile(_slsPath + "mountdrive.ps1", FileMode.Create);

    // small exe for executing powershell script for mounting drive
    blob = container.GetBlobReferenceFromServer("Programinstaller.exe");
    blob.DownloadToFile(_slsPath + "Programinstaller.exe", FileMode.Create);

    ZipFile.ExtractToDirectory(_slsPath + @"\Program.zip", _slsPath);

    var share = storageAccount
    .CreateCloudFileClient()
    .GetShareReference("someshare");
    share.CreateIfNotExists();

    var filesPath = @"Z:\Folder";
    // Mounting drive
    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.CreateNoWindow = false;
    startInfo.UseShellExecute = false;
    startInfo.RedirectStandardOutput = true;
    startInfo.FileName = _slsPath + @"Programinstaller.exe";
    startInfo.WindowStyle = ProcessWindowStyle.Normal;
    startInfo.Arguments = _slsPath + @"\ " + filesPath;

    // Start the process with the info we specified.
    // Call WaitForExit and then the using statement will close.
    using (Process exeProcess = Process.Start(startInfo))
    {
            int count = 0;
            var res = exeProcess.StandardOutput.ReadLine();
            System.IO.File.WriteAllText(_slsPath + @"ResultOfDriveMount.txt", res + Environment.NewLine);
            while (count < 30)
            {
                    Thread.Sleep(1000);
                    res = exeProcess.StandardOutput.ReadLine();
                    System.IO.File.AppendAllText(_slsPath + @"ResultOfDriveMount.txt", res + Environment.NewLine);
                    count++;
            }
    }
}

Allright, so, the Programinstaller.exe is just this:

    static void Main(string[] args)
    {
        Console.WriteLine(args[0]);
        Thread t = new Thread(() =>
        {
            ExecutePowerShell(args[0] + "mountdrive.ps1", args[0]);
        });
        t.Start();
        Thread.Sleep(20000);
        InstallProgram(args[0], args[1]);
    }

    private static void ExecutePowerShell(string scriptfile, string SlsPath)
    {
        RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();

        Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
        runspace.Open();

        RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);

        Pipeline pipeline = runspace.CreatePipeline();

        //Here's how you add a new script with arguments
        Command myCommand = new Command(scriptfile);
        //CommandParameter testParam = new CommandParameter("key", "value");
        //myCommand.Parameters.Add(testParam);

        pipeline.Commands.Add(myCommand);

        // Execute PowerShell script
        var results = pipeline.Invoke();
        foreach (var res in results)
            System.IO.File.WriteAllText(SlsPath + @"ResultOfPowerShell.txt", res.ToString());
    }

    /// <summary>
    /// Launch the legacy application with some options set.
    /// </summary>
    static void InstallProgram(string folderPath, string pathTwo)
    {
        // Use ProcessStartInfo class
        ProcessStartInfo startInfo = new ProcessStartInfo();
        startInfo.CreateNoWindow = false;
        startInfo.UseShellExecute = false;
        startInfo.RedirectStandardOutput = true;
        startInfo.FileName = folderPath + @"ProgramAuthor.ProgramName.exe";
        startInfo.WindowStyle = ProcessWindowStyle.Normal;
        startInfo.Arguments = folderPath + [someargument] + pathTwo;

        try
        {
            // Start the process with the info we specified.
            // Read output lines, store to txt
            using (Process exeProcess = Process.Start(startInfo))
            {
                int count = 0;
                var result = exeProcess.StandardOutput.ReadLine(); 

                System.IO.File.WriteAllText(folderPath + @"ResultOfProgramInstall.txt", result + Environment.NewLine);
                while (count < 300)
                {
                    Thread.Sleep(1000);
                    result = exeProcess.StandardOutput.ReadLine();
                    System.IO.File.AppendAllText(folderPath + @"ResultOfProgramInstall.txt", result + Environment.NewLine);
                    count++;
                }
            }
        }
        catch (Exception ex)
        {
            System.IO.File.WriteAllText(folderPath + @"Error2.txt", ex.Message + " ... " + ex.StackTrace);
        }
    }

And the Ps1-file goes like this:

Set-Executionpolicy -Scope CurrentUser -ExecutionPolicy UnRestricted
cmdkey /add:[account].file.core.windows.net /user:[account] /pass:[key]
net use z: \\[account].file.core.windows.net\someshare

Strange thing is that running the Programinstaller.exe file, that was downloaded from the blob, from command prompt - with same parameters - in remote desktop in the worker role, will mount the mapped drive and install the program. But calling that same file from code after deploying (i.e. from OnStart()) doesn't mount the drive. The ProgramAuthor.ProgramFile.exe is executed, and tries to install in the mapped drive, but it was never mapped so it fails.

What's up with this?

right_there
  • 175
  • 1
  • 1
  • 11

1 Answers1

0

Ok, so I went down this way instead, as recommended in this answer. Only problem being that the drive doesn't show up in the file explorer when logged in to the VM. Not a big deal.

Community
  • 1
  • 1
right_there
  • 175
  • 1
  • 1
  • 11
  • I changed the runtime executioncontext to elevated, and so the drive shows up in the file explorer, but it is marked with a red cross and it says it's not accessible because user name or password is not correct. The program with files installed on it is still running though! – right_there Mar 03 '15 at 08:16