1

I'm using PowerShell 5.1, Visual Studio 2017, C# , and XenServer SDK 7.1.1.

Using Get-Credentials and Export-CliXml in a PowerShell program, I've saved my pool master server login credentials for the root user to an XML credentials file (xml_creds.xml)

Now, I want to create and login to a session using C# (see code below). As you can see, I'm forced to convert my secure string to a plain text string to satisfy the signature for the Xen .NET API's login_with_passwordmethod.

Using the API, how do I login to the session using a secure string?

Code

try
{

    securedPassword = new SecureString();
    string unsecuredPassword = "";

    Runspace rs = RunspaceFactory.CreateRunspace();
    rs.Open();

    Pipeline pipeline = rs.CreatePipeline(@"Import-CliXml 'C:\foo\xml_creds.xml';");

    Collection<PSObject> results = pipeline.Invoke();

    if (results.Count == 1)
    {
        PSObject psOutput = results[0];

        securedPassword = ((PSCredential)psOutput.BaseObject).Password;
        unsecuredPassword = new System.Net.NetworkCredential(string.Empty, securedPassword).Password;
        username = ((PSCredential)psOutput.BaseObject).UserName;

        rs.Close();

        session = new Session(hostname, port);

        session.login_with_password(username, unsecuredPassword, API_Version.API_1_3);
    }
    else
    {
        throw new System.Exception("Could not obtain pool master server credentials");
    }
}
catch (Exception e1)
{
    System.Console.WriteLine(e1.Message);
}
finally
{
    if (securedPassword != null)
    {
        securedPassword.Dispose();
    }

    if (session != null)
    {
        session.logout(session);
    }
}

1 Answer 1

1

I contacted Citrix.

The Xen API does not provide a mechanism for logging into a session using a secure string password.

So, I ended up using a C# program that executes two PowerShell scripts that do support a secure string password.

See the code below.

Notes:

I have the 7.1.1 XenServerPSModule installed in %USERPROFILE%\Documents\WindowsPowerShell\Modules\XenServerPSModule. This module provides the Connect-XenServer cmdlet

I created the xml credentials file using PowerShell get-credentials followed by using export-clixml

I loaded the requisite System.Management.Automation reference by installing Microsoft.PowerShell.5.ReferenceAssemblies from NuGet

form1.cs (form has just a button)

using System;
using System.Windows.Forms;
using XenSnapshotsXenAccess;

namespace Create_XenSnapshotsUi
{
    public partial class Form1 : Form
    {
        XenSessionAccess xenSession = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void Button1_Click(object sender, EventArgs e)
        {

            xenSession = new XenSessionAccess("https://xxx.xx.x.x", @"C:\foo\xml_credentials.xml");

            xenSession.Logout();

        }
    }
}

XenSessionAccess class

using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using XenAPI;

namespace XenSnapshotsXenAccess
{
    public class XenSessionAccess
    {
        private Session xenSession = null;

        public Session XenSession { get => xenSession; set => xenSession = value; }

        public void Logout()
        {
            if (XenSession != null)
            {
                XenSession.logout(XenSession);
            }
        }

        public XenSessionAccess(string poolMasterServerUrl, string xml_creds_path)
        {
            Collection<PSObject> results = null;
            PSCredential psCredential = null;

            //https://learn.microsoft.com/en-us/powershell/developer/hosting/creating-an-initialsessionstate

            //Createdefault2* loads only the commands required to host Windows PowerShell (the commands from the Microsoft.PowerShell.Core module.
            InitialSessionState initialSessionState = InitialSessionState.CreateDefault2();

            using (Runspace runSpace = RunspaceFactory.CreateRunspace(initialSessionState))
            {
                runSpace.Open();

                using (PowerShell powerShell = PowerShell.Create())
                {
                    powerShell.Runspace = runSpace;
                    powerShell.AddCommand("Import-CliXml");

                    powerShell.AddArgument(xml_creds_path);
                    results = powerShell.Invoke();

                    if (results.Count == 1)
                    {
                        PSObject psOutput = results[0];
                        //cast the result to a PSCredential object
                        psCredential = (PSCredential)psOutput.BaseObject;
                    }
                    else
                    {
                        throw new System.Exception("Could not obtain pool master server credentials");
                    }
                }

                runSpace.Close();
            }

            initialSessionState = InitialSessionState.CreateDefault2();
            initialSessionState.ImportPSModule(new string[] { "XenServerPSModule" });
            initialSessionState.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Unrestricted;

            SessionStateVariableEntry psCredential_var = new SessionStateVariableEntry("psCredential", psCredential, "Credentials to log into pool master server");
            initialSessionState.Variables.Add(psCredential_var);

            SessionStateVariableEntry poolUrl_var = new SessionStateVariableEntry("poolUrl", poolMasterServerUrl, "Url of pool master server");
            initialSessionState.Variables.Add(poolUrl_var);

            using (Runspace runSpace = RunspaceFactory.CreateRunspace(initialSessionState))
            {
                runSpace.Open();

                using (PowerShell powerShell = PowerShell.Create())
                {
                    powerShell.Runspace = runSpace;
                    powerShell.AddScript(@"$psCredential | Connect-XenServer -url $poolUrl -SetDefaultSession -PassThru");
                    results = powerShell.Invoke();
                }

                if (results.Count == 1)
                {
                    PSObject psOutput = results[0];
                    //cast the result to a XenAPI.Session object
                    XenSession = (Session)psOutput.BaseObject;
                }
                else
                {
                    throw new System.Exception(String.Format("Could not create session for {0}", poolMasterServerUrl));
                }

                runSpace.Close();
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.