Link to home
Start Free TrialLog in
Avatar of wolfiewolf
wolfiewolf

asked on

how to join domain and rename with one reboot in c#

I see many VB examples of renaming and join domains from WMI, to netapi win32 dlls.
i have some code that seems to join a domain but fails on the rename sometime with error 53 which is wierd. either way, I am looking for a robust way to perform these 2 operations in c# (any reasonable method (WMI seems to be common). in a robust way with only 1 reboot required. my code will be running on a windows server 2008 R2 machine that is not a member of the domain, but a user will enter domain creds allowing the join.
Avatar of gtworek
gtworek
Flag of Poland image

Did you try to begin with rename then join?
Avatar of wolfiewolf
wolfiewolf

ASKER

rename then join results in renaming success then a join success then a reboot and the computer showing up under the old name. so yes tried and failed, but again i am looking for some c# examples here.
Avatar of Chinmay Patel
HI wolfiewolf,
Are you trying to avoid reboot at all or you are looking for automation when you want to avoid Reboot?
Regards,
Chinmay


the reboot is required however i don't want to do 2 reboots -one for domain join and one for rename.
like in the windows UI, you can join domain and rename in one operation then reboot, i know how to reboot from c#. my problem is piecing together the wmi or (any other api) calls for join and rename to work correctly.
Ok. I suggest you try rename and then join domain. That should work. You need C# code to do this? How about writing a script and then via Process class calling it to get the job done? 
I believe if you rename and join then you won't have to do two reboots. Also there is a possibility that we can do this entire process without C# and in a single reboot.
Let me know which way you would like to go?


guess you did'nt read my priovus comment about how rename then join looks like it succeeds but does not.
i need to c# code because at each point i want to catch possible exception and report them back to our control software.
Alright. I did read it reverse. :|
I read you join and then rename. Sorry my bad.
Coming to your code
I think you would have also used ManagementClass right? if yes then post your code here and I will help you translate it to something so that it can reboot after the name change and then automatically login and join the domain and reboot again to complete the process? If you don't have C# code then just let me know.
Also for that error 53 I found this check points
1) if it is domain environment, check your WINS;
2) if it is peer-to-peer workgroup, enable NetBIOS over TCP/IP;
3) make sure the machine is running;
4) make sure file and Printer Share enabled on remote computer;
5) make sure client for ms networks is enabled on local computer;
6) make sure you type the correct name.
7) Make sure no firewall running or any security setting.

Regards,
Chinmay


ok here is what i already have, i know the username and password are good because the domain join works. what even more wierd if that something is not quite right here because when it gets this error 53 for the rename, if i then goto the stock windows ui and change hostname it get error dialog with the same error. so it's almost as if the join was not 100% or something.
/**********************************************************************
* GetComputerName: Gets the local computer name
* Inputs:  None
* Outputs: String representing name, empty string if unavailable
**********************************************************************/
public string GetComputerName()
{
	string szRet = "";
	ManagementClass objMC;
	ManagementObjectCollection objMOC;

	try
	{
		// caller doesn't have to catch
		objMC = new ManagementClass("Win32_ComputerSystem");
		objMOC = objMC.GetInstances();
	}
	catch (ManagementException e)
	{
		SymDebug.EmitString(SymDebug.Severity.warning, "Caught management exception looking up WMI - name not available. ({0})", e.Message);
		return szRet;
	}
	catch (Exception e)
	{
		SymDebug.EmitString(SymDebug.Severity.warning, "Caught unexpected exception looking up WMI - name not available. ({0})", e.Message);
		return szRet;
	}

	foreach (ManagementObject objMO in objMOC)
	{
		if (null != objMO)
		{
			szRet = objMO["Name"].ToString();
			break;
		}
	}

	return szRet;
}

/**********************************************************************
* GetDomainName: Gets the attached machine domain name
* Inputs:  none
* Outputs: Domain name, or empty string if not on a domain
**********************************************************************/
public string GetDomainName()
{
	string szRet = "";
	ManagementClass objMC;
	ManagementObjectCollection objMOC;

	try
	{
		// caller does not have to catch
		objMC = new ManagementClass("Win32_ComputerSystem");
		objMOC = objMC.GetInstances();
	}
	catch (ManagementException e)
	{
		SymDebug.EmitString(SymDebug.Severity.warning, "Caught management exception on getting domain name: {0}", e.Message);
		return szRet;
	}
	catch (Exception e)
	{
		SymDebug.EmitString(SymDebug.Severity.warning, "Caught unexpected exception on getting domain name: {0}", e.Message);
		return szRet;
	}
			
	foreach (ManagementObject objMO in objMOC)
	{
		if (null != objMO)
		{
			if ((bool)objMO["partofdomain"])
			{
				szRet = objMO["domain"].ToString();
				SymDebug.EmitString(SymDebug.Severity.info, "System is part of domain '{0}'", szRet);
			}
			else
			{
				SymDebug.EmitString(SymDebug.Severity.info, "System is part of workgroup, no domain.");
			}
		}
	}

	return szRet;
}

/**********************************************************************
* HandleJoinDomain: Joins the named domain
* Inputs:  szDomain eg. foo.com
 *         szNewHostname eg user-pc
 *         szUsername (domain authed to add machines to domain) so: Administrator@foo.com
 *         szPassword the password
* Outputs: none
**********************************************************************/
public void HandleJoinandRenameDomain(string szDomain,string szNewHostname, string szUsername, string szPassword)
{
    string szCurrentHostname = GetComputerName();
    string szCurrent = GetDomainName();
    if ("" != szCurrent)
    {
        if (szCurrent.ToUpper() == szDomain.ToUpper())
        {
            // already correct 
            SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Already joined to Host: '" + szCurrentHostname + "' domain: '" + szCurrent + "'");
            // since if this was true then hostname could not have been changed so we are done.
            return;

        }
        else
        {
            // else, it's incorrect, send a failure (user must unjoin)      
            SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed: Already joined to '" + szCurrent + "'. Can not attach to multiple domains.");
            return;
        }
    }   
    ManagementObject objMO = new ManagementObject("Win32_ComputerSystem.Name='" + szCurrentHostname + "'");
    if (null != objMO)
    {
        ManagementBaseObject result;

        // documented at http://msdn.microsoft.com/en-us/library/aa392154%28VS.85%29.aspx
        objMO.Scope.Options.EnablePrivileges = true;
        objMO.Scope.Options.Authentication = AuthenticationLevel.PacketPrivacy;
        objMO.Scope.Options.Impersonation = ImpersonationLevel.Impersonate;

        ManagementBaseObject query;
        try
        {
            // we catch
            query = objMO.GetMethodParameters("JoinDomainOrWorkgroup");
        }
        catch (ManagementException)
        {
            SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed to look up local computer for join");
            return;
        }
        query["Name"] = szDomain;
        query["Password"] = szPassword;
        query["UserName"] = szUsername;
        query["FJoinOptions"] = 1 + 2; // + 256 (tried with and with 256

        SymDebug.EmitString(SymDebug.Severity.info, "Attempting WMI method JoinDomainOrWorkgroup({0}, ***, {1}, null, {2}).", query["Name"].ToString(), query["UserName"].ToString(), query["FJoinOptions"].ToString());
        try
        {
            result = objMO.InvokeMethod("JoinDomainOrWorkgroup", query, null);
        }
        catch (ManagementException e)
        {
            SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed (" + (uint)e.ErrorCode + ") to execute join request: " + e.Message);                   
            return;
        }

        if (0 != (uint)result["ReturnValue"])
        {
            SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed (" +(uint)result["ReturnValue"] + ") to execute join request");                         
            return;
        }
      
        // need to try and set hostname before domain join since it cannot be done beforehand (tried)
        if ((szCurrentHostname.ToUpper() != szNewHostname.ToUpper()) && ("" != szNewHostname))
        {
            try
            {
                SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Setting Hostname");               
                ManagementBaseObject query2;
				query2 = objMO.GetMethodParameters("Rename");
				query2["Name"] = szNewHostname;
                query2["Password"] = szPassword;
                query2["UserName"] = szUsername;

                SymDebug.EmitString(SymDebug.Severity.info, "Attempting WMI method Rename({0}, {1}, ***).", query2["Name"].ToString(), query2["UserName"].ToString());
				result = objMO.InvokeMethod("Rename", query, null);

				if (0 != (uint)result["ReturnValue"])
				{
                    SymDebug.EmitString(SymDebug.Severity.info, "Failed to set Computer name, code " + result["ReturnValue"].ToString());
				}
		

				SymDebug.EmitString(SymDebug.Severity.alert, "Host name change request successful - ASM must be rebooted.");

				// now we're done :)
				return;
            }
            catch (InvalidOperationException e)
            {
                SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed: " + e.Message);
                return;
            }
            catch (ManagementException e)
            {
                SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed change hostname: " + e.Message);
                return;
            }
        }
        // reboot
        // now we're done :)
        return;
    }
    else
    {
        SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed to open computer management object.");              
        return;
    }
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Chris Dent
Chris Dent
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ok i can't believe i missed that but that was it, NETSETUP_JOIN_WITH_NEW_NAME. i don't need the win32 api since my wmi method has the same option. so the new complete solution below:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.IO;
using System.Management;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Security;
using System.Security.Principal;
using System.Security.Cryptography.X509Certificates;
using System.ServiceProcess;
using System.Runtime.InteropServices;

namespace domainjoin
{
    public class SymDebug
    {
        public enum Severity
        {
            emerg = 0,	// total system failure, operation will not continue
            alert,		// immediate attention required
            crit,		// serious malfunction requiring user action
            err,		// correctable error detected
            warning,	// warning of an event or circumstance
            notice,		// notices requiring attention at some later time
            info,		// normal information
            debug,		// lowest debug level
            none		// don't use this
        };
        public static void EmitString(Severity sev, string szFormat, params object[] args)
        {
            Debug.Print(szFormat, args);
        }
    };

    class Program
    {
        static void Main(string[] args)
        {
            HandleJoinandRenameDomain("foo.com", "newhostname", "foo@foo.com", "passfoo");
        }
    

/**********************************************************************
* GetComputerName: Gets the local computer name
* Inputs:  None
* Outputs: String representing name, empty string if unavailable
**********************************************************************/
public static string GetComputerName()
{
	string szRet = "";
	ManagementClass objMC;
	ManagementObjectCollection objMOC;

	try
	{
		// caller doesn't have to catch
		objMC = new ManagementClass("Win32_ComputerSystem");
		objMOC = objMC.GetInstances();
	}
	catch (ManagementException e)
	{
		SymDebug.EmitString(SymDebug.Severity.warning, "Caught management exception looking up WMI - name not available. ({0})", e.Message);
		return szRet;
	}
	catch (Exception e)
	{
		SymDebug.EmitString(SymDebug.Severity.warning, "Caught unexpected exception looking up WMI - name not available. ({0})", e.Message);
		return szRet;
	}

	foreach (ManagementObject objMO in objMOC)
	{
		if (null != objMO)
		{
			szRet = objMO["Name"].ToString();
			break;
		}
	}

	return szRet;
}

/**********************************************************************
* GetDomainName: Gets the attached machine domain name
* Inputs:  none
* Outputs: Domain name, or empty string if not on a domain
**********************************************************************/
public static string  GetDomainName()
{
	string szRet = "";
	ManagementClass objMC;
	ManagementObjectCollection objMOC;

	try
	{
		// caller does not have to catch
		objMC = new ManagementClass("Win32_ComputerSystem");
		objMOC = objMC.GetInstances();
	}
	catch (ManagementException e)
	{
		SymDebug.EmitString(SymDebug.Severity.warning, "Caught management exception on getting domain name: {0}", e.Message);
		return szRet;
	}
	catch (Exception e)
	{
		SymDebug.EmitString(SymDebug.Severity.warning, "Caught unexpected exception on getting domain name: {0}", e.Message);
		return szRet;
	}
			
	foreach (ManagementObject objMO in objMOC)
	{
		if (null != objMO)
		{
			if ((bool)objMO["partofdomain"])
			{
				szRet = objMO["domain"].ToString();
				SymDebug.EmitString(SymDebug.Severity.info, "System is part of domain '{0}'", szRet);
			}
			else
			{
				SymDebug.EmitString(SymDebug.Severity.info, "System is part of workgroup, no domain.");
			}
		}
	}

	return szRet;
}

/**********************************************************************
* HandleJoinDomain: Joins the named domain
* Inputs:  szDomain eg. foo.com
 *         szNewHostname eg user-pc
 *         szUsername (domain authed to add machines to domain) so: Administrator@foo.com
 *         szPassword the password
* Outputs: none
**********************************************************************/
public static void HandleJoinandRenameDomain(string szDomain, string szNewHostname, string szUsername, string szPassword)
{
    string szCurrentHostname = GetComputerName();
    string szCurrent = GetDomainName();
    // need to try and set hostname before domain join since it cannot be done beforehand (tried)
    ManagementObject objMO = new ManagementObject("Win32_ComputerSystem.Name='" + szCurrentHostname + "'");
    if (null != objMO)
    {
        ManagementBaseObject result;

        // documented at http://msdn.microsoft.com/en-us/library/aa392154%28VS.85%29.aspx
        objMO.Scope.Options.EnablePrivileges = true;
        objMO.Scope.Options.Authentication = AuthenticationLevel.PacketPrivacy;
        objMO.Scope.Options.Impersonation = ImpersonationLevel.Impersonate;

        if ((szCurrentHostname.ToUpper() != szNewHostname.ToUpper()) && ("" != szNewHostname))
        {
            try
            {
                SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Setting Hostname");
                ManagementBaseObject query2;
                query2 = objMO.GetMethodParameters("Rename");
                query2["Name"] = szNewHostname;
                query2["Password"] = null;
                query2["UserName"] = null;

                SymDebug.EmitString(SymDebug.Severity.info, "Attempting WMI method Rename({0}, ***).", query2["Name"].ToString());
                result = objMO.InvokeMethod("Rename", query2, null);

                if (0 != (uint)result["ReturnValue"])
                {
                    SymDebug.EmitString(SymDebug.Severity.info, "Failed to set Computer name, code " + result["ReturnValue"].ToString());
                }


                SymDebug.EmitString(SymDebug.Severity.alert, "Host name change request successful - ASM must be rebooted.");
          
            }
            catch (InvalidOperationException e)
            {
                SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed: " + e.Message);
                return;
            }            
            catch (ManagementException e)
            {
                SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed change hostname: " + e.Message);
                return;
            }
        }
        if ("" != szCurrent)
        {
            if (szCurrent.ToUpper() == szDomain.ToUpper())
            {
                // already correct 
                SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Already joined to Host: '" + szCurrentHostname + "' domain: '" + szCurrent + "'");
                // since if this was true then hostname could not have been changed so we are done.
                return;

            }
            else
            {
                // else, it's incorrect, send a failure (user must unjoin)      
                SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed: Already joined to '" + szCurrent + "'. Can not attach to multiple domains.");
                return;
            }
        }   
     
        ManagementBaseObject query;
        try
        {
            // we catch
            query = objMO.GetMethodParameters("JoinDomainOrWorkgroup");
        }
        catch (ManagementException)
        {
            SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed to look up local computer for join");
            return;
        }
        query["Name"] = szDomain;
        query["Password"] = szPassword;
        query["UserName"] = szUsername;
        query["FJoinOptions"] = 1 + 2 +1024; // + 256 (tried with and with 256

        SymDebug.EmitString(SymDebug.Severity.info, "Attempting WMI method JoinDomainOrWorkgroup({0}, ***, {1}, null, {2}).", query["Name"].ToString(), query["UserName"].ToString(), query["FJoinOptions"].ToString());
        try
        {
            result = objMO.InvokeMethod("JoinDomainOrWorkgroup", query, null);
        }
        catch (ManagementException e)
        {
            SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed (" + (uint)e.ErrorCode + ") to execute join request: " + e.Message);                   
            return;
        }

        if (0 != (uint)result["ReturnValue"])
        {
            SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed (" +(uint)result["ReturnValue"] + ") to execute join request");                         
            return;
        }    
       
          
    }
    else
    {
        SymDebug.EmitString(SymDebug.Severity.info, "Join Domain: Failed to open computer management object.");              
        return;
    }
}


    }
}

Open in new window