Ask a questionAsk a question
 

AnswerRemote MSI install using c# and WMI

  • Tuesday, October 24, 2006 5:22 PMfraser_foo Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi,

    I having a problem  whilst trying to install an application on remote machines using WMI. The code im using seems right, but it just isn't working. Can anybody,please, help point me in the right direction? Or maybe post a link/script i can have a look at?

    Just to note the strings..

    _DOMAIN
    _USERNAME
    _PASSWORD
    _MSIPATH
    _ARGS
    _MACHINE

    are all set correctly before they are passed to the method...

    Here is the code I'm working on...The thing is it doesn't throw any Exceptions at all, but it dosen't work either.

    So i am at a bit of a loss as how to fix it...

    Any help at all would be greatly appreciated.

    CODE:
    -----

    public void installMsi(string _DOMAIN, string _USERNAME, etc, etc)

    {
                ManagementScope ms = null;

                // Connection options
                ConnectionOptions co = new ConnectionOptions();
                co.Impersonation = ImpersonationLevel.Impersonate;
                co.Authentication = AuthenticationLevel.PacketPrivacy;
                co.Authority = "ntlmdomain:" + _DOMAIN;

                // local machine
                if (_MACHINE.ToUpper() == Environment.MachineName.ToUpper())
                {
                    ms = new ManagementScope(@"\ROOT\CIMV2", co);
                }
                // remote machine
                else
                {
                    co.Username = _USERNAME;
                    co.Password = _PASSWORD;
                    ms = new ManagementScope(@"\\" + _MACHINE + "\root\cimv2", co);
                    ms.Options.Impersonation = ImpersonationLevel.Impersonate;
                }
                try
                {
                    ms.Connect();
                    ManagementPath mp = new ManagementPath("Win32_Product");
                    ObjectGetOptions ogo = new ObjectGetOptions();
                    ManagementClass mc = new ManagementClass(ms, mp, ogo);
                    ManagementBaseObject inParams = mc.GetMethodParameters("Install");
                    inParams["PackageLocation"] = _MSIPATH; 
                    inParams["Options"] = _ARGS;
                    inParams["AllUsers"] = true;
                    ManagementBaseObject retVal = mc.InvokeMethod("Install", inParams, null);
                }

                catch (Exception ex)
                {

                    MessageBox.Show("Exception: " + ex.Message);

                }
                catch (ManagementException err)
                {
                    MessageBox.Show("WMI Error: " + err.Message);
                }
                catch (System.UnauthorizedAccessException unauthorizedErr)
                {
                    MessageBox.Show("Connection error: " + unauthorizedErr.Message);
                }

    }

    //END

     

    Thanks.

    Fraser

Answers

  • Wednesday, November 08, 2006 12:33 PMfraser_foo Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Hi Marek,

    Wow, thanks so much for your response, it has helped me a great deal.

    With regard to the remote installation of MSI packages, I eventually write a method which allowed me to use MSI packages hosted on a third machine.

    Computer A: machine I’m working on

    Computer B: machine I’m want to install apps on

    Computer C: machine hosting the MSI packages.

    The additional steps were to setup Kerberos delegation in Active Directory.

    I.E:

    1: Enabled delegation in Active Directory on the domain controller.

    2: The account on B marked as Trusted (Kerberos).

    3: The account on A not marked as sensitive.

    I decided to post the code in case anyone else was looking for a similar answer. The code is a bit sloppy but it did what I wanted. Hope it may help someone.

     

    public void RemoteMSI(string machine, string msi, string commandline, string username, string password, string domain)

    {

    try

    {

    ConnectionOptions connection =

    new ConnectionOptions();

    connection.Authority = "kerberos:" + domain + @"\" + machine;

    connection.Username = username;

    connection.Password = password;

    connection.Impersonation = ImpersonationLevel.Delegate;

    connection.Authentication = AuthenticationLevel.PacketPrivacy;

    //define the WMI root name space

    ManagementScope scope =

    new ManagementScope(@"\\" + machine + "." + domain + @"\root\CIMV2", connection);

    //define path for the WMI class

    ManagementPath p =

    new ManagementPath("Win32_Product");

    //define new instance

    ManagementClass classInstance = new ManagementClass(scope, p, null);

    // Obtain in-parameters for the method

    ManagementBaseObject inParams = classInstance.GetMethodParameters("Install");

    // Add the input parameters.

    inParams["AllUsers"] = true; //to install for all users

    inParams["Options"] = commandline; //paramters must be in the format “property=setting“

    inParams["PackageLocation"] = msi; //source file must be on the remote machine

    // Execute the method and obtain the return values.

    ManagementBaseObject outParams = classInstance.InvokeMethod("Install", inParams, null);

    // List outParams

    string retVal = outParams["ReturnValue"].ToString();

    string msg = null;

    switch (retVal)

    {

    case "0":

    msg = "The installation completed successfully.";

    break;

    case "2":

    msg = "The system cannot find the specified file. \n\r\n\r" + msi;

    break;

    case "3":

    msg = "The system cannot find the path specified. \n\r\n\r" + msi;

    break;

    case "1619":

    msg = "This installation package \n\r\n\r " + msi + "\n\r\n\rcould not be opened, please verify that it is accessible.";

    break;

    case "1620":

    msg = "This installation package \n\r\n\r " + msi + "\n\r\n\rcould not be opened, please verify that it is a valid MSI package.";

    break;

    default:

    msg = "Please see... \n\r\n\r http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/error_codes.asp \n\r\n\rError code: " + retVal;

    break;

    }

    // Display outParams

    MessageBox.Show(msg, "Installation report");

    }

    catch (ManagementException me)

    {

    MessageBox.Show(me.Message, "Management Exception");

    }

    catch (COMException ioe)

    {

    MessageBox.Show(ioe.Message, "COM Exception");

    }

    }

  • Friday, November 17, 2006 10:10 AMfraser_foo Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Hi Udooz,

     

    I would suggest that the two lines in you code:

    co.Impersonation = ImpersonationLevel.Impersonate;

    co.Authentication = AuthenticationLevel.Default;

    need to read:

     co.Impersonation = ImpersonationLevel.Delegate;

    co.Authentication = AuthenticationLevel.PacketPrivacy;

    Also you need to enable delegation on the computer accounts.

    Have a look at the following:


    A: Machine running your application.

    B: Machine to install software on to.

    C: Machine hosting the required MSI packages

     

    +----+                   +----+                   +----+
    |    |                   |    |                   |    |
    | A: | ==== 1st hop ===> | B: | ==== 2nd hop ===> | C: |
    |    | (A connects to B) |    | (B connects to C) |    |
    +----+                   +----+                   +----+        

                                       

    1: Enable delegation in Active Directory on the domain controller.

    2: The account on B must be marked as Trusted (Kerberos).

    3: The account on A must not be marked as sensitive.

    4: A, B, and the domain controller must be members of the same domain.

     

    Working Code:  

                             // set these values to your requirements

                _DOMAIN = "your.domain"; // your domain name

                _MACHINE = "target.machine"; // machine to install on

                _USERNAME ="username"; // username of account that exists on A and B

                _PASSWORD = "password"; // password for _USERNAME account

                _MSI = "\\path\to\package.msi"; // UNC path to the MSI package

                _ARGS = "property=value"; // commandline arguments for installer

                             //

     

          ConnectionOptions co =

    new ConnectionOptions();

    co.Authority = "kerberos:" + _DOMAIN + @"\" + _MACHINE;

          co.Username = _USERNAME;

          co.Password = _PASSWORD;

     

    //to impersonate current logged user

    co.Impersonation = ImpersonationLevel.Delegate;

    //PRC_C_IMP_LEVEL_DELEGATE (c++)

    co.Authentication = AuthenticationLevel.PacketPrivacy;

          co.EnablePrivileges = true;

     

    //define the WMI root name space

    ManagementScope ms =

    new ManagementScope(@"\\" + _MACHINE + "." + _DOMAIN + @"\root\CIMV2", co);

               

          //define path for the WMI class

          ManagementPath mp =

    new ManagementPath("Win32_Product");

     

    //define new instance

    ManagementClass mc =

    new ManagementClass(ms, mp, null);

     

    // Obtain input parameters for the method

    ManagementBaseObject inParams = mc.GetMethodParameters("Install");

     

    // Add the input parameters.

    inParams["AllUsers"] = true; //to install for all users

          inParams["PackageLocation"] = _MSI;  //msi source file

    inParams["Options"] = _ARGS;  //'property=setting'

     

    // Execute the method and obtain the return values.

    ManagementBaseObject outParams =

    mc.InvokeMethod("Install", inParams, null);

     

     

     

     

All Replies

  • Friday, November 03, 2006 3:06 PMGrabarz M Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi, this part of code should help you.

    Code depends on two things:

    • connection to local/remote computer.
    • computer is in domain or workgroup.

    Local:

    /// <summary>

    /// Binds working namespace to local computer's root\cimv2 namespace.

    /// </summary>

    public void ConnectLocalComputer()

    {

    m_WorkingNamespace = new ManagementScope();

    m_WorkingNamespace.Path = new ManagementPath(@"\\.\root\cimv2");

    try

    {

    m_WorkingNamespace.Connect();

    }

    catch (COMException comException)

    {

    this.m_WorkingNamespace = null;

    throw new ArgumentException("Server does not exists or access denied. \nConfigure firewall options.", comException);

    }

    catch (UnauthorizedAccessException authException)

    {

    this.m_WorkingNamespace = null;

    throw new ArgumentException("Access denied or timeout expired. \nCheck if you are in domain Administrators group.", authException);

    }

    }

    Remote:

    /// <summary>

    /// Binds working namespace to remote computer's root\cimv2 namespace.

    /// </summary>

    /// <param name="computerName">Name or ip address of remote computer.</param>

    /// <param name="domainName">Remote computer's domain. If computer is not in domain pass null value.</param>

    /// <param name="userName">Windows user name, domain account in the Administrators group.</param>

    /// <param name="password">Username's password.</param>

    /// <param name="connectionTimeout">Connection timeout.</param>

    public void ConnectRemoteComputer( string computerName, string domainName, string userName, string password,

    TimeSpan connectionTimeout )

    {

    ConnectionOptions connectionConfiguration = new ConnectionOptions();

    connectionConfiguration.Impersonation = ImpersonationLevel.Impersonate;

    connectionConfiguration.Authentication = AuthenticationLevel.Default;

    if (domainName == null || domainName == string.Empty)

    {

    connectionConfiguration.Username = computerName + "\\" + userName;

    connectionConfiguration.Authority = null;

    }

    else

    {

    connectionConfiguration.Username = userName;

    connectionConfiguration.Authority = "NTLMdomain:" + domainName;

    }

    connectionConfiguration.Password = password;

    connectionConfiguration.Timeout = connectionTimeout;

    connectionConfiguration.EnablePrivileges = true;

    m_WorkingNamespace = new ManagementScope();

    m_WorkingNamespace.Path = new ManagementPath(@"\\" + computerName + @"\root\cimv2");

    m_WorkingNamespace.Options = connectionConfiguration;

    try

    {

    m_WorkingNamespace.Connect();

    }

    catch( COMException comException )

    {

    this.m_WorkingNamespace = null;

    throw new ArgumentException("Server does not exists or access denied. \nCheck host name and configure firewall options.", comException);

    }

    catch( UnauthorizedAccessException authException )

    {

    this.m_WorkingNamespace = null;

    throw new ArgumentException("Access denied or timeout expired. \nCheck if username, password and domain are correct and if user is a member of domain Administrators group.", authException);

    }

    }

    Remember that you will connect remotely only if remote user is in Administrators group and your firewall has remote admnistration enabled.

     

    Now installing:

    /// <summary>

    /// Installs new msi package on bound computer

    /// </summary>

    /// <param name="msiFilePath">Path (on bound computer) to msi package.

    /// There can be only path to local, phisical drive!</param>

    /// <param name="installOptions">Additional command line options for installation if format property=setting.</param>

    /// <param name="allUsers">Indicates whether packege is installed for all users.</param>

    public void InstallProduct(string msiFilePath, string installOptions, bool allUsers)

    {

    if (!this.IsConnected)

    throw new InvalidOperationException("Object is not bound to WMI namespace. Use one of Connect methods before this operation.");

    ManagementClass productClass = new ManagementClass(this.m_WorkingNamespace,

    new ManagementPath("Win32_Product"), new ObjectGetOptions());

    try

    {

    object[] parameters = { msiFilePath, installOptions, allUsers };

    UInt32 returnValue = (UInt32) productClass.InvokeMethod("Install", parameters);

    if (returnValue > 0)

    throw new Exception("Installation failed. Error code = " + returnValue);

    }

    catch (ManagementException exc)

    {

    throw new Exception("Installation failed. RPC Server Fault Error.", exc);

    }

    }

    I hope it helps :)

    Cheers,

    Marek

  • Wednesday, November 08, 2006 12:33 PMfraser_foo Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Hi Marek,

    Wow, thanks so much for your response, it has helped me a great deal.

    With regard to the remote installation of MSI packages, I eventually write a method which allowed me to use MSI packages hosted on a third machine.

    Computer A: machine I’m working on

    Computer B: machine I’m want to install apps on

    Computer C: machine hosting the MSI packages.

    The additional steps were to setup Kerberos delegation in Active Directory.

    I.E:

    1: Enabled delegation in Active Directory on the domain controller.

    2: The account on B marked as Trusted (Kerberos).

    3: The account on A not marked as sensitive.

    I decided to post the code in case anyone else was looking for a similar answer. The code is a bit sloppy but it did what I wanted. Hope it may help someone.

     

    public void RemoteMSI(string machine, string msi, string commandline, string username, string password, string domain)

    {

    try

    {

    ConnectionOptions connection =

    new ConnectionOptions();

    connection.Authority = "kerberos:" + domain + @"\" + machine;

    connection.Username = username;

    connection.Password = password;

    connection.Impersonation = ImpersonationLevel.Delegate;

    connection.Authentication = AuthenticationLevel.PacketPrivacy;

    //define the WMI root name space

    ManagementScope scope =

    new ManagementScope(@"\\" + machine + "." + domain + @"\root\CIMV2", connection);

    //define path for the WMI class

    ManagementPath p =

    new ManagementPath("Win32_Product");

    //define new instance

    ManagementClass classInstance = new ManagementClass(scope, p, null);

    // Obtain in-parameters for the method

    ManagementBaseObject inParams = classInstance.GetMethodParameters("Install");

    // Add the input parameters.

    inParams["AllUsers"] = true; //to install for all users

    inParams["Options"] = commandline; //paramters must be in the format “property=setting“

    inParams["PackageLocation"] = msi; //source file must be on the remote machine

    // Execute the method and obtain the return values.

    ManagementBaseObject outParams = classInstance.InvokeMethod("Install", inParams, null);

    // List outParams

    string retVal = outParams["ReturnValue"].ToString();

    string msg = null;

    switch (retVal)

    {

    case "0":

    msg = "The installation completed successfully.";

    break;

    case "2":

    msg = "The system cannot find the specified file. \n\r\n\r" + msi;

    break;

    case "3":

    msg = "The system cannot find the path specified. \n\r\n\r" + msi;

    break;

    case "1619":

    msg = "This installation package \n\r\n\r " + msi + "\n\r\n\rcould not be opened, please verify that it is accessible.";

    break;

    case "1620":

    msg = "This installation package \n\r\n\r " + msi + "\n\r\n\rcould not be opened, please verify that it is a valid MSI package.";

    break;

    default:

    msg = "Please see... \n\r\n\r http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/error_codes.asp \n\r\n\rError code: " + retVal;

    break;

    }

    // Display outParams

    MessageBox.Show(msg, "Installation report");

    }

    catch (ManagementException me)

    {

    MessageBox.Show(me.Message, "Management Exception");

    }

    catch (COMException ioe)

    {

    MessageBox.Show(ioe.Message, "COM Exception");

    }

    }

  • Thursday, November 16, 2006 9:00 AMudooz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi fraser_foo,

    I've used the same code in .NET 2.0, but i'm facing installer file acess perfmission error # 1619.

    Please give me a solution for this.

    Regards,

    Udooz

     

  • Thursday, November 16, 2006 1:09 PMfraser_foo Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi Udooz,

    Well Error # 1619 is ERROR_INSTALL_PACKAGE_OPEN_FAILED if you check on:

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/error_codes.asp

    You can see that the decription for this is:

    This installation package could not be opened. Verify that the package exists and is accessible, or contact the application vendor to verify that this is a valid Windows Installer package.

    So at a guess the MSI isn't accessable to the target machine...Are your paths correct?

    Also, when you say you used the same code, what do you mean by that? The code I posted above?

    I wrote that code to work in a particular application i was developing. It may not be what you need at all...

    lIf you post your code i could propbably give some more help...

    F.

  • Friday, November 17, 2006 5:43 AMudooz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi Fraser_Foo,

    Consider the following case:

    Machine A: The application is running.

    Machine B: where the MSI file (eg: TestAppSetup.MSI) is placed.

    Machine C: target machine on which i need to install TestAppSetup.MSI

     

    S.No

    Scenario

    Test Result

    Return Value

    1

    Running application in A.

    MSI file in B. [Accessing this in UNC file path format]

    Target machine is A itself with local credential.

    PASS

    0

    2

    Running application in A.

    MSI file in B.[Accessing this in UNC file path format]

    Target machine is C with admin credential.

    FAIL

    1619

    3

    Running application in A.

    MSI file in C. [Accessing this in UNC file path format]

    Target machine is C with admin credential.

    PASS

    0

    But my application exactly needs the scenario #2 only. 

    See the sample code:

    string machineCName; //In this case, "machineC"

    if
    (!Directory.Exists(installerPath)) //installerPath eg. \\machineB\builds
    {
        return "The source installer path " + installerPath + " is invalid";
    }

    machineCFullPath = "\\\\" + machineCName + @"\root\cimv2";

    ManagementScope ms = null;

    ConnectionOptions co = new ConnectionOptions();

    co.Impersonation = ImpersonationLevel.Impersonate;

    co.Authentication = AuthenticationLevel.Default;

    co.Authority = "kerberos:" + domainName + "\\" + machineCName;

    co.Username = mUserName;

    co.Password = mPassword;

    // New

    co.EnablePrivileges = true;

    ms = new ManagementScope(machineCFullPath, co);

    try

    {

      ms.Connect();

    }

    catch (System.Runtime.InteropServices.COMException comException)

    {

    return "Server does not exists or access denied. Check host name and configure firewall options. Details: " + comException.Message

    + Environment.NewLine + comException.StackTrace;

    }

    catch (UnauthorizedAccessException authException)

    {

    return "Access denied or timeout expired. Check if username, password and domain are correct and if user is a member of domain Administrators group. Details: " +

    authException.Message + Environment.NewLine + authException.StackTrace;

    }

    catch (Exception ex)

    {

    return "Unexpected error occurred. Details: " + ex.Message + Environment.NewLine + ex.StackTrace;

    }

    try

    {

    string[] msiFiles = Directory.GetFiles(installerPath, "*.msi");

    int intRetVal = 0;

    string lastMSIFile = "";

    for (int i = 0; i < msiFiles.Length; i++)

    {

       lastMSIFile = msiFilesIdea;

       ManagementPath mp = new ManagementPath("Win32_Product");

       ObjectGetOptions ogo = new ObjectGetOptions();

       ManagementClass mc = new ManagementClass(ms, mp, ogo);

       ManagementBaseObject inParams = mc.GetMethodParameters("Install");

       inParams["PackageLocation"] = msiFilesIdea;

       if (mArgument != null && mArgument.Trim() != "")

          inParams["Options"] = mArgument;

       inParams["AllUsers"] = true;

       ManagementBaseObject retVal = mc.InvokeMethod("Install", inParams, null);

       intRetVal = Convert.ToInt32(retVal["ReturnValue"]);

       if (intRetVal != 0)

           break;

    }

    if (intRetVal == 1619)

      return "Unable to open installation package " + lastMSIFile + ". Check the file permission.";

    else if (intRetVal == 1620)

      return "Unable to open installation package " + lastMSIFile + ". Verify that given is valid MSI.";

    else if (intRetVal == 2)

      return "The system cannot find the MSI file.";

    else if (intRetVal == 3)

      return "The system cannot find installer path.";

    else if (intRetVal == 1259)

      return "The MSI " + lastMSIFile + " is incompatible with current operating system installed on this machine.";

    else if (intRetVal == 1601)

      return "Unable to access MSI service in this machine.";

    else if (intRetVal == 1618)

      return "An installer already running on the machine.";

    else if (intRetVal != 0)

      return "Unknown error code " + intRetVal + " returned.";

    return "";

    }

     

    catch (Exception ex)

    {

    return "Error while performing installation. Details: " + ex.Message + " " + ex.StackTrace;

    }

    Please send reply asap.  Thanks

    Regards,

    Udooz

  • Friday, November 17, 2006 10:10 AMfraser_foo Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    Hi Udooz,

     

    I would suggest that the two lines in you code:

    co.Impersonation = ImpersonationLevel.Impersonate;

    co.Authentication = AuthenticationLevel.Default;

    need to read:

     co.Impersonation = ImpersonationLevel.Delegate;

    co.Authentication = AuthenticationLevel.PacketPrivacy;

    Also you need to enable delegation on the computer accounts.

    Have a look at the following:


    A: Machine running your application.

    B: Machine to install software on to.

    C: Machine hosting the required MSI packages

     

    +----+                   +----+                   +----+
    |    |                   |    |                   |    |
    | A: | ==== 1st hop ===> | B: | ==== 2nd hop ===> | C: |
    |    | (A connects to B) |    | (B connects to C) |    |
    +----+                   +----+                   +----+        

                                       

    1: Enable delegation in Active Directory on the domain controller.

    2: The account on B must be marked as Trusted (Kerberos).

    3: The account on A must not be marked as sensitive.

    4: A, B, and the domain controller must be members of the same domain.

     

    Working Code:  

                             // set these values to your requirements

                _DOMAIN = "your.domain"; // your domain name

                _MACHINE = "target.machine"; // machine to install on

                _USERNAME ="username"; // username of account that exists on A and B

                _PASSWORD = "password"; // password for _USERNAME account

                _MSI = "\\path\to\package.msi"; // UNC path to the MSI package

                _ARGS = "property=value"; // commandline arguments for installer

                             //

     

          ConnectionOptions co =

    new ConnectionOptions();

    co.Authority = "kerberos:" + _DOMAIN + @"\" + _MACHINE;

          co.Username = _USERNAME;

          co.Password = _PASSWORD;

     

    //to impersonate current logged user

    co.Impersonation = ImpersonationLevel.Delegate;

    //PRC_C_IMP_LEVEL_DELEGATE (c++)

    co.Authentication = AuthenticationLevel.PacketPrivacy;

          co.EnablePrivileges = true;

     

    //define the WMI root name space

    ManagementScope ms =

    new ManagementScope(@"\\" + _MACHINE + "." + _DOMAIN + @"\root\CIMV2", co);

               

          //define path for the WMI class

          ManagementPath mp =

    new ManagementPath("Win32_Product");

     

    //define new instance

    ManagementClass mc =

    new ManagementClass(ms, mp, null);

     

    // Obtain input parameters for the method

    ManagementBaseObject inParams = mc.GetMethodParameters("Install");

     

    // Add the input parameters.

    inParams["AllUsers"] = true; //to install for all users

          inParams["PackageLocation"] = _MSI;  //msi source file

    inParams["Options"] = _ARGS;  //'property=setting'

     

    // Execute the method and obtain the return values.

    ManagementBaseObject outParams =

    mc.InvokeMethod("Install", inParams, null);

     

     

     

     

  • Monday, November 20, 2006 12:42 PMudooz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi fraser_foo

    I've done the same, but still, i can't resolved. 

    If i'm using NTLMADMIN. getting the "Not Found" error at the following line:

    ManagementBaseObject inParams = objMgmtClass.GetMethodParameters("Install");

    Exception Detail:

      Message: "Not found "

      Source:  "System.Management" 
      StackTrace:   at System.Management.ManagementException.ThrowWithExtendedInfo(ManagementStatus errorCode)\r\n   at System.Management.ManagementObject.Initialize(Boolean getObject)\r\n   at System.Management.ManagementObject.get_ClassPath()\r\n   at System.Management.ManagementObject.GetMethodParameters(String methodName, ManagementBaseObject& inParameters, IWbemClassObjectFreeThreaded& inParametersClass, IWbemClassObjectFreeThreaded& outParametersClass)\r\n   at System.Management.ManagementObject.GetMethodParameters(String methodName)\r\n   at iSOFT.iDeployer.App.Deploy.DeployMSI(String serverIP, String installerPath) in D:\\Projects\\PackDeploy\\iDeployerSolution\\iDeployer\\Deploy.cs:line 160"

    If I'm using Kerberos, getting the "A security package specific error occurred. (Exception from HRESULT: 0x80070721)" error at the same:

    Exception Detail:

      Source: "mscorlib"

      StackTrace: "   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)\r\n   at System.Management.ManagementObject.Initialize(Boolean getObject)\r\n   at System.Management.ManagementObject.get_ClassPath()\r\n   at System.Management.ManagementObject.GetMethodParameters(String methodName, ManagementBaseObject& inParameters, IWbemClassObjectFreeThreaded& inParametersClass, IWbemClassObjectFreeThreaded& outParametersClass)\r\n   at System.Management.ManagementObject.GetMethodParameters(String methodName)\r\n   at iSOFT.iDeployer.App.Deploy.DeployMSI(String serverIP, String installerPath) in D:\\Projects\\PackDeploy\\iDeployerSolution\\iDeployer\\Deploy.cs:line 160" string

    Please help me.

    Regards,

    Udooz

  • Monday, November 20, 2006 5:05 PMfraser_foo Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi Udooz,

    You can't do this 2-hop-method via NTLMADMIN, you must use Kerberos delegation. The error your getting is because the client asks for delegation, but the created security context does not support delegation.

    Do you have a firewall runnig on the server? on the target machine? If so try turning these off... If it then works, you need to configure the firewall to stop it blocking the requests.

    Also, are the machines all at least XP? or is the target 2000?

    F.

  • Monday, November 20, 2006 7:48 PMjohn zhou Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi, fraser_foo,

    I am using your code, but always got an exception of "The RPC server is unavailable". In my situation, I want to deploy a msi package to computer B remotely. B is the target machine, A is the machine running the application code. Also, the msi package is in a shared directory in machine A. A is windows 2003 server, B is Windows XP SP2. I am using a domain administrator account. Any ideas about the exception?

    Thanks

    John

  • Tuesday, November 21, 2006 10:29 AMfraser_foo Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    The error message: RPC Server is Unavailable

    This issue can occur for any of the following reasons:

    The RPC service may not be started.
    You are unable to resolve a DNS or NetBIOS name.
    An RPC channel cannot be established.

    You could try:

    1) Make sure the Remote Procedure Call (RPC) service is running on both machines (net start rpcss)

    2) Make sure the Remote Procedure Call  Locator (rpclocator) service is running on both machines (net start rpclocator)

    3) Make sure the DCOM Server Process Launcher (DcomLaunch) service is running on both machines  (net start dcomlaunch)

    4) Make sure any firewall / antivirus software isn't blocking the RPC.

    Regards,

    Fraser

  • Tuesday, November 21, 2006 7:51 PMjzhou415 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Thank you very much for your response. I checked all items you mentioned above and found no problem. But I still got "RPC server is unavailable" error. I read your previous posted message carefully and found you mentioned in one of the messages the following:

    The additional steps were to setup Kerberos delegation in Active Directory.

    I.E:

    1: Enabled delegation in Active Directory on the domain controller.

    2: The account on B marked as Trusted (Kerberos).

    3: The account on A not marked as sensitive.

     

    What's the detailed steps to do it (I am using domain administrator's account)?

     

    Thanks

     

    John

  • Thursday, November 23, 2006 5:07 AMudooz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi Fraser,

    I've did all those things.

    After that, it returns error number 1619 or 2, even i've provided all permissions to access the installer file path.

    Regards,

    Udooz

  • Monday, November 27, 2006 9:00 PMjzhou415 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi, Marek,

    I am using your code to install a MSI package on remote machines (I am using the code you posted exactly and the MSI package is already on the remote machine). It works fine if the remote machine is a windows xp sp2. But It fails if remote machine is windows 2003 server sp1 and it throws an ManagementException. Do you have any idea about this?

    Thanks

    John

  • Tuesday, November 28, 2006 5:30 AMudooz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi John,

    Check that whether WMI Installer Provider is installed on your server or not?  By default, WMI Windows Installer Provider is not installed in Win2003.  You have to install by

    select Start > Control Panel > Add or Remove Programs.

    In Add or Remove Programs window,  press Add or Remove Windows Components button. 

    In Windows Components Wizard window, select Management and Monitoring Tools from the Components list.  Press Details.. button. 

    In Management and Monitoring Tools window, select WMI Windows Installer Provider in the Subcomponents of Management and Monitoring Tools list.

    Press OK.

    And one more thing, did u check the following scenario?

    Place the MSI file on one machine and install it on some other remote machine through WMI.  If yes, please give me the details.

    Regards,

    Udooz

  • Thursday, November 30, 2006 12:09 AMjzhou415 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi, Udooz,

    That is exactly why it failed on windows 2003. After I installed WMI installer provider, It worked fine.

    Also, I tried to install application on a remote machine using msi package on a another machine, I never succeeded. I read all the posts in this thread carefully, but I still cannot figure out the reason of failure. Now I am using a workaround: remotely copy MSI file to the target machine by using "WNetAddConnection2", and then "CopyFile".

    Thanks

    John

  • Thursday, November 30, 2006 10:00 AMudooz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi John,

    Can you please give sample code for the abve?

    Thanks

    Udooz

  • Wednesday, January 17, 2007 7:45 PMRonakPPatel Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I am using your code to do Remote Installation. But i am getting the following error.

    Access denied. (Exception from HRESULT:  0x80070005 (E_ACCESSEDDENIED)

    at this Location

    ManagementBaseObject inParams = mc.GetMethodParameters("Install");


    any idea why i am getting this error.

  • Wednesday, January 31, 2007 10:02 AMTekchand Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I did like the same thing but during remote installation first i copied my msi file to remote system in which i have to install.Then i install that pack there and after installation i remove my msi file from remote system. This process working fine.I was also getting priviously that error.
  • Wednesday, January 31, 2007 10:08 AMTekchand Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Befor running ur program check these configration:

    1. If reading logs from another computer on the network, make sure that the user and password you have supplied for each feed correspond to an administrator account on the target computer. That account MUST have a non-blank password.

    2. Check that DCOM is enabled on both the host and the target PC. Check the following registry value on both computers:
    Key: HKLM\Software\Microsoft\OLE, value: EnableDCOM, should be set to 'Y'

    3. Check that WMI is installed. WMI is present by default in all flavors of Windows 2000 and later operating systems, but must be installed manually on NT4 systems.

    To check for the presence of WMI, type "wbemtest" into the Run box (Start Menu). If the WMI Tester application starts up, then WMI is present, if not, it must be installed. Consult the Troubleshooting section of the Help for details.

    4. Ensure that WMI permissions have been set correctly. Please consult the Troubleshooting section of the Help for details.

    5. On a Windows XP Pro computer, make sure that remote logons are not being coerced to the GUEST account (aka "ForceGuest", which is enabled by default computers that are not attached to a domain). To do this, open the Local Security Policy editor (e.g. by typing 'secpol.msc' into the Run box, without quotes). Expand the "Local Policies" node and select "Security Options". Now scroll down to the setting titled "Network access: Sharing and security model for local accounts". If this is set to "Guest only", change it to "Classic" and restart your computer.

    6. Also on an XP computer running SP2, configure the firewall to allow remote administration. To do this, open a command prompt and type: netsh firewall set service RemoteAdmin

    7. If you have other internal firewalls on your network, you may have to configure them to allow WMI messages. Again, you'll find advice on how to do this in the troubleshooting section of the Help.

    Even if you are not knowingly running any firewall software, bear in mind that big-name antivirus solutions such as those produced by McAfee and Symantec often contain their own firewall functionality. If such software is not properly configured to allow WMI traffic, then this may be the cause of the problem.

    8. Make sure that no remote access or WMI-related services have been disabled. On an XP machine, the following services should be running (or at least allowed to start on demand):

    COM+ Event System
    Remote Access Auto Connection Manager
    Remote Access Connection Manager
    Remote Procedure Call (RPC)
    Remote Procedure Call (RPC) Locator
    Remote Registry
    Server
    Windows Management Instrumentation
    Windows Management Instrumentation Driver Extensions
    WMI Performance Adapter
    Workstation

    thanks

    tekchand

  • Wednesday, February 07, 2007 11:31 PMRonakPPatel Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi Tekchand

    These are so many steps to just do this. Dont you think if i have to do Remote Installation on 100 Computers this is more time consuming then to just copy the Installation file on that computer and Run it manually.

    In Windoes 2003  Win32_Product class in not isntalled by default. I was testing on that PC for one week when finally i got this Information. I just want to know whats the differance between NTLMADMIN and  Kerberos.

    Here is what my solution looks like using the code given in this post. It uses NTLMADMIN

    1) Map the Remote Machine(A)'s drive to Local Machine (B)

    2) Copy the Installation file from Local Machine(B) to Remote Machine(A)

    3) Connect to Remote Machine Using NTLMADMIN authentication to Install the product: Everything using WMI and C#

    4) Delete the Installation File from Remote Machine.

    5) UnMapp the network Drive.

    I want to achive the Remote Installation ability without mapping the drive. Is there way to Install the msi file from UNC path..(share folder). I know that for that i have to use kerberos authenticaton, but all the solution posted in this thread some how does not work as they should be for this type of authentication.

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Diagnostics;
    using System.Management;
    using System.IO;
    using System.Runtime.InteropServices;

    namespace RemoteInstall
    {
        public class RemoteInstall
        {
            ManagementScope m_WorkingNamespace;
            private string _status;      

            /*
             * Install Properties
             */
            public string Status
            {
                get { return _status; }
                set
                {
                    _status = value;
                }
            }

            public delegate void StatusUpdate(string message);

            // Define an Event based on the above Delegate
            public event StatusUpdate statusUpdate;

            protected void OnStatusUpdate(string message)
            {
                if (statusUpdate != null)
                {
                    statusUpdate(message);
                }
            }

            public int StartRemoteInstall(String RemoteMachineName, String domainName, String username, String password, String localmsiPath, String installOptions)
            {
                NetworkDrive NetDrive = new NetworkDrive();
                try
                {
                    if(RemoteMachineName.ToUpper().Equals(Environment.MachineName.ToUpper()))
                    {
                        Status = "Installing on Local machine with Current User's Credentials";
                        OnStatusUpdate(Status);                   
                        int retVal = LocalInstall(localmsiPath,installOptions,true);
                        return retVal;
                    }
                    else
                    {
                        Status = "Mapping a remote machine drive to local machine";
                        OnStatusUpdate(Status);                   
                        NetDrive.Force = true;
                        NetDrive.ShareName = @"\\" + RemoteMachineName + @"\c$";
                        String nextdriveletter = NextDriveLetter();
                        NetDrive.LocalDrive = nextdriveletter;
                        NetDrive.MapDrive(username, password);
                        Status = "Copying installer on to Remote machine.";
                        OnStatusUpdate(Status);
                        String networkdrive = nextdriveletter + "\\" + Path.GetFileName(localmsiPath);
                        System.IO.File.Copy(localmsiPath, networkdrive, true);
                        Status = "Connecting to Remote Machine.";
                        OnStatusUpdate(Status);
                        TimeSpan connectionTimeout = new TimeSpan(0, 3, 0);                             
                        ConnectRemoteComputer(RemoteMachineName, domainName, username, password, connectionTimeout);               
                        Status = "Installing Product on Remote Machine.";
                        OnStatusUpdate(Status);
                        String remotemsiPath = "C:\\" + Path.GetFileName(localmsiPath);
                        int retVal = InstallProduct(remotemsiPath, installOptions, true);
                        System.Threading.Thread.Sleep(10000);
                        Status = "Removing Installer from Remote Machine.";
                        OnStatusUpdate(Status);
                        System.IO.File.Delete(networkdrive);
                        Status = "Unmapping a remote machine drive from local machine.";
                        OnStatusUpdate(Status);
                        NetDrive.UnMapDrive();
                        return retVal;
                    }
                }
                catch (Exception ex)
                {
                    if (!RemoteMachineName.ToUpper().Equals(Environment.MachineName.ToUpper()))
                    {
                        NetDrive.UnMapDrive();
                    }
                    Status = ex.Message;
                    return 1;
                }           
            }

            public void ConnectLocalComputer()
            {

                m_WorkingNamespace = new ManagementScope();

                m_WorkingNamespace.Path = new ManagementPath(@"\\.\root\cimv2");

                try
                {

                    m_WorkingNamespace.Connect();

                }

                catch (COMException comException)
                {

                    this.m_WorkingNamespace = null;

                    throw new ArgumentException("Server does not exists or access denied. \nConfigure firewall options.", comException);

                }

                catch (UnauthorizedAccessException authException)
                {

                    this.m_WorkingNamespace = null;

                    throw new ArgumentException("Access denied or timeout expired. \nCheck if you are in domain Administrators group.", authException);

                }

            }

            public int LocalInstall(string msiFilePath, string installOptions, bool allUsers)
            {
                ConnectionOptions connection = new ConnectionOptions();          
                connection.Impersonation = ImpersonationLevel.Impersonate;

                connection.Authentication = AuthenticationLevel.PacketPrivacy;
                connection.EnablePrivileges = true;
                //define the WMI root name space

                ManagementScope scope =

                    new ManagementScope(@"\\" + "." + @"\root\CIMV2", connection);

                //define path for the WMI class

                ManagementPath p = new ManagementPath("Win32_Product");

                //define new instance

                ManagementClass classInstance = new ManagementClass(scope, p, null);
                ManagementBaseObject inParams = null;
                try
                {

                    inParams = classInstance.GetMethodParameters("Install");
                }
                catch (Exception exex)
                {
                    throw new Exception(exex.Message);
                }

                inParams["AllUsers"] = allUsers; //to install for all users

                inParams["Options"] = installOptions; //paramters must be in the format “property=setting“

                inParams["PackageLocation"] = msiFilePath; //source file must be on the remote machine

                // Execute the method and obtain the return values.

                ManagementBaseObject outParams = classInstance.InvokeMethod("Install", inParams, null);

                // List outParams

                UInt32 retVal = (UInt32)outParams["ReturnValue"];
                return (int)retVal;
               
            }

            public void ConnectRemoteComputer(string computerName, string domainName, string userName, string password,TimeSpan connectionTimeout)
            {

                ConnectionOptions connectionConfiguration = new ConnectionOptions();

                connectionConfiguration.Impersonation = ImpersonationLevel.Impersonate;

                connectionConfiguration.Authentication = AuthenticationLevel.Default;

                if (domainName == null || domainName == string.Empty)
                {

                    connectionConfiguration.Username = computerName + "\\" + userName;

                    connectionConfiguration.Authority = null;

                }

                else
                {

                    connectionConfiguration.Username = userName;

                    connectionConfiguration.Authority = "NTLMdomain:" + domainName;


                }

                connectionConfiguration.Password = password;

                connectionConfiguration.Timeout = connectionTimeout;

                connectionConfiguration.EnablePrivileges = true;

                m_WorkingNamespace = new ManagementScope();

                m_WorkingNamespace.Path = new ManagementPath(@"\\" + computerName + @"\root\cimv2");

                m_WorkingNamespace.Options = connectionConfiguration;

                try
                {

                    m_WorkingNamespace.Connect();

                }

                catch (COMException comException)
                {

                    this.m_WorkingNamespace = null;

                    throw new ArgumentException("Server does not exists or access denied. \nCheck host name and configure firewall options.", comException);

                }

                catch (UnauthorizedAccessException authException)
                {

                    this.m_WorkingNamespace = null;

                    throw new ArgumentException("Access denied or timeout expired. \nCheck if username, password and domain are correct and if user is a member of domain Administrators group.", authException);

                }

            }

            public int InstallProduct(string msiFilePath, string installOptions, bool allUsers)
            {

                if (!this.m_WorkingNamespace.IsConnected)

                    throw new InvalidOperationException("Object is not bound to WMI namespace. Use one of Connect methods before this operation.");

                ManagementClass productClass = new ManagementClass(this.m_WorkingNamespace,

                new ManagementPath("Win32_Product"), new ObjectGetOptions());

                try
                {

                    object[] parameters = { msiFilePath, installOptions, allUsers };

                    UInt32 returnValue = (UInt32)productClass.InvokeMethod("Install", parameters);

                    return (int)returnValue;
                }

                catch (ManagementException exc)
                {

                    throw new Exception("Installation failed. RPC Server Fault Error.", exc);

                }

            }


            public int CreateProcess(string command,String workingDir)
            {
              
                if (!this.m_WorkingNamespace.IsConnected)

                    throw new InvalidOperationException("Object is not bound to WMI namespace. Use one of Connect methods before this operation.");

                ManagementClass productClass = new ManagementClass(this.m_WorkingNamespace,

                new ManagementPath("Win32_Process"), new ObjectGetOptions());

                ManagementBaseObject inParams = null;
                try
                {

                    inParams = productClass.GetMethodParameters("Create");
                }
                catch (Exception exex)
                {
                    throw new Exception(exex.Message);
                }

                // Add the input parameters.                       
                inParams["CommandLine"] = command; //execute this command           
                inParams["CurrentDirectory"] = workingDir; //working directory for new process

                // Execute the method and obtain the return values.
                ManagementBaseObject outParams = productClass.InvokeMethod("Create", inParams, null);
               
                // List outParams
                string retVal = outParams["ReturnValue"].ToString();
                int retValInt = Convert.ToInt32(retVal);
                return retValInt;
               
            }
            public String ErrorCodeInstall(int errorcode)
            {
                string msg = null;

                switch (errorcode.ToString())
                {

                    case "0":

                        msg = "The installation completed successfully.";

                        break;

                    case "1":

                        msg = Status;

                        break;

                    case "2":

                        msg = "The system cannot find the specified file.";

                        break;

                    case "3":

                        msg = "The system cannot find the path specified.";

                        break;

                    case "1619":

                        msg = "This installation package could not be opened, please verify that it is accessible.";

                        break;

                    case "1620":

                        msg = "This installation package could not be opened, please verify that it is a valid MSI package.";

                        break;

                    default:

                        msg = "Please see... \n\r\n\r http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/error_codes.asp \n\r\n\rError code: " + errorcode.ToString();

                        break;

                }

                return msg;
            }

            public string NextDriveLetter()
            {
                DriveInfo[] allDrives = DriveInfo.GetDrives();
                for (int i = 68; i <= 90; i++)
                {
                    String nextletter = Convert.ToChar(i).ToString() + ":\\";
                    int temp = 0;
                    foreach (DriveInfo de in allDrives)
                    {                   
                        if (de.Name.Equals(nextletter))
                            temp = 1;

                    }
                    if (temp == 0)
                        return nextletter.Substring(0, 2);
                }
                return null;
            }

        }
    }



    .


  • Wednesday, August 15, 2007 10:13 PMMartin Slemr Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi,
     is there someone, who finds the solution with UNC path to MSI package?
    I think that copy msi to remote computer isn't the best way...
  • Thursday, August 16, 2007 5:51 PMbigcoops Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    What about the cenario below:

    Run application and share MSI from Machine A and install on Machine B.

    ie:  A <--> B

    Would I still have to use Kerberos?

    I am able to install on Machine B if the MSI is already on Machine B using NTLMdomain authentication. However, when I try to install the MSI from Machine A (via UNC path), I get the 1619 error (The RPC server is unavailable).

    Thanks in advance.
  • Friday, August 17, 2007 3:18 PMbigcoops Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    OK,  I was able to get the MSI deployment working using delegation for the second hop.

    However, I still fell this method is limited as you can only deploy to machines on the same domain.

    Other than copying the MSI file to the remote machine first, are there any options of deploying a MSI to machines on another domain?
  • Wednesday, December 05, 2007 6:01 PMRonakPPatel Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi bigcoops,

    Can you please post your code how did you get it working on Same Domain whithout copying the installer on to the remove machine?
  • Wednesday, December 05, 2007 6:55 PMbigcoops Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I used the exact same code that fraser_foo provided in this thread.  You must setup delegation in Active Directory as he outlined.

    I ended up not using this method for deployment as it is difficult to have working in different environments, and prone to failing, so I don't have the exact code I used.
  • Wednesday, December 05, 2007 7:20 PMRonakPPatel Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi bigcoops,

    In that case my code works perfectly fine. You dont have to do any thing on your machine and remote machine.
    It can also deploy something on another domain. As long as you hv administrator rights on that remote machine.


  • Friday, November 28, 2008 11:50 PMcochee83 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Can anyone provide some code examples of how I can remotely install a *.exe installation file instread of a *.msi file?

    Thanks!

    Alejandro

  • Saturday, December 27, 2008 9:37 PMInetkid Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Dear RonakPPatel and bigcoops,
    There are 2 methods you can install using UNC path:
    1) Use Impersonate=delegate
    http://www.microsoft.com/technet/scriptcenter/resources/wmifaq.mspx
    You need domain to do delegation.

    2) Run NET USE on machine B to Machine C (using WMI's Win32_Process Method Create)
    You don't need domain but need the login

    *********************

    Dear Alejando,

    You can install *.exe using Win32_Process but bear in mind that the exe must able to install silently.

  • Friday, January 16, 2009 8:59 PMRoeman Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Inetkid, thanks for your response. 

    I discovered this thread while looking into WMIC... unfortunately, I have the same difficulty (cannot remotely install a WMI compatible MSI unless the files are hosted on that machine). You mentioned the net use command, but I'm concerned that the net use commans are the same that create network drives. I guess my question is:

    How can net use be applied in such a way that wmic or wmi installation calls may be executed on the remote machine - which accesses the .msi across a network?

    Thanks for any info you can toss my way!