Part I.5: Creating a user for our Testlab with DSC

Posted on Updated on

IntroToDsc

Being that I am a creature of pure distilled vanity, I often reread my articles and blog posts after the fact to make sure that I wrote well and don’t have any typos. Well, when I reread my last post, I realized that I forgot to add the step of making a User Account with PowerShell DSC! Whoops!

As it turns out, actually creating a user with DSC had me ready to pull my hair off in frustration, so to save you intrepid Googlers from this pain, I’ve outlined what you SHOULDN’T do, and also have a working easy to understand demo in the bottom.

Add a User Resource to our DSC Config

So, building on our DSC Config from last week; when we want to add a new DSC Resource, the first start is to run Get-DSCResource and look at what Properties we can (and need to) focus on.

Get-DscResource User | select -ExpandProperty Properties

newUser_01

Based on what we see above, we should be good to add the following under xComputer


 User LocalAdmin {
            UserName = $UserName 
            DependsOn = '[xComputer]NewNameAndWorkGroup'
            Description = 'Our new local admin' 
            Disabled = $false
            Ensure = 'Present'
            FullName = 'Stephen FoxDeploy' 
            Password = "$Password"
            PasswordChangeRequired = $false 
            PasswordNeverExpires = $true 
        
        }

You can see that we added a few variables there, so let’s go add them all to our Parameter block.

Change our params block in this script to the following

param
    ( 
        [string[]]$NodeName ='localhost', 
        [Parameter(Mandatory)][string]$MachineName, 
        [Parameter(Mandatory)][string]$WorkGroupName,
        [Parameter()][string]$UserName,
        [Parameter()][string]$Password
    ) 

Now let’s invoke it…

TestLab -MachineName DSCDC01 -WorkGroupName TESTLAB -Password "myRootPw" -UserName "Stephen FoxDeploy"

ERROR :(

Write-NodeMOFFile : Invalid MOF definition for node 'localhost': Exception calling "ValidateInstanceText" with "1" argument(s): "Convert property 'Password' value from type 
'STRING' to type 'INSTANCE' failed
 At line:37, char:2
 Buffer:
onName = "TestLab";
};^

Fix: Convert property value from type string to type instance failed

What?!? Maybe my brain just doesn’t work so good, but I had a really hard time understanding what this message meant: Convert Property Value from type String to type Instance. So I took a peek at TechNet.

Checking TechNet, I see this example of how to use the DSC User Resource(I’ve actually bolded the part that was causing me grief, let’s see if you can figure it out quicker than I could!):

User UserExample
{
Ensure = “Present” # To ensure the user account does not exist, set Ensure to “Absent”
UserName = “SomeName”
Password = $passwordCred # This needs to be a credential object
DependsOn = “[Group]GroupExample” # Configures GroupExample first
}

Let’s look at the error message again…

“Convert property ‘Password’ value from type ‘STRING’ to type ‘INSTANCE’ failed

And now side-by-side…

Password = $passwordCred # This needs to be a credential object
Can’t convert property ‘Password’ value from type ‘STRING’ to type ‘INSTANCE’ failed

Hmm…I converting from a string failed, and TechNet says it needs to be a Credential object instead…! Wait! PowerShell is telling me I can’t give the PW as a string, it actually has to be a credential object! Not sure why it took me so long to understand this. Actually, if we take a look at the output from Get-DSCResource, it even says right there what type to provide the data in.

newUser_015

So, let’s replace our -PassWord ‘RootPW’ with a parenthesis with Get-Credential and see what happens…

TestLab -MachineName DSCDC01 -WorkGroupName TESTLAB -Password (Get-Credential -UserName 'FoxDeploy' -Message 'Enter New Password') -UserName "FoxDeploy"

Fix: Storing passwords as plain text is not recommended

Running the cmd above gives us…some more blood in the water, but this is great because we’ve solved the first problem!

ConvertTo-MOFInstance : System.InvalidOperationException error processing property 'Password' OF TYPE 'User': Converting and storing encrypted passwords as plain text is not 
recommended. For more information on securing credentials in MOF file, please refer to MSDN blog: http://go.microsoft.com/fwlink/?LinkId=393729

Hey, at least we’re getting somewhere! This is probably one of the most informative error messages I’ve ever had in PowerShell! It’s saying hey, you can’t do this, here is a link with more info. I like it! Much better than before.

I did some googling and found this article on the topic, it turns out we need to specify a -ConfigurationData parameter, which will allow us to tell PS to, just this once, ignore our bad behavior password.

Let’s throw this bad boy on there…


$configData = @{
                AllNodes = @(
                              @{
                                 NodeName = "localhost";
                                 PSDscAllowPlainTextPassword = $true
                                    }
                    )
               }

Now, to run it, one last time!

newUser_02

BLAM! Let’s apply it!

RESULTS

[[xComputer]NewNameAndWorkgroup] Checking if computer name is DSCDC01
[[xComputer]NewNameAndWorkgroup] Checking if workgroup name is TESTLAB
[[xComputer]NewNameAndWorkgroup]  in 0.2420 seconds.
[[xComputer]NewNameAndWorkgroup]
[[User]LocalAdmin] A user with the name FoxDeploy does not exist.
[[User]LocalAdmin]  in 2.4380 seconds.
[[User]LocalAdmin]
[[User]LocalAdmin] Configuration of user FoxDeploy started.
[[User]LocalAdmin] Performing the operation "Add" on target "User: FoxDeploy".
[[User]LocalAdmin] User FoxDeploy created successfully.
[[User]LocalAdmin] Configuration of user FoxDeploy completed successfully.
[[User]LocalAdmin]  in 2.5090 seconds.

Now, let’s look to see if our User was created

newUser_03

Ok, that’s damned sexy

Completed DSC File

This DSC config will rename our PC, join it to a workgroup, and then add a new local user to the machine. When you run this, you’ll be prompted to provide the PW for the new local user. Make sure to change the -Username value to a name you’d like to use.

configuration TestLab 
{ 
    param
    ( 
        [string[]]$NodeName ='localhost', 
        [Parameter(Mandatory)][string]$MachineName, 
        [Parameter(Mandatory)][string]$WorkGroupName,
        [Parameter()][string]$UserName,
        [Parameter()]$Password
    ) 
       
    #Import the required DSC Resources  
    Import-DscResource -Module xComputerManagement 
  
    Node $NodeName
    { 
        xComputer NewNameAndWorkgroup 
        { 
            Name          = $MachineName
            WorkGroupName = $WorkGroupName
        }
        
        
        User LocalAdmin {
            UserName = $UserName 
            Description = 'Our new local admin' 
            Ensure = 'Present'
            FullName = 'Stephen FoxDeploy' 
            Password = $Password
            PasswordChangeRequired = $false 
            PasswordNeverExpires = $true 
            DependsOn = '[xComputer]NewNameAndWorkGroup'
        }
        
    } 
}

$configData = 'a'

$configData = @{
                AllNodes = @(
                              @{
                                 NodeName = "localhost";
                                 PSDscAllowPlainTextPassword = $true
                                    }
                    )
               }

#See whats needs to be configured
# Get-DscResource User | select -ExpandProperty Properties | select -expand name

TestLab -MachineName DSCDC01 -WorkGroupName TESTLAB -Password (Get-Credential -UserName 'FoxDeploy' -Message 'Enter New Password') -UserName "FoxDeploy" -ConfigurationData $configData

Start-DscConfiguration -ComputerName localhost -Wait -Force -Verbose -path .\TestLab

Wrapping Up

So, it seems that most things in DSC look deceptively easy when you see the finished result, but working up to that is quite difficult. Instead this was more of a deep dive into using the User Resource with DSC. Join us again next week when we add our user to the Administators built-in Group, then make our machine into a Domain Controller.

System Center Orchestrator: Solving Return Data is blank

Posted on Updated on

System Center Orchestrator–formerly Opalis Orchestrator– and now lovingly called SCORCH by its fans is a powerful automation tool, but there are a lot of gotcha’s that makes it difficult to begin rolling out in the environment.

For instance, it’s desirable to Return Data back from a Runbook either to a parent runbook, or to Service Manager or another system to act on the results. As an example, imagine a runbook that can fork in many places and then return an exit code that we then send off to a parent runbook to register as an Operations Manager event, or to send in an e-mail. There’s lot of options. Well, even with this common scenario, people still run into a brick wall when they experience the following

Symptom

When a runbook has valid data pushed to the SCORCH Databus, adding a Return Data step results in a blank window like the following.

scorc01

Cause

Oddly enough, the settings for which data is returned from the runbook aren’t configured from anywhere within the runbook, but rather within the runbook properties itself.

Resolution

This one is easy to fix, go up to the top of the Orchestrator window and right-click on the Runbook name itself, and choose properties.

scorc02

Next we browse down to to Returned Data and prepare to roll our eyes.

Seriously...?
Seriously…?

This is actually the place where you enable values for the Return Data activity. I know, I think it’s absolutly horrific from a usability and discoverability stand-point. One of the many things that make Orchestrator a challenge to use.

If we go back into the runbook itself now, we can Check the runbook back in and out and then our Return Data field will update.

scorc03
Enjoy!

Part I : Building an AD Domain Testlab with DSC

Posted on Updated on

IntroToDsc

I often rebuild my testlab from the ground up, and have gotten to the point that setting up my Domain, DHCP, DNS and the like all is a very quick and easy task., But it wasn’t always this way, in fact, I used to spend hours trying just to get DHCP and Domain Controller working.

This is post one of a projected three part series in which we’ll use the magical power of infrastructure as code and embrace the DevOps lifestyle using PowerShell Desired State Configuration. In post one, we’ll start easily and just change the name of our machine and the workgroup, then configure a local admin account in the same doc.

In part II – we’ll configure some Windows Roles, and make this system into a Domain Controller.
In part III – we’ll pull out all of the stops and ensure that our DSC configuration handles DHCP and DNS as well, giving us a one-click DSC Testlab.

Read the rest of this entry »

Orchestrator and PowerShell – Solved: the execution of scripts is disabled on this system

Posted on

System Center Orchestrator (formerly Opalis Orchestrator) is a wonderful tool for automating heavy lifting in your environment, like managing Exchange server Windows Updates, while respecting DAGs, or other situations with repetitive tasks that can take a lot of manual labor, so long as the logic for responding to particular circumstances are well understood.

That being said, Orchestrator can be one of the most daunting and gotcha ridden programs for any System Center Devop and Wintel admin to wrap his head around.

Take this case, I have a straightforward task that involves running a PowerShell script, but every time I run a script, I run into this…

Problem

Read the rest of this entry »

Solved: Getting a user’s Distribution Group Memberships

Posted on Updated on

It’s surprisingly hard to get back a listing of all of a particular user’s Exchange Distribution Group Memberships. The strange thing about this is that you can very easily get a list of all of a user’s AD Security Groups using

Get-ADPrincipalGroupMembership

. If this works for your purposes, great, but if what you really need is a report of all of a user’s / mailbox or resource mailbox Distribution Group membership, I’ve come up with the following.

get-distributiongroup | ForEach-Object {
$groupName = $_
Get-DistributionGroupMember -Identity $groupname.Name | ForEach-Object{
    [pscustomObject]@{GroupName=$groupname;groupMember=$_.Name}
    }
} | Group-Object -Property GroupMember |
    Select-object Name, @{Name=‘Groups‘;Expression={$_.Group.GroupName}}

Whoa! What’s happening there?

Here’s the walkthrough of why this works:

  • We’re getting a big list of all of the distribution groups
  • for each, resolving the full membership of each group
  • For every entity we discover who is a member of this group, we create a custom object of “username,groupname”
  • Once this finishes, we send this to the Group-Object command to let it pick out every unique user
  • Then gather all of their memberships using a calculated property
  • We then can send this on to a CSV file, to get an output like this.
#TYPE Selected.Microsoft.PowerShell.Commands.GroupInfo
"Name","Groups"
"Stephen","Group_1 Group_2 OtherFolks"
"Lenna.Paprocki","Group_2 OtherFolks"
"James.Butt","Group_2 OtherFolks"
"Josephine.Darakjy","OtherFolks"

In my opinion, XML would be the best way to display this info, rather than a CSV. Additionally, it would be very cool to have a lighter weight cmdlet to return just the Distribution Group membership of one user. If I come up with this approach, I’ll be sure to update this.

Hope you enjoy!