The Ultimate RODC Q&A


, , , , , ,

During the past couple of months many people have asked me a lot of questions regarding the functionality of RODCs. It’s a relatively new concept and some information are not easily available as well. So I thought of recording them in this post so the information is easily available at a single place for everyone. The purpose of this post is to answer the questions to which the answers are not readily available out there. Therefore, the basic stuff are obviously not covered here except for a few of them like the first two. 🙂

What is a RODC?

A Windows domain controller that holds complete, read-only copies of the partitions of the Active Directory database and a read-only copy of the SYSVOL folder and its contents.

Why a RODC?

By selectively caching credentials, RODCs address some of the challenges that enterprises can encounter in branch office locations where physical security of the domain controllers cannot be guaranteed or where other applications must run on the domain controller and be maintained by a server administrator that is not a domain administrator.

Is RODC DNS different?

Yes. The DNS of a RODC is also read-only and it refers to a writable DNS server for any write requests that are directed to it. Afterwards the new information is replicated back to itself.

How does dynamic DNS work with RODC?

When a client attempts a dynamic update, it sends a Start of Authority (SOA) query to its preferred DNS server. Typically, clients are configured to use the DNS server in their branch site as their preferred DNS server. The RODC reads its SOA record and at best effort return a writable Windows Server 2008 domain controller to the client. The client makes the dynamic update at the writable DNS server returned. The RODC waits a time that is a minimum of 30 seconds and a maximum of 210 seconds and attempts to replicate the updated DNS record object in Active Directory from the DNS server that it referred the client to through a Replicate Single Object (RSO) operation back to itself.

How are the minimum and maximum waiting times calculated?

The SOA query triggers the DNS server on the RODC to put an entry in remotePollList, which is an internal queue on each DNS server. The entry includes the following:

  • The object to be replicated
  • The source domain controller to replicate from
  • A time stamp

The time stamp is set to a time in the future that is equal to the current time plus a replication delay. The replication delay is controlled by a registry setting named DsRemoteReplicationDelay. By default, the value of this setting is 30 seconds. The internal queue (remotePollList) is processed at regular intervals. The queue-processing interval is controlled by a registry setting named DSPollingInterval. By default, the value of the interval is 3 minutes (180 seconds).

When the DNS server processes the queue, it attempts to replicate only objects whose time stamp is less than current time. Therefore, the delay between the time that the RODC refers the client to an authoritative DNS server and then attempts to replicate in is determined by the following:

  • The next time that the DNS server processes the queue
  • Whether the remote replication delay that is set on the entry in the queue has elapsed

If the default values for the registry settings are used then the amount of time before the RODC attempts to perform a RSO operation is a minimum of 30 seconds where the DsRemoteReplicationDelay has exceeded and a polling operation is executed, and a maximum of 210 (180+30) seconds where the DsRemoteReplicationDelay has exceeded and a polling operation is yet to be executed.

Can these values be changed for faster replication?

Yes. You can modify the values of these registry settings to reduce the amount of time before the RODC attempts to replicate the DNS update. The minimum value for the DsRemoteReplicationDelay setting is 5 seconds. The minimum value for the DSPollingInterval setting is 30 seconds. When the minimum values are used the amount of time before the RODC attempts to replicate the DNS update is a minimum of 5 seconds and a maximum of 35 seconds.

Will the changes affect other Active Directory operations of the RODC?

Yes. DsPollingInterval controls all Active Directory polling, not just RODC RSO handling. If you change this value, be aware that this change will affect more than just RODC RSO operations. For example, this setting will affect how often the DNS server polls Active Directory for new or updated resource records or DNS zones.

What is a RSO operation?

A RSO operation is an operational attribute named replicateSingleObject that has existed in Active Directory since Windows 2000 and allows replication of a single object by using a LDAP modify operation of the replicateSingleObject attribute. However the replicateSingleObject has been updated in Windows Server 2008 to support replication of secrets to RODCs.

Can a large number of RSO operations overload a domain controller?

No. The maximum number of RSO requests per 5 minutes cycle is limited to 300 to prevent Denial of Service attacks.

Do RODC’s register NS records?

No. RODC’s do not register Name Server (NS) records.

What is the SOA selection model for RODC’s?

  1. Try to select a writable domain controller that is running Windows Server 2008 and is published as a Name Server for the zone.
  2. Pick a random NS from the NS list if there are no Windows Server 2008 writable domain controllers that have published a NS for the zone.

Can a RODC select another RODC as a SOA during the selection process?

No. Since RODCs do not register NS records they are not available for selection.

Are SOAs selected every time a DNS update operation is requested?

No. The current SOA target DC is maintained separately for each zone and re-selected every 20 minutes. The duration is not configurable.

Is the same SOA DC selected during each selection process?

No. The selection algorithm contains a random component to try to spread load between writable domain controllers.

Is there a tool to make the DNS related registry modifications in a RODC safely?

Yes. To modify any of the registry entries that are related to the RSO operations for DNS updates on an RODC, use the Dnscmd.exe command-line tool to set the appropriate parameter.
Example: “dnscmd <server>.<domain>.<com> /Config /DsRemoteReplicationDelay 10”

Can we make changes in the SYSVOL of a RODC?

Yes but the changes will be overwritten with the SYSVOL content from a writable domain controller during the next replication cycle. So it would be a useless task.

Do RODCs store any credentials at all?

Yes. It stores the credentials for its own computer account and the krbtgt account that is unique to it but nothing else.

Do RODCs use the normal krbtgt account of the domain for authentication services?

No. During the promotion of a RODC a separate krbtgt account is created on the domain for the use of that particular RODC only. This account is used for all authentication operations performed at this RODC.

Are RODCs advertised as Key Distribution Centers (KDCs)?

Yes but only for its own site.

If the credentials are not replicated then how can a user or computer authenticate for the first time with a RODC?

The first time an account attempts to authenticate to an RODC, the RODC sends the request to a writable domain controller. If the authentication is successful, the RODC also requests a copy of the appropriate credentials. The writable domain controller recognizes that the request is coming from an RODC and consults the Password Replication Policy that is in effect for that RODC to check if the requested credentials are allowed to be cached.

What is a “Password Replication Policy”?

The Password Replication Policy determines if a set of credentials are allowed to be replicated and stored on a particular RODC. If allowed, a writable domain controller sends the credentials to the RODC, and the RODC caches them. After the credentials are cached the next time that user or computer attempts to log on, the request is directly serviced by the RODC.

Do RODCs cache credentials for eternity?

No. The cached credentials are flushed once they are changed.

Can a non-domain administrator be made an administrator of a RODC?

Yes. This is known as “Administrative Role Separation”. A user can be given administrative access to a single RODC without giving administrative access to any other domain controllers.

What explicit access the “RODC admins” have on Active Directory?


Do RODCs support DFS-n and DFS-R?


How does DFS replication work in a RODC?

As for ADDS, the DFS replication of a RODC is also unidirectional in the inbound direction.

A RODC is a domain controller. Can a corruption or a potentially harmful change at a RODC damage the whole domain?

No. No changes at a RODC are replicated outbound.

Can a non-domain administrator promote a RODC?

Yes but the new RODC’s domain controller account should be created prior to the promotion by a domain administrator. Check Steps for Deploying a RODC for more information.

How do RODC’s handle password changes?

When a password change is requested by a user or computer in a RODC site the request is forwarded to a writable domain controller that runs Windows Server 2008 or later. The next steps are the same as would occur if the password change happened directly on the writable domain controller.

Can a cached password be cleared/flushed from a RODC?

No. There is no mechanism to erase passwords after they are cached on a RODC. If you want to clear a password that is stored on a RODC, the password should be reset at a writable domain controller.

Are there any advantages of hosting RODCs on Microsoft Azure?

Yes. Microsoft Azure does not charge for inbound network traffic. Since RODCs only perform inbound replications there will be no chargeback for network usage. Usage of other resources such as compute and storage will still be charged.

What will fail at a RODC site if a writable domain controller is not available?

  • Access to Windows Management Instrumentation (WMI) filters by Group Policy.
    • Failure to access WMI filters may prevent affected clients from applying intended Group Policy or cause those clients to improperly apply Group Policy.
  • Application of Internet Protocol Security (IPsec) policies by IPsec clients.
  • Time synchronization in Windows XP and Windows Server 2003.
    • The Windows Time service (W32time) in Windows XP and Windows Server 2003 does not recognize an RODC.
  • Domain joins.
  • Password changes.
  • Retrieval and creation of public key certificates.
    • The Data Protection Application Programming Interface (DPAPI) on client computers that only have access to an RODC cannot decrypt master keys unless they have previously contacted a writable domain controller and retrieved a public key certificate. Clients that only have access to an RODC cannot decrypt master keys.
  • Successful publishing of printers in ADDS.
    • If an RODC services a client request to publish a printer, it forwards the request to a writable domain controller. The spooler attempts to read from the RODC immediately after the write. Since the information has not yet been replicated to the RODC, and spooler fails the publish operation. All spooler internal structures are updated, and the printer is marked as unpublished.
  • Retrieval of printers published in ADDS.
  • Active Directory Service Interfaces (ADSI) calls.


Delegating User/Computer Delegation to Non-domain Admins


, , , , ,

Last week I came across a situation where a user needed to set up Microsoft SQL Server Reporting Services and was having difficulties in integrating Kerberos to it. He needed to change the options related to account delegation continuously on several user accounts and computer accounts that he was using for this purpose. Since he had no experience with Active Directory I was helping him with his queries and changing these options when needed. After some time, my schedule started to conflict with his troubleshooting. Therefore I decided to give him a quick training on Active Directory basics and delegate the necessary permissions for him so he can continue with his work at his own pace.

From a quick glance, trusting user/computer account for delegation is an option related to each user or computer account. So granting Full control to the target account for the user should work fine. But this was not the case! After the user was granted permissions, he was receiving the error message “The following Active Directory Domain Services error occurred: Access is denied.” Now this is a “super helpful” error message with a lot of information in it, that could direct us to a solution – “Thanks Microsoft”! 😀

Before the user was granted Full control - all options are greyed out due to lack of permissions.

Before the user was granted Full control – all options are greyed out due to lack of permissions.

The options are available after the user was granted Full control for this computer account.

The options are available after the user was granted Full control for this computer account.

The "super helpful" error message received when trying to save delegation options.

The “super helpful” error message received when trying to save delegation options.

A day passed. I tried delegating at the OU level – no success! Since my mind was telling me that there should be a solution I decided to seek help from Google! One of the interesting search results was this post and it directed me to a setting in group policy. Who would think to look that far for a simple thing like this?!!

The delegation settings for user accounts and computer accounts belong to the domain controllers, sort of. Therefore a user needs to have this permission on the domain controllers. When you go to User Rights Assignment section in the Default Domain Controllers Policy (Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Local Policies -> User Rights Assignment), you can find the setting Enable computer and user accounts to be trusted for delegation. By default only the Administrators are granted this permission. Since I did not want to come here and change the GPO every time a user is in need of this permission, I decided to create a security group named “Access.EnableDelegation” and added it to this GPO setting. Once the user was added to this security group, voila! he is now able to change this setting himself and I’ve got a very happy customer. 🙂

The GPO setting

The GPO setting “Enable computer and user accounts to be trusted for delegation”

Adding the new security group to the GPO setting

Adding the new security group to the GPO setting

A few things to note

  • Microsoft cautions on using this permission as it can impersonate clients and use their credentials to gain access to network resources. Therefore, make sure that the users are revoked of this permission once they are done using it.

Misuse of this user right, or of the Trusted for Delegation setting, could make the network vulnerable to sophisticated attacks using Trojan horse programs that impersonate incoming clients and use their credentials to gain access to network resources.

  • It is a best practice to perform custom changes such as this one in a separate GPO rather than in the Default Domain Controllers Policy.
  • Once a user is granted this permission he has access to change delegation options for all user accounts and computer accounts. Be mindful of the scope of this permission. The only workaround for this would be to use “data hiding”. No one can change anything that is not visible to them!

Delegating Microsoft DHCP Server Administration in a Windows Domain, “completely”


, , , , ,

“What is there to talk about a simple task like this?!” – this question you may have in your mind is actually a valid question on first look. If you’ve ever had the need to delegate the Microsoft DHCP server administration to a person or, say the network team of your organization you might have used the built-in domain local Active Directory security group “DHCP Administrators” pretty easily but does this approach delegate the DHCP infrastructure “completely” from an Active Directory perspective? Not exactly! You might experience the incompleteness of this “delegation” when your network team says that they cannot authorize or unauthorize DHCP servers. So how do we make this “complete”?

The  domain local security group DHCP Administrators

The domain local security group DHCP Administrators

To do this task we need to look a little deeper into the Active Directory (well, as usual 😉 ). The DHCP server metadata is stored in the NetServices compartment in the node Services in the Active Directory Sites and Services.

How to expose the Service node in Active Directory Sites and Services

How to expose the Service node in Active Directory Sites and Services

The metadata are stored in the dHCPClass objects and each authorized DHCP server has a corresponding dHCPClass object. These corresponding dHCPClass objects are created during the authorization process of DHCP servers and are deleted during the process of unauthorization. Now you almost know what to do next! 😉

dHCPClass objects

dHCPClass objects (Note: DhcpRoot is present by default and you shouldn’t meddle with it!)

The delegation of authorization and unauthorization of DHCP servers is two-fold.

  1. Granting permission to create/delete dHCPClass objects.
  2. Granting permission to change all properties of the existing dHCPClass objects.

So, we go into the Security tab of the NetServices node and find the create/delete dHCPClass objects permission or ACL. But wait, where are those ACLs???

Permissions available in Active Directory Sites and Services which does not contain dHCPClass objects

Permissions available in Active Directory Sites and Services which does not contain dHCPClass objects

"Applies to" section available in Active Directory Sites and Services which does not contain dHCPClass objects

“Applies to” section available in Active Directory Sites and Services which does not contain dHCPClass objects

After pulling our my hair for a few minutes I decided to call upon my sweet friend, the “ADSI Edit”! 🙂 The NetServices node is located in the Configuration naming context in Active Directory. (Note: viewing the Configuration naming context using ADSI Edit is not covered here.)


Now we are in business! When you go into the security settings of the node NetServices you can see the two ACLs Create dHCPClass objects and Delete dHCPClass objects. You need to select the This object only from the Applies to: section as it is useless to propagate this ACL to the child objects.

The dHCPClass ACLs - yay! :)

The dHCPClass ACLs – yay! 🙂

When we set the two ACLs shown above we have already accomplished the first goal of ours, which is to delegate permission to create/delete dHCPClass objects. The second goal is to delegate permission to change all properties of existing dHCPClass objects. To accomplish this task we need to Allow List Contents, Read all properties, Write all properties, and Delete to the Descendant dHCPClass objects. Of course you can grant Full control but its really unnecessary!

Always remember the principle of least privilege and never grant a permission that is not needed.

Delegation permissions for exisiting dHCPClass objects

Delegation permissions for existing dHCPClass objects

That’s it! But you know, you can make this delegation “perfect” so no one will ever have to worry about this in future. What if you delegate these permissions to a security group, say “DHCP Authorizers” and add the built-in DHCP Administrators domain local security group as a member to it? Pretty nice ha! Now the DHCP Administrators will indeed be the “full” DHCP Administrators after all.

Until next time!

Note: By default, only the Domain Admins and the Enterprise Admins have the privilege to authorize and unauthorize DHCP servers in an Active Directory domain.

Reset CPU ID Masks of VMware vSphere Virtual Machines


, , , , ,

It was 2013, a warm sunny day in Colombo and another busy day in my virtual world. We just upgraded all our VMware hosts to new hardware. With new hardware comes new features that can be made available for the virtual machines hosted in them. One of those features that almost always arrives with new hardware is new CPU capabilities. When the hardware is upgraded the CPU Identification Masks should be reset or “refreshed” to match the new host CPU register values so that incompatible values are removed to prevent vMotion issues when the EVC mode is changed to the latest level. As you might already know, upgrading the EVC mode to the newer levels exposes more CPU features to the virtual machines. So you should definitely do it unless there is a very good reason to do otherwise. In my opinion this whole refresh process should be automatic but who am I to shout at VMware. 😉 When we performed the initial random check on our virtual machines’ CPU ID Masks the VMs we found sometimes had the identification masks set and sometimes not. There was no consistency across the virtualization environment. Once we ran our script we noticed that only around 20% of the total number of VMs actually had any CPU ID Mask configuration set and this was never set by us. I’m not sure of the exact reason behind this difference in configuration of the CPU ID Masks of these VMs and why these (or some) ID masks “stick” for the lifetime of a VM. My guess is that these CPU ID Masks are somehow set automatically during some events and the resulting mask depends on the hardware of the host that the VM resides during the time. The task of resetting the CPU ID Mask is simple as clicking a button in the vSphere client but is unimaginably complex when it comes to scripting it. There was no easy way of doing this and not even a clue to reach my goal even remotely with PowerCLI. The one that came to the rescue was one of the VMware Flings – Onyx. VMware Flings available at the VMware Labs has a lot of powerful nifty tools that can ease a vSphere admin’s life.

Onyx is a standalone application that serves as a proxy between the vSphere Client and the vCenter Server. It monitors the network communication between them and translates it into an executable PowerShell code.

So once I used Onyx to monitor and retrieve what the vSphere client actually sends to the vCenter server when we reset the CPU ID Mask of a VM the task was pretty straight forward. Playing with the vCPU’s core was frightening for us as this was our first time doing it and there was no much documentation of it online as well. Since we were performing this task on the production VMs we wanted the task to be more than perfect to avoid any angry customers. So we decided to contact the VMware support. I won’t go into the detail here but the VMware support took a relatively long time to respond to us with a clear answer on how we needed to perform this task and whether we were on the right track in doing it. Basically from their responses it seemed that they were new to this task as us. 🙂 Finally they confirmed that what we did in our script to reset the CPU ID Mask was correct. So we decided to proceed with it. Before running it I decided to add extensive logging so I can revert changes in case something goes horribly wrong. We executed the script from the vCenter servers during a maintenance weekend and it worked like a charm. Time to grab a cold beer!

Update: I have noticed that WordPress messes up the PowerShell syntax in the script. Please use this link to download the script directly.

The code:

# ========================================================================
# name		: reset_cpu_id_mask_to_default.ps1
# author	: Nimantha Wickremasinghe
# version	: 1.0
# purpose	: Reset CPU ID Masks to default values.
# requirements  : PowerCLI
# ========================================================================

# ------- Get_Current_User -------
$script:currentUser = $env:userprofile.split('\')[2]
$script:logPath = &amp;amp;quot;C:\$currentUser\Script_Logs\&amp;amp;quot;

# ------- Get_All_Powered_Off_VMs -------
Function Get-PoweredOffVMs {
	return Get-VM | ? {$_.PowerState -eq 'PoweredOff'}

# ------- ReconfigVM_Task -------
Function Reset-vCpuMask($vm) {
	    $vmConfigSpec = new-object VMware.Vim.VirtualMachineConfigSpec
	    $featureMask = new-object VMware.Vim.VirtualMachineCpuIdInfoSpec
	    $featureMask.Operation = &amp;amp;quot;remove&amp;amp;quot;
		$ = new-object VMware.Vim.HostCpuIdInfo
		$ = 0x80000001
	    $featureMaskAMD = new-object VMware.Vim.VirtualMachineCpuIdInfoSpec
	    $featureMaskAMD.Operation = &amp;amp;quot;remove&amp;amp;quot;
	    $ = new-object VMware.Vim.HostCpuIdInfo
		$ = 0x80000001
	    $ = &amp;amp;quot;amd&amp;amp;quot;
	    $vmConfigSpec.CpuFeatureMask = $featureMask,$featureMaskAMD

		$view = get-view $
		Log-Summary ($vm.Name +&amp;amp;quot;: Set CPU ID Masks to default ------- OK&amp;amp;quot;)
	catch {
		Log-Failed ($vm.Name + ': ------- FAILED! --- ' + $Error[0])

# ------- Backup_OldvCpuMask -------
Function Backup-OldvCpuMask($vm) {
	$bkpLogPath = &amp;amp;quot;$logPath\Backup\&amp;amp;quot;
	$bkpFileName = $vm.Name
		[array]$CpuFeatueMask = (Get-View $
		if($CpuFeatueMask) {
			if (!(Test-Path $bkpLogPath)) {
				New-Item -ItemType directory -Path $bkpLogPath
			try {
				$CpuFeatueMask &amp;amp;gt;&amp;amp;gt; $bkpLogPath&amp;amp;quot;$bkpFileName.txt&amp;amp;quot;
				Log-Summary ($vm.Name +&amp;amp;quot;: Back up old CPU ID Masks ------- OK&amp;amp;quot;)
			catch {
				Log-Summary ($vm.Name +&amp;amp;quot;: Back up old CPU ID Masks ------- FAILED!&amp;amp;quot;)
		else {
			Log-Summary ($vm.Name +&amp;amp;quot;: Back up old CPU ID Masks --- (Masks Unset. Nothing to backup.) ------- OK &amp;amp;quot;)
	catch {
		Log-Failed ($vm.Name + ': ' + $Error[0])

# ------- Logging -------
Function Log-Failed ($logEntry) {
	$ErrorActionPreference = 'Stop'
	if (!(Test-Path $logPath)){
		New-Item -ItemType directory -Path $logPath
		Add-Content $logPath'Failed.log' &amp;amp;quot;$logEntry&amp;amp;quot;
		Write-Host $Error[0] -ForegroundColor Red
	Write-Host &amp;amp;quot;$logEntry&amp;amp;quot; -ForegroundColor Yellow

Function Log-Summary ($logEntry) {
	$ErrorActionPreference = 'Stop'
	$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
	if (!(Test-Path $logPath)) {
		New-Item -ItemType directory -Path $logPath
	try {
		Add-Content $logPath'Summary.log' &amp;amp;quot;$timestamp # $logEntry&amp;amp;quot;
	catch {
		Write-Host $Error[0] -ForegroundColor Red
	Write-Host &amp;amp;quot;$timestamp # $logEntry&amp;amp;quot; -ForegroundColor Cyan

# ------- Main -------
$choice = Read-Host `n'Start the script? [y/n]'
if ($choice -eq 'y') {	
	do {
		$vc = Read-Host `n'Specify the vCenter Server to connect [name/IP]'
		if ($vc) {
			if (Test-Connection -ComputerName $vc -Count 2 -Quiet -ErrorAction Stop) {
				asnp VMware.VimAutomation.Core -ErrorAction SilentlyContinue
				Log-Summary ($vc + ' available')
				Log-Summary ('------- Script Started -------')
				Log-Summary ('Connecting to ' + $vc + '...')
				try {
					Connect-VIServer $vc -ErrorAction Stop
					Log-Summary ('Connect to ' + $vc + ' ------- OK')

					Log-Summary ('Retrieving powered off VMs...')
					[array]$pwrOffVms = Get-PoweredOffVMs
					$pwrOffVmCount = $pwrOffVms.count
					Log-Summary (&amp;amp;quot;Retrieved $pwrOffVmCount VMs ------- OK&amp;amp;quot;)
					foreach ($vm in $pwrOffVms) {
						if ((Get-VM -Id $ -eq 'PoweredOff') {
							Log-Summary ($vm.Name + ': Task execution ------- START')
							Backup-OldvCpuMask ($vm)
							Reset-vCpuMask ($vm)
							Log-Summary ($vm.Name + ': Task execution ------- END')
						else {
							Log-Failed ($vm.Name)
							Log-Summary ($vm.Name + ': ------- FAILED! --- PowerState: ON')
						Log-Summary ('------- ########## -------')
					Disconnect-VIServer $vc -Confirm:$false -ErrorAction SilentlyContinue
					Log-Summary ('Disconnect from ' + $vc + ' ------- OK')
				catch {
					Log-Summary ($Error[0])
				Log-Summary ('------- Script Completed -------')
			else {
				Log-Summary ($vc + ' unavailable!')
		else {
			Write-Host `n'Please enter a valid name/IP for the vCenter Server!' -ForegroundColor Red
		$choice2 = Read-Host `n'Do you want to specify another vCenter Server to connect? [y/n]'
	} while ($choice2 -eq 'y')
	Write-Host `n&amp;amp;quot;Logs can be found at $logPath&amp;amp;quot; -ForegroundColor Green
	Write-Host `n`n&amp;amp;quot;Press any key to continue ...&amp;amp;quot;
	$x = $host.UI.RawUI.ReadKey(&amp;amp;quot;NoEcho,IncludeKeyDown&amp;amp;quot;)

Delegating DFS to Non-domain Admins


, , , , , ,

Last week I came across a company where its IT personnel is divided into teams based on specific services that the IT department offers the customers. Usually the Distributed File System (DFS) is managed by the person or the group of people who manages the Active Directory. However, in this scenario there is a different team to manage DFS, who is not responsible for managing the Active Directory.

At the time I started working with this, the practice has been for years is that, if a delegation cannot be easily done using the delegation wizard, a person was granted the Domain Admin privileges (or at least that was how it seemed). This needed to be changed!

When you open the DFS Management MMC console, the delegation is pretty straight forward. You can delegate separately for Namespaces and Replication groups using the Delegate Management Permission… option in the Actions pane.

DFS namespace delegation DFS Replication Groups delegation

This seemingly simple task becomes complicated when you have many replication groups as the delegations should be set for each group individually. In addition to this painstaking task, the delegations will need to be done for each new namespace and replication group individually as the delegations are not inherited. For a lazy guy like me, this was unacceptable! 🙂 It was time to dig deeper to find the gems!!

The DFS configuration metadata is stored in the containers Dfs-Configuration and DFSR-GlobalSettings in Active Directory. These containers can be found under the container System. The container Dfs-Configuration holds the DFS Namespace metadata in fTDfs objects and the container DFSR-GlobalSettings holds the DFS Replication metadata in msDFSR-ReplicationGroup objects.

DFS metadata containers

DFS metadata containers

At this point you can be creative on how you want to grant privileges. For my task I just needed to delegate the full control of DFS to the DFS team. So in the security settings of these two containers I added an ACL to allow Full Control for This object and all descendant objects to a new security group named “DFS Admins”. That’s all there is to it! Now when I go to the Delegation tab of a replication group, I can see the DFS Admins group has an ACL that is Inherited. A similar ACL will be there for the namespaces as well.

New inherited ACL

New inherited ACL

Delegating Microsoft NPS Administration, the non-standard way


, , , , , , ,

If you found this post, then you probably have searched to the ends of the Earth and the cyber space for a solution to this requirement. I know the frustration and I hope I have a solution for you!

My story starts in an organization with a Microsoft infrastructure where the Microsoft Network Policy Servers (NPS) are deployed on the domain controllers as recommended by Microsoft. The domain controllers are managed by the Directory Services team and the NPS, being a network service is managed by a separate Network Services team. Microsoft probably didn’t think of a scenario where the NPS is needed to be managed by a non-domain administrator before they publicly announced their recommendation on deploying the NPS. (It’s Microsoft, nothing surprising there 😉 ). When I started this work we already had more than 10 domain admins which is fairly high. There was only one person in the Network Services team and he was a member of the Domain Admins group since he was the one who managed NPS. The situation became complicated with the arrival of a new member to the Network team.

For NPS administration, you should be a member of the local administrators group of the server on which the NPS role is installed. In the recommended setup, the user should be a member of the domain controller’s Administrators group. There are 4 highly privileged groups in an Active Directory domain; Administrators, Enterprise Admins, Domain Admins, and Schema Admins. These groups are also called Protected Groups. (There are a few other Protected Groups as well). Out of these 4 groups, Administrators group is the most privileged group by design. For example, in a situation where the Administrators group is denied full control of an Active Directory object, a member of this group can “still” take ownership of that particular object and reset all the ACLs of it. Pretty neat ha!

In delegating NPS we have to use the Administrators group whether we like it or not. What we can do however is to reduce the undesired “impact” of this situation. We need to avoid using the groups Domain Admins and Enterprise Admins as they allow “heavenly powers” such as promotion and demotion of domain controllers. So the concepts to follow here are,

  1. enforcing the principle of least privilege, and
  2. preventing privilege escalation.

We have already covered the first one, where we decided to use the Administrators group instead of any other privileged group. Once a user is a member of the Administrators group he/she can freely add him/herself to Domain Admins or Enterprise Admins as he/she needs. The solution, we remove “write members” property on the groups Domain Admins and Enterprise Admins for Administrators right? Unfortunately this simple solution work only for the next ~60 minutes from the moment the change is done. In the built-in mechanics of Microsoft Active Directory, there is a process called SDProp that resets the ACLs of the Protected Groups every 60 minutes. (You can read more about this in the TechNet magazine and the AskDS TechNet blog). Now this is a dead end! We need to grant the Network team access to NPS to perform their day to day work but at the same time we don’t want them to be able to be Domain or Enterprise Admins as they please.

If they can’t see the groups Domain Admins, Enterprise Admins, Schema Admins, and Administrators (of course this one too, so that they can’t make one of their friends an Administrator 🙂 ) they can’t do anything to them right? How can someone change the membership of a group that they can’t see or access in the first place, right?! The strategy I followed here is called “data hiding in Active Directory”. I haven’t seen this technique being widely used but it is indeed a valuable feature. So I created a new group for NPS administration, let’s say “NPS Admins”, added it as a member of the Administrators group. Then I created a new OU named “Protected Objects” at the root of the directory,

  • denied Full Control on it for the “NPS Admins”,
  • disabled permission inheritance,
  • removed Administrators, Authenticated Users and other non-important ACLs, and
  • made sure that the Enterprise Admins, Domain Admins, SYSTEM, ENTERPRISE DOMAIN CONTROLLERS retain the permissions they need on it.

Hang on, we are almost there! Finally I moved the groups Domain Admins, Enterprise Admins, and Schema Admins into the new OU. Unfortunately, the group Administrators being a built-in one it cannot be moved. So I had to add an ACL on the Builtin OU that denied List Contents for the NPS Admins. That’s it, right? Not exactly! What if the new network guy decides to reset the passwords of all Domain Admins and Enterprise Admins one day?! Pretty scary right?! We need to protect them as well. So I moved the users that are members of these two groups into the Protected Objects OU. We have now delegated NPS administration in “safer way” without much compromise.

Protected Objects OU

Protected Objects OU

View of the Protected Objects OU for a NPS Admin

View of the Protected Objects OU for a NPS Admin

View of the Builtin OU for a NPS Admin

View of the Builtin OU for a NPS Admin

You need to make sure that any ACLs that grants “allow” permissions on the OU’s that contain user accounts and groups that are sensitive to your business are removed. Manage these permissions with custom access groups. Something to keep in mind in working with ACLs is that, although the deny ACLs always override the allow ones, in Microsoft Active Directory an allow ACL closest to the target object will override a deny one that is farthest to it. In other words, a non-inherited allow ACL will override an inherited deny one.

Note: If you go deep into modifying the AdminSDHolder you can be creative and set up ACLs on the Protected Groups and accounts according to your requirements but think twice before over complicating your set up. It might be a nightmare during troubleshooting in future, if not for you, then for the next domain administrator. Modifying the AdminSDHolder will not give any solution in delegating the NPS administration. You can read more about this in the Laura’s nice blog post here.

A Quick Report of GUID to Name Mappings of GPOs for the Busy SYSVOL Admins


, , , ,

A few weeks back, I needed to find the physical files or the folders of a few Group Policy Objects and I had to do the laborious task of navigating to each GPO in the Group Policy Management Console, navigating to the Details tab, copying the GUID, and searching for the GUID in the SYSVOL directory to find them. I could have done this within a few minutes if I already had the GUID to Name mappings of these GPOs. I could have quickly retrieved this each time I wanted by a PowerShell command but to do this I still need to run this command manually each time. So why not automate it?!!

So I came up with the following script to automate this task and created a scheduled task to run it daily. I also thought of preserving the mappings for some time so I can have a “sort of” timeline of creation and deletion of GPOs. So the script keeps a GUID to name mapping records for a single week before it overwrites the whole report on Monday. This was the simplest way to do this to fulfill my requirement. If you need to extend the number of days to retain the records you just need to think a bit more. 🙂

Note: You need to replace with your domain name before you run the script. You can use the Get-ADDomain cmdlet if you want to automate this part too.

The generated report will be similar to the following one and will be stored in your Policies directory.

GPO report

Please download the script from here as WordPress may have messed up the PowerShell syntax below.

The code:

# ==============================================================================================
# name    : get_gporeport.ps1
# author  : Nimantha Wickremasinghe
# purpose : Generate a GPO report with Guid-Name mapping.
# version : 1.0
# ==============================================================================================

Import-Module GroupPolicy -ErrorAction Stop

$hostname = [Environment]::MachineName
$date = Get-Date
$rptFile = &amp;amp;quot;\\&amp;amp;quot;+ $hostname +&amp;amp;quot;\sysvol\\Policies\GPOReport.txt&amp;amp;quot;

$rpt = &amp;amp;quot;$date&amp;amp;quot;
$rpt += Get-GPO -All | Select Id, DisplayName | Format-Table -AutoSize | Out-String -Width 10000
$rpt += &amp;amp;quot;===================================================================`n&amp;amp;quot;

if ($date.DayOfWeek -ne &amp;amp;quot;Monday&amp;amp;quot;) {
    # Overwrites the file on Monday.
    # Guid-Name history is kept for 7 days in the report.
    if (Test-Path -Path $rptFile) {
        $curData = Get-Content -Path $rptFile | Out-String

$rpt | Out-File $rptFile -Encoding ascii -Width 10000
# Without ASCII encoding Add-Content adds funny characters.

# Append the old data
if ($curData) {
    Add-Content $curData -Path $rptFile

Reporting VMware vCPU Usage Statistics for a Given Period of Time


, , ,

Some time back I was managing a VMware vSphere environment that was spread across several regions with more than two thousand virtual machines. In a very dynamic virtualised environment such as this one the virtual machines are sized frequently due to varying needs. After some time the VMs are sometimes allocated to different projects or decommissioned or sometimes the sizing was for a short term. These VMs that now have reduced workloads are over provisioned and one of the main resource that is over provisioned this way is the number of vCPUs. To maintain an efficient infrastructure it is a good practice to right size virtual machines from time to time.

The requirement I had this time was to right size virtual machines’ vCPU configurations. In this situation I focused on collecting the vCPU usage statistics of the virtual machines that had more than 2 virtual processors for a period of 30 days. One of the challenges in here was to limit the statistics to the working hours only so that I have a more accurate report on the work hour workload on them. Although I have laid the criteria to generate the report easily there was no option in VMware vSphere management console to collect this kind of a customized data set. Time to get into PowerCLI – yay! 🙂

Finally I ended up in writing the following script. It allows the user to specify the number of days from the day of the script is run to search for statistics during the runtime and generate a user friendly HTML report using the statistics. The names of the virtual centers should be specified in the variable $VCs and if the minimum number of vCPUs that you need to check is different than 2 then the value can be changed in the integer variable $numCpu.

Please download the script from here as WordPress may have messed up the PowerShell syntax below.

# =============================================================================
# name		: get_vcpu_usage_stats.ps1
# author	:NimanthaWickremasinghe
# version	: 1.0
# purpose	: Retrieves the CPU usage statistics ofVMs for a given period.	
# requirements	:PowerCLI
# =============================================================================asnp VMware.VimAutomation.Core-ErrorActionSilentlyContinue

[double]$statHistory = Read-Host &quot;Please enter the duration you want to check for statistics in number of days&quot;-ErrorActionSilentlyContinue

if($?-and ($statHistory-gt 0)){
	$date = Get-Date
	$today = Get-Date-Formatd-M-yyy
	$rptPath = &quot;C:\vm_cpu_stat_all_vms_$today.html&quot;
	$VCs = &quot;vCenter1&quot;,&quot;vCenter2&quot;,&quot;vCenter3&quot;
	$sTimeWH = &quot;08:00:00&quot;
	$fTimeWH = &quot;17:00:00&quot;
	$sTimeNWH = &quot;17:00:01&quot;
	$sTimeNWH = &quot;07:00:00&quot;
	[int]$numCpu = 3
	$rptHeader+= ''
	$rptHeader+= ''
	$rptHeader+= ''
	$rptHeader+= ''
	$rptHeader+= &quot;&lt;h2&gt;&lt;span style=&quot;color: purple; font-family: Helvetica;&quot;&gt;Virtual Machine vCPU Usage &lt;/span&gt;&lt;/h2&gt;&quot;
	$rptHeader+= &quot;&lt;h3&gt;&lt;span style=&quot;font-family: Helvetica;&quot;&gt;Period: &quot; + (Get-Date).AddDays(-$statHistory).tostring().split(&quot;,&quot;)[0] +&quot; - &quot;+ (Get-Date).tostring().split(&quot;,&quot;)[0] + &quot;&lt;/span&gt;&lt;/h3&gt;&quot;

	foreach ($vc in $VCs){
		Connect-VIServer $vc

		$vms = Get-VM | ?{$_.NumCpu -ge $numCpu}
		$rptBody += &quot;&lt;span style=&quot;color: green; font-family: Helvetica;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;&quot; + $vc.toUpper() + &quot;&lt;/span&gt;: &quot;+ $vms.count +&quot; VMs&lt;/b&gt;&lt;/span&gt;

		$rptBody += ''
		$rptBody += ''
		$rptBody += ''
		$rptBody += ''
		$rptBody += ''
		$rptBody += ''
		$rptBody += ''
		$rptBody += ''
		$rptBody += ''
		$rptBody += ''
		$rptBody += ''
		$rptBody += ''

		foreach ($vm in $vms){
			$chkDate = -$statHistory
			$cpuStat = $vm | Get-Stat -ErrorAction SilentlyContinue -Start $date.AddDays(-$statHistory) -Finish $date -Stat cpu.usage.average | Measure-Object -Property Value -Average -Maximum -Minimum
				$sTimeStampWH = $date.AddDays($chkDate).tostring().split('')[0] +' '+ $sTimeWH
				$fTimeStampWH = $date.AddDays($chkDate).tostring().split('')[0] +' '+ $fTimeWH
				$sTimeStampNWH = $date.AddDays($chkDate).tostring().split('')[0] +' '+ $sTimeNWH
				$fTimeStampNWH = $date.AddDays($chkDate+1).tostring().split('')[0] +' '+ $sTimeNWH
				$cpuStatWH += ($vm | Get-Stat -ErrorAction SilentlyContinue -Start $sTimeStampWH -Finish $fTimeStampWH -Stat cpu.usage.average | Measure-Object -Property Value -Average).Average
				$cpuStatNWH += ($vm | Get-Stat -ErrorAction SilentlyContinue -Start $sTimeStampNWH -Finish $fTimeStampNWH -Stat cpu.usage.average | Measure-Object -Property Value -Average).Average
			} while ($chkDate -le 0)
			$os = ($vm | Get-View).Summary.Guest.GuestFullName
				$os = &quot;&lt;i&gt;&quot;+ ($vm | Get-View).Summary.Guest.ToolsStatus + &quot;&lt;/i&gt;&quot;
				if($cpuStat.Average -ge 1){$avgCpu = [Math]::Round($cpuStat.Average)}else{$avgCpu = &quot;{0:N1}&quot; -f $cpuStat.Average}
				if($cpuStat.Maximum -ge 1){$maxCpu = [Math]::Round($cpuStat.Maximum)}else{$maxCpu = &quot;{0:N1}&quot; -f $cpuStat.Maximum}
				if($cpuStat.Minimum -ge 1){$minCpu = [Math]::Round($cpuStat.Minimum)}else{$minCpu = &quot;{0:N1}&quot; -f $cpuStat.Minimum}
				$avgCpu = &quot;&lt;i&gt;No data&lt;/i&gt;&quot;
				$maxCpu = &quot;&lt;i&gt;No data&lt;/i&gt;&quot;
				$minCpu = &quot;&lt;i&gt;No data&lt;/i&gt;&quot;
				$avgCpuWH = $cpuStatWH/$statHistory
				if($avgCpuWH -ge 1){
					$avgCpuWH = [Math]::Round($avgCpuWH)
					$avgCpuWH = &quot;{0:N1}&quot; -f $avgCpuWH
				$avgCpuWH = &quot;&lt;i&gt;No data&lt;/i&gt;&quot;
				$avgCpuNWH = $cpuStatNWH/$statHistory
				if($avgCpuNWH -ge 1){
					$avgCpuNWH = [Math]::Round($avgCpuNWH)
					$avgCpuNWH = &quot;{0:N1}&quot; -f $avgCpuNWH
				$avgCpuNWH = &quot;&lt;i&gt;No data&lt;/i&gt;&quot;
			$rptBodyTop += ''
		$rptBody += $rptBodyTop
		$rptBody += &quot;&lt;table border=&quot;1&quot;&gt;
&lt;th&gt;&lt;span style=&quot;color: midnightblue; font-family: Times;&quot;&gt;Name&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;color: midnightblue; font-family: Times;&quot;&gt;PowerState&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;color: midnightblue; font-family: Times;&quot;&gt;NumCPU&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;color: midnightblue; font-family: Times;&quot;&gt;AvgCPU (%)&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;color: midnightblue; font-family: Times;&quot;&gt;MaxCPU (%)&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;color: midnightblue; font-family: Times;&quot;&gt;MinCPU (%)&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;color: midnightblue; font-family: Times;&quot;&gt;AvgCPU WH(08:00-17:00) (%)&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;color: midnightblue; font-family: Times;&quot;&gt;AvgCPU NWH(17:00-07:00)(%)&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;color: midnightblue; font-family: Times;&quot;&gt;OS&lt;/span&gt;&lt;/th&gt;
&lt;td&gt;&lt;span style=&quot;font-family: Tahoma;&quot;&gt;&quot;+ $vm.Name.toLower() +&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: Tahoma;&quot;&gt;&quot;+ $vm.PowerState +&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: Tahoma;&quot;&gt;&quot;+ $vm.NumCpu +&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: Tahoma;&quot;&gt;&quot;+ $avgCpu +&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: Tahoma;&quot;&gt;&quot;+ $maxCpu +&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: Tahoma;&quot;&gt;&quot;+ $minCpu +&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: Tahoma;&quot;&gt;&quot;+ $avgCpuWH +&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: Tahoma;&quot;&gt;&quot;+ $avgCpuNWH +&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: Tahoma;&quot;&gt;&quot;+ $os +&quot;&lt;/span&gt;&lt;/td&gt;
		Disconnect-VIServer $vc -Confirm:$false
		Clear-Variable rptBodyTop
	$rptBody += &quot;&lt;i&gt; * No data &lt;/i&gt; - Statistics are unavailable for the given period.&quot;
	$rptFooter += ''

	$rpt = $rptHeader + $rptBody + $rptFooter
	$rpt | Out-File $rptPath

	$execTime = ((Get-Date)-$date)
	Write-Host `n&quot;Report generated in (h:m:s): $execTime&quot; -ForegroundColor Yellow
	Write-Host Please find the report at $rptPath -ForegroundColor Green
} else{
	Write-Host `n&quot;Invalid data. You have entered either a non-numeric value or value less than 1.&quot; -ForegroundColor Red
	Write-Host `n&quot;Press any key to continue ...`n&quot; -ForegroundColor Yellow
	$x = $host.UI.RawUI.ReadKey(&quot;NoEcho,IncludeKeyDown&quot;)


A HTML report similar to the following one will be generated at the end of the execution of the script.

vCPU Usage Statistics Report

vCPU Usage Statistics Report

How to set up remote logins via VNC for Debian, Solaris and Red Hat


, , , , ,


Debian Linux (6)

    1. Run the following commands respectively.
apt-get update
apt-get upgrade
apt-get dist-upgrade
    1. Reboot the OS.
    1. Install the GNOME desktop.
apt-get install gnome-desktop-environment
      • If “apt-get install gnome-desktop-environment” says the packages are missing then ensure “deb squeeze main contrib non-free” is added to the list file.
      • adding the link to sources.list
nano /etc/apt/sources.list

Paste “deb squeeze main contrib non-free” without quotes.

    1. Install required fonts for the VNC server GNOME session.
apt-get install xfonts-100dpi
apt-get install xfonts-100dpi-transcoded
apt-get install xfonts-75dpi
apt-get install xfonts-75dpi-transcoded
apt-get install xfonts-base
    1. Install VNC.
apt-get install vnc4server
    1. Run VNC server manually and set up a password.
    1. Making VNC server start at system start up.
      • Run the following command to create the vncserver file.
nano /etc/init.d/vncserver
    1. Copy the following script, paste, and save.
      • Replace “my-vnc-server” with the hostname and keep with quotes. (Optional)
#-----Beginning of the script-------------------------------------------

#!/bin/sh -e
# Provides:          vncserver
# Required-Start:    networking
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6


# The Username:Group that will run VNC
export USER=&quot;root&quot;

# The display that VNC will use
# Color depth (between 8 and 32)
# The Desktop geometry to use.
# The name that the VNC Desktop will have.

OPTIONS=&quot;-name ${NAME} -depth ${DEPTH} -geometry ${GEOMETRY} :${DISPLAY}&quot;

. /lib/lsb/init-functions 

case &quot;$1&quot; in 
log_action_begin_msg &quot;Starting vncserver for user '${USER}' on localhost:${DISPLAY}&quot;
su ${USER} -c &quot;/usr/bin/vncserver ${OPTIONS}&quot;

log_action_begin_msg &quot;Stopping vncserver for user '${USER}' on localhost:${DISPLAY}&quot;
su ${USER} -c &quot;/usr/bin/vncserver -kill :${DISPLAY}&quot;

$0 stop
$0 start

exit 0
#-----End of the script-------------------------------------------------
    1. Grant permissions for everyone to execute the file.
chmod +x /etc/init.d/vncserver
    1. Register the VNCServer service to run at startup.
update-rc.d vncserver defaults
    1. If VNC login shows a gray screen, then run the following command to set permissions for XInit.
chmod 755 /etc/X11/xinit/xinitrc

Solaris 10

Solaris (10)

  1. Download the latest VNC package for Solaris from
    1. Go to the download location of the file in the terminal and run the following commands.
gunzip vnc-4_1_3-sparc_solaris.pkg.gz
pkgadd –d vnc-4_1_3-sparc_solaris.pkg
    • Solaris 10 is shipped with a basic VNC service mostly configured. This is the procedure to enable it.
    1. Find the VNC service.
svcs -a | grep -i vnc

disabled 13:47:12 svc:/application/x11/xvnc-inetd:default
    1. Enable VNC service.
svcadm enable svc:/application/x11/xvnc-inetd:default
    1. Note that the VNC is broken by default, some changes will be required.
svcs svc:/application/x11/xvnc-inetd:default

maintenance 14:22:41 svc:/application/x11/xvnc-inetd:default
    1. Append VNC to the /etc/services.
echo &quot;vnc-root\t5900/tcp\t\t\t# Xvnc&quot; &gt;&gt;/etc/services
    1. Check /etc/services.
tail /etc/services

snmpd 161/udp snmp # SMA snmp daemon
vnc-root 5900/tcp # Xvnc
    1. Note, the GNU display manager is not customized yet, and needs correction.
ls -al /etc/X11/gdm/custom.conf

/etc/X11/gdm/custom.conf: No such file or directory
    1. Enable and configure GNU display manager for VNC.
cat &gt;/etc/X11/gdm/custom.conf &lt;&lt;!--
    1. Check the customization configuration file.
ls -al /etc/X11/gdm/custom.conf

-rw-r--r-- 1 root root 85 Dec 19 14:43 /etc/X11/gdm/custom.conf
    1. Disable and re-enable, and validate the VNC service.
svcadm disable svc:/application/x11/xvnc-inetd:default

disabled 14:46:29 svc:/application/x11/xvnc-inetd:default

svcadm enable svc:/application/x11/xvnc-inetd:default

svcs svc:/application/x11/xvnc-inetd:default

online 14:46:43 svc:/application/x11/xvnc-inetd:default
    1. Edit /etc/default/login and comment out the following line to permit log on as Root.
# CONSOLE=/dev/console


RHEL (Red Hat Enterprise Linux)

If the RHEL installation is licensed then this is not difficult at all. You just need to run

yum install tigervnc-server -y

at a terminal. However this gets complicated when the installation of RHEL is not licensed.

After a considerable number of disappointing hours of searching, testing, and some research I finally found a solution to this. Here I am going to use TigerVNC as the VNC server and RealVNC viewer as the client (you can use any VNC viewer you prefer).

  1. Navigate to the TigerVNC downloads which at the moment of this blog post is hosted as a SourceForge project here  and download the latest build corresponding to the bit version of your Linux installation.
  1. Extract the contents into a suitable location.
  1. Within the extracted contents a folder named bin exists and it contains all the binaries required for the sound operation of VNC server (except the one which as they say is obsolete now). Locate this folder and copy the contents of it to /bin directory in Linux. The following files need to be copied.
    • vncconfig
    • vncpasswd
    • vncserver
    • Xvnc
    1. Execute the command vncsever at a terminal.
    • This will require you to set a password for logging in remotely using VNC.
    • This will also create the necessary files required to start a xsession for a particular user when logging in using VNC.
  1. Usually after the above step you are good to go but in some cases you might end up with an error Connection timed out(1006) at the VNC viewer when you try to log in. This is because the host in which the VNC server runs is blocking the VNC communication, i.e. it’s blocking the VNC port 5900. Here you have to allow the port 5900 at the firewall as a trusted port or if security is not a big issue with the Red Hat host then you can simply disable it.