Lately I have been using Windows PowerShell Desired State Configuration(aka DSC) more and more to do specific tasks. In this blog post I wanted to show you how you can use DSC to add accounts to the local administrators group on a target server. These accounts can be domain/local users, domain/local groups, as well as computer accounts. I’m sure there are a few different ways that this task can be accomplished but I will share with you how I am doing it. Hopefully you will find this useful.
So What is DSC?
DSC is a feature in Windows PowerShell that enables the deployment and management of configuration data using resources that declaratively specify how the software environment on a server should look. In layman’s terms, I want my server configuration to have a desired state. Oh, and if someone happens to change it, put it back to the way I specified it. This can be done via a ‘push’ or ‘pull’ method. We will be using the ‘push’ method for now. We will save the ‘pull’ method for a future post.
Make it So!
My goal was to come up with an easier way to add domain specific accounts (users, groups, or computers) to the local admins group on one or more servers. We will create a script using the DSC Group resource to do this for us.
Scenario: My environment consists of a Domain Controller, 2 SCOM Servers, a 2-node SQL Cluster, VMM, and a Jump server that acts as my management server. All servers are running 2012 R2 and domain joined. I will be running the script from the Jump server targeting the two SQL nodes. I have previously created two domain service accounts and a domain security group. I will add these accounts along with the VMM computer account to the local admins group on each SQL node.
Here are the accounts in AD that I will be adding.
Here are the local admins groups of each SQL node showing those accounts do not exist.
After running the script, here are the results. Note, it only took 12 seconds. How nice is that. The nice thing is I could run this again and it would see that those accounts already exist and just move on without error.
Here you can see the accounts have been added to the local admins group on each SQL node. I added two different service accounts, a security group, and a computer account, all domain based. This can be done with local accounts as well.
So how do we do this and show us the script! Ok, here it is.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
$ConfigurationData = @{ AllNodes = @( @{ NodeName = '*' PSDscAllowPlainTextPassword = $true } @{ NodeName = 'INFSQL1N01' } @{ NodeName = 'INFSQL1N02' } ) } Configuration AddToLocalAdminsGroupSQL { Node $AllNodes.nodename { Group Administrators { GroupName = 'Administrators' Ensure = 'Present' MembersToInclude = 'Domain\!snapdrive','Domain\!smsql','Domain\SQL Admins','Domain\SCVMM01$' Credential = $cred } } } AddToLocalAdminsGroupSQL -ConfigurationData $ConfigurationData -OutputPath C:\DSCconfigs\AddToLocalAdminsGroupSQL Start-DscConfiguration -Path C:\DSCconfigs\AddToLocalAdminsGroupSQL -Force -Wait -Verbose -Cred (Get-Credential) |
Let’s break this down so we can understand what the script is doing.
The first thing we need to do is to create the configuration data which is an array of hash tables that is used to specify the environment part of the configuration. The AllNodes key, a hash table in itself, contains the elements NodeName that are hash tables containing the configuration data to the nodes. You can add or remove additional NodeName elements depending on how many servers you wish to target.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ConfigurationData = @{ AllNodes = @( @{ NodeName = '*' PSDscAllowPlainTextPassword = $true } @{ NodeName = 'INFSQL1N01' } @{ NodeName = 'INFSQL1N02' } ) } |
The first NodeName element listed includes the ‘*’ which specifies the configuration on all nodes. The ‘PSDscAllowPlainTextPassword’ key is set to true verifying that you are aware that you are storing the password in plain text inside the .MOF file.
So why does this happen? The Get-Credential cmdlet produces a secure string, right? Yes; however, when the configuration runs it decrypts the password and stores it as plain text as seen in the MOF file above. Without this key you would get a nice error message stating “Converting and storing an encrypted password as plain text is allowed only if PSDscAllowPlainTextPassword is set to true”. I should note that the preferred method would be to encrypt the password with a certificate.
The next section of the script is where we declare the Configuration. I called mine ‘AddToLocalAdminsGroupSQL’. Here we are using the Group <Resource> and we specify the properties. We are targeting the GroupName as ‘Administrators’, ensuring that the group is present, adding the members we wish to include, and calling the stored credential.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Configuration AddToLocalAdminsGroupSQL { Node $AllNodes.nodename { Group Administrators { GroupName = 'Administrators' Ensure = 'Present' MembersToInclude = 'Domain\!snapdrive', 'Domain\!smsql', 'Domain\SQL Admins', 'Domain\SCVMM01$' Credential = $cred } } } |
Now that the configuration has been declared, we need to create the MOF file by calling the function. Here we need to include the ConfigurationData parameter to pass the configuration data to the configuration. In addition, I have specified the path I wish to store my MOF files. The file will have the name of the configuration.
1 |
AddToLocalAdminsGroupSQL -ConfigurationData $ConfigurationData -OutputPath C:\DSCconfigs\AddToLocalAdminsGroupSQL |
Finally we can apply the configuration using Start-DscConfiguration.
1 |
Start-DscConfiguration -Path C:\DSCconfigs\AddToLocalAdminsGroupSQL -Force -Wait -Verbose -Cred (Get-Credential) |
This is great, but what if I wanted to avoid the credential popup? You can use ConvertT0-SecureString and create a credential object and assign it to the variable $cred as shown below. Just add the code block prior to the configuration data and remove the credential parameter from the Start-DscConfiguration line. Keep in mind this will display your password in your script.
1 2 3 4 |
$UserName = 'Your_Domain\Administrator' $AdministratorPassword = '123@XYZ' $securedstring = ConvertTo-SecureString -String $AdministratorPassword -AsPlainText -Force $cred = New-Object System.Management.Automation.PSCredential ($UserName, $securedstring) |
Wrap Up
So what do you think of DSC? Although DSC is in its early stages, it is becoming more popular. There are a handful of resources that ship in product and there are many more that are being developed by the PowerShell team and the community. If you see an ‘x’ as the prefix on the resource, this means experimental. If you see a ‘c’, this means community. You need to be running PowerShell v4 which ships in Windows 8.1 and Windows Server 2012 R2.
Check out these links for additional info:
https://gallery.technet.microsoft.com/scriptcenter/DSC-Resource-Kit-All-c449312d