Monthly Archives: April 2015

Output to variable and console

I have a confession to make, I’m a PowerShell addict!

You don't say

I recently got a twitter account, not to tweet per se, but to get more PowerShell updates! Man! talk about real-time updates! It’s almost a day-job keeping up with the tweets!!!

So I was reading a blog by Stephen Owen aka FoxDeploy when I stumbled on a cmdlet I haven’t heard of: Tee-Object. See this is why you should read and not just scan blogs, you might learn something new… 😉

What’s the Tee-Object for? Eh, get-help Tee-Object much? Ok so Tee-Object saves command output in a file or variable and also sends it down the pipeline.

Hey I remember reading about saving results to a variable while sending output to the console on powershell.com some time back. Turns out there more than one way to get output to a variable and console. 🙂

Option 1 use parentheses
Pretty straightforward:

($results = Get-Service)

Option2 use -OutVariable
Ok I’ll admit I haven’t used this one much. When using the -OutVariable be sure to omit the “$” char or you’ll get an error. To see what’s been stored just type in the variable using, yes, $variablename, so in our case $TotalProcs and $SelectedProcs.

(Get-Process -OutVariable TotalProcs |
Select-Object ProcessName,Handles -OutVariable SelectedProcs)

$TotalProcs
$SelectedProcs

Option 3 use the Tee-Object
Last but not least the Tee-object. This will definitely help with sending data to a variable or file.

Get-Process |
Tee-Object -Variable Processes1 |
Select-Object ProcessName,Handles,Id |
Tee-Object -Variable Processes2
 
$Processes1
$Processes2

Think of the possibilities! How many times have you stored results in arrays to send to out-gridview to then later on send to export-csv? I like the third examples from get-help appending data to a cumulative file while send current results to a different file. Nice! Tee-Object reminds me of the pipe game… good times! 🙂

So there you have it, output to variable and console in three different flavors! Here’s a recap of all three:

#region Option 1 use Parentheses
($results = Get-Service)
#endregion

#region Option 2 OutVariable
(Get-Process -OutVariable TotalProcs|
Select-Object ProcessName,Handles -OutVariable SelectedProcs) 

$TotalProcs
$SelectedProcs
#endregion

#region Option 3 Tee-Object
Get-Process |
Tee-Object -Variable Processes1 |
Select-Object ProcessName,Handles,Id |
Tee-Object -Variable Processes2

$Processes1
$Processes2
#endregion

Hope it’s worth something to you,

Ttyl,

Urv

Before the PowerShell summit I had no idea of the existence of DSC. We had a hackathon evening where we got to work in groups creating (or rather make an attempt) a DSC Resource. I’ll admit I started out, but being in the room with Lee Homes, Don Jones and Richard Siddaway, who really wants to code then eh? It was awesome being able to interact with these guys!

Back at office I started gathering all information possible about DSC. The DSC Book @PowerShell.Org is a great place to start! If you’re anything like me, you’ll start wondering what makes DSC tick? How does it work under the hood? That’s where “Windows PowerShell Desired State Configuration Revealed” by Ravikanth Chaganti helps.

Ok I’ll go out on a limb here and make an assumption that you already know the basics so as not to bore you. 🙂 If you’re looking for a primer, have a look at Andrew Barnes (aka Scriptimus Prime) Desired State Configuration blog series. Great stuff!!!

Ok so the DSC Resource I’ve created is designed for creating an ADGroup. As luck would have it there’s already a xADUser DSC Resource, I’ve based cADGroup on the logic I found there, hey why reinvent the wheel? 😉

I like how the PowerShell team used a function ValidateProperties with an apply switch.
With -apply the configuration will be set, without only tested.

My first attempt was without using the DSCResourceDesigner. I knew the basics and started from there and I looked a lot into how things were done in xADUser. Turns out it’s not that difficult to apply

Import-Module xDSCResourceDesigner

#Define DSC parameters
$ResourceName = 'PSHOrg_cActiveDirectory'
$FriendlyName = 'cADGroup'
$DomainName = New-xDscResourceProperty -Name DomainName -Type String -Attribute Required
$GroupName = New-xDscResourceProperty -Name GroupName -Type String -Attribute Key
$GroupCategory = New-xDscResourceProperty -Name GroupCategory -Type String -Attribute Required
$GroupScope = New-xDscResourceProperty -Name GroupScope -Type String -Attribute Required
$ADSPath = New-xDscResourceProperty -Name ADSPath -Type String -Attribute Required
$DomainAdministratorCredential = New-xDscResourceProperty -Name DomainAdminCredential -Type PSCredential -Attribute Required
$Ensure = New-xDscResourceProperty -Name Ensure -Type String -Attribute Write -ValidateSet 'Present', 'Absent'

# Create the DSC resource
New-xDscResource `
   -Name 'PSHOrg_cADGroup' `
   -Property $DomainName,$GroupName,$GroupCategory,$GroupScope,$ADSPath,$DomainAdministratorCredential,$Ensure `
   -Path "C:\Program Files\WindowsPowerShell\Modules\$ResourceName" `
   -ClassVersion 1.0 `
   -FriendlyName $FriendlyName `
   -Force

So the DSCResource designer takes care of all the defaults. Things like creating the DSCResources folder, the default module and mof file. Definitely worth looking into if you want to get things right the first time!

DSCResourceDesigner-Results

Yeah I know, lesson learned.

Ok a quick recap:

  • Get-TargetResource returns a hash table
  • Test-TargetResource returns a boolean value
  • Set-TargetResource, that’s where the magic happens! 🙂

Ok so what do we need to know to create a ADGroup using DSC? Staying close to xADUser I’ll use *-ADGroup cmdlets.

These are the parameters required:

  • DomainName
  • GroupName
  • GroupScope
  • ADSPath
  • DomainCredentials

PSHORg_CADGroup mof file

Loving the DSCResourceDesigner!

Now to update the module

function Get-TargetResource {
	[CmdletBinding()]
	[OutputType([System.Collections.Hashtable])]
	param
	(
		[parameter(Mandatory = $true)]
		[System.String]
		$DomainName,

		[parameter(Mandatory = $true)]
		[System.String]
		$GroupName,

		[parameter(Mandatory = $true)]
		[System.String]
		$GroupCategory,

		[parameter(Mandatory = $true)]
		[System.String]
		$GroupScope,

		[parameter(Mandatory = $true)]
		[System.String]
		$ADSPath,

		[parameter(Mandatory = $true)]
		[System.Management.Automation.PSCredential]
		$DomainAdminCredential
	)
    try {
        Write-Verbose -Message "Checking if the group $GroupName in domain $DomainName is present ..."
        $group = Get-ADGroup -Identity $GroupName -Credential $DomainAdminCredential
        Write-Verbose -Message "Group $GroupName in domain $DomainName is present."
        $Ensure = 'Present'
    }
    #Group not found
    catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
        Write-Verbose -Message "Group $GroupName account in domain $DomainName is NOT present"
        $Ensure = 'Absent'
    }
    catch {
        Write-Error -Message "Unhandled exception looking up $GroupName account in domain $DomainName."
        throw $_
    }

    $returnValue = @{
        DomainName = $DomainName
        GroupName = $GroupName
        GroupCategory = $GroupCategory
        GroupScope =  $GroupScope
        ADSPath = $ADSPath
        Ensure = $Ensure
    }
    $returnValue
}

function Set-TargetResource {
	[CmdletBinding()]
	param
	(
		[parameter(Mandatory = $true)]
		[System.String]
		$DomainName,

		[parameter(Mandatory = $true)]
		[System.String]
		$GroupName,

		[parameter(Mandatory = $true)]
		[System.String]
		$GroupCategory,

		[parameter(Mandatory = $true)]
		[System.String]
		$GroupScope,

		[parameter(Mandatory = $true)]
		[System.String]
		$ADSPath,

		[parameter(Mandatory = $true)]
		[System.Management.Automation.PSCredential]
		$DomainAdminCredential,

		[ValidateSet('Present','Absent')]
		[System.String]
		$Ensure
	)

    try {
        ValidateProperties @PSBoundParameters -Apply
    }
    catch {
        Write-Error -Message "Error setting ADGroup $GroupName in domain $DomainName. $_"
        throw $_
    }

}

function Test-TargetResource
{
	[CmdletBinding()]
	[OutputType([System.Boolean])]
	param
	(
		[parameter(Mandatory = $true)]
		[System.String]
		$DomainName,

		[parameter(Mandatory = $true)]
		[System.String]
		$GroupName,

		[parameter(Mandatory = $true)]
		[System.String]
		$GroupCategory,

		[parameter(Mandatory = $true)]
		[System.String]
		$GroupScope,

		[parameter(Mandatory = $true)]
		[System.String]
		$ADSPath,

		[parameter(Mandatory = $true)]
		[System.Management.Automation.PSCredential]
		$DomainAdminCredential,

		[ValidateSet('Present','Absent')]
		[System.String]
		$Ensure
	)

    try {
        $parameters = $PSBoundParameters.Remove('Debug');
        ValidateProperties @PSBoundParameters
    }
    catch {
        Write-Error -Message "Error testing AD User $UserName in domain $DomainName. $_"
        throw $_
    }
}

function ValidateProperties {
    param (
        [Parameter(Mandatory)]
        [string]$DomainName,

        [Parameter(Mandatory)]
        [string]$GroupName,

        [Parameter(Mandatory)]
        [string]$GroupCategory,

        [Parameter(Mandatory)]
        [string]$GroupScope,

        [Parameter(Mandatory)]
        [string]$ADSPath,

        [Parameter(Mandatory)]
        [PSCredential]$DomainAdminCredential,

        [ValidateSet('Present','Absent')]
        [string]$Ensure,          

        [Switch]$Apply
    )

    # Check if group exists
    try {
        Write-Verbose -Message "Checking if the group $GroupName in domain $DomainName is present ..."
        $group = Get-ADGroup -Identity $GroupName -Credential $DomainAdminCredential

        if ($group) {
            Write-Verbose -Message "Group $GroupName in domain $DomainName is present."
            if( $Apply ) {
                if ($Ensure -ne 'Present'){
                    Remove-ADGroup -Identity $GroupName -Credential $DomainAdminCredential -Confirm:$false
                    Write-Verbose -Message "Group $GroupName account in domain $DomainName has been deleted"
                }
            }
            Else{
                return ($Ensure -eq 'Present')
            }
        }
    }
    #Group not found
    catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
        Write-Verbose -Message "Group $GroupName account in domain $DomainName is NOT present"
        if($Apply) {
            if( $Ensure -ne 'Absent' ) {
                $params = @{
                    Name = $GroupName
                    SamAccountName = $GroupName
                    GroupCategory = $GroupCategory
                    GroupScope = $GroupScope
                    Path = $ADSPath
                    Credential = $DomainAdminCredential
                }
                New-ADGRoup @params
                Write-Verbose -Message "Group $GroupName account in domain $DomainName has been created"
            }
        }
        else {
            return ( $Ensure -eq 'Absent' )
        }
    }
}

Export-ModuleMember -Function *-TargetResource

At the heart of it is the ValidateProperties function. Did I mention that I like the way the PowerShell team solved this? 🙂 The logic is as follows:

See if the group exists. If apply switch has been provided and Ensure is ‘Absent’ then remove the group, else return (Ensure -eq Present). If the group doesn’t exist (using catch ADIdentityNotFoundException) see if apply switch has been provided. if Ensure isn’t equal to Absent create the group, else return (Ensure -eq Absent)

I’ll admit, I had to revise it quite a few times. The Test-TargetResource is the trickiest part in my opinion.

Here’s the code code create the mof files, Ofcourse this works in my environment:

$ConfigData = @{
    AllNodes = @(
        @{
            NodeName                    = '*'
            PSDscAllowPlainTextPassword = $True
        }
        @{
            NodeName     = 'dc-dsc-01'
        }
    )
}
configuration CreateDomainGroup{
  param(
    [string[]]$ComputerName,
    [string]$UserDomain,
    [pscredential]$Credential
  )

  Import-DscResource -ModuleName 'PSHORG_cActiveDirectory'

  node $ComputerName{

    cADGroup ComputerAdminGroup {
        Ensure = 'Present'
        GroupName = "DEL-$ComputerName-ADM"
        GroupScope = 'Global'
        GroupCategory = 'Security'
        ADSPath = 'OU=Delegation,OU=Resources,DC=pshirwin,DC=local'
        DomainName = $UserDomain
        DomainAdminCredential = $Credential
    }
  }
}

$Cred = Get-Credential

CreateDomainGroup -Credential $Cred -ConfigurationData $ConfigData -OutputPath "$pwd\modules\CreateDomainGroup" -ComputerName 'DC-DSC-01' -UserDomain $env:USERDOMAIN
Start-DscConfiguration -Path .\modules\CreateDomainGroup -Wait -Verbose -ComputerName DC-DSC-01 -Force

I know PSDSCAllowPlainTextPasswords are not done! Baby steps… 🙂

Now for something different
So that was my first attempt at creating a DSC Resource. I was quite proud of myself! But then I started thinking (Oh boy here we go…) Deleting and Creating Security Groups means that even though the object looks the same, the SID (Security Identifier) will be different. If for some reason after an extended period of time the group has been deleted (using a script or adac or dsa, take your pick) It will be recreated, only it will have a different SID.  Any resource that’s using that group (Think NTFS security rights) will have a rogue ACE entry. So in this case, configuring the LocalConfigurationManager to ‘ApplyOnly’ might be a wise choice. And as I’m writing this…  if you want more in-depth knowledge have a look at Ravikanth Chaganti book!

Infrastructure, make way for DSC

The future versions of DSC will be based on DSC Classes, that’s how quick DSC is evolving. DSC Classes does require WMF 5.0 at the moment. if you’re interested in PowerShell & Classes have a look at Doug Finke’s blog on the subject And if you really wanna get started with DSC Classes, Ben Gelens has just the thing for you, a DSC Class template!!! Gotta love the PowerShell community!!!

This just in: Microsoft Publishes DSC Resource Kit in GitHub.

I guess GitHub will be where we can get hands on DSC Resources in the future!

DSC is rapidly taking over the Infrastructure scene, so hop on while you still can! The best way to learn about DSC is by using it! I know this doesn’t cover all the ins and outs, but I hope it has conviced you that you should be looking into DSC…

Ttyl,

Urv

You down with DSC? Yeah you know me!!!

‘Sup, PSHomies? Oh it’s not a thing yet but it will be… 😉

Back on the DSC wagon. My takeaway from the 2014 European PowerShell Summit was that DSC is where it’s at! Then at TechEd 2014@Barcelona, I saw Mark Russinovich openly embrace Docker, I knew something was up.

Yesterday (08-04-2015) Jeffrey Snover announced the nano server!!! What??? You’re not excited??? Here’s why you should be.

Here’s an excerpt from the announcement:

All management is performed remotely via WMI and PowerShell. We are also adding Windows Server Roles and Features using Features on Demand and DISM. We are improving remote manageability via PowerShell with Desired State Configuration as well as remote file transfer, remote script authoring and remote debugging. We are working on a set of new Web-based management tools to replace local inbox management tools.

You had me at PowerShell… As for DSC, well that’s just gravy! When Jeffrey Snover tells you to invest in something, don’t second guess, just do it!!!

So that’s why we needed to get on the DSC bandwagon! If you’re a Infrastructure guy, you can’t afford not to invest time and effort in learning PowerShell & DSC!

Here’s the official announcement: Microsoft Announces Nano Server for Modern Apps and Cloud

Need a jumpstart learning DSC? Hop on over to MVA: Getting Started with PowerShell Desired State Configuration (DSC) and learn from the mastermind himself!!!

There’s no shortage of DSC Resources. Have a look at the latest wave: DSC wave 10. When I first got introduced to DSC, wave 7 was just out. That’s how fast DSC is evolving…

It’s a new era for IT…

Ttyl,

Urv

What does being an iron addict and scripting have in common?

I love scripting! I’m also an iron addict, no doubt! If I could do both at the same time I would… Come to think of it, some of my best ideas came to me under the bar… 😉

Scripting much like lifting gets better with practice (and time, lot’s of it!), you gotta pay your dues! There’s no shortcut or quickfix. Here’s what lifting has taught me at becoming a better scripter.

Learn the basics, using good form
You would think that’s obvious. Learn how to do the basic compound lifts using correct form. Once you make progress, you’re allowed to experiment. At the heart of it, know your basics. With scripting you should understand the basics of your scripting language. Practice until it becomes second nature to you. This never ends.

Understand that getting strong(er) takes time
When I first started lifting I made progress… fast! At the rate I was going I thought I’d be benching 200 kg in no time… Slow your role Urv it doesn’t work like that… I remember hitting my first plateau, benching 90 kgs (oh way back…) , talk about frustration! The key was to keep at it, it will come… When I started out learning PowerShell there were three cmdlets I lived by: get-help, get-command and get-member. PowerShell is all about objects, something I appreciate now, but back then didn’t quite grasp. I made it a point to learn the proper way of using custom objects and now I wouldn’t want it any other way! Keep at it, it will come… The only way to burst through plateaus is being persistent.

Know that tools are just a means to an end.
Ever seen someone at the gym with a lifting belt on, only to do arm curls with 12 pounds dumbbells? Come on, you should be able to handle the weight without depending too much on accessories. How about someone doing extensive leg stretching only to start curling? SMH… If a tool will help you get to the next level then by all means, use it, but at least have a good foundation to build on. Most guys get so dependant on their belt, they can’t do without it anymore… Can you still produce quality scripts without additional tooling? If your answer is yes, you’ll be fine…

Learn from the best
“Mediocrity is contagious – so is excellence. So choose your surroundings wisely…”

When I started lifting I had the good fortune of being at a gym with some strong guys… Ever saw someone bench 250 kgs RAW? Now that’s impressive!!! I got a lot of good tips from these guys. Remember I talk about good form? Well to this day the suicide grip is what feels natural to me. I know it isn’t considered correct but it’s what I was taught. It also helped me burst through my first plateau! The PowerShell community isn’t short of experts! Follow them, learn from them. Don’t forget, these are the heavyweights, so approach them with respect! If you’re lucky to interact with an expert, please, please refrain from giving them advice on how to become better! There’s a reason why they are the experts! Don’t be that beginner (read lightweight with no visible gains) that tells a lifter (think Ronnie Coleman huge) he’s curling all wrong, or what he needs to do to get huge! Granted we can always learn from each other, just don’t be a wise guy about it…

Be prepared to overcome obstacles
Over the years I’ve fractured bones, torn ligaments, name a body part and I’ve probably injured it. I injured my right shoulder some time back. When recovering, benching 40 kg was almost impossible. Here I was, back at square one. I did my warm-ups with 100 kg, now I couldn’t even bench 40 kg. That was humbling to say the least! When I started with PowerShell, I was quite versed in VBS. It took some time for me to warm up to the idea of PowerShell being superior to VBS, now I’m a huge advocate of PowerShell! These days I can’t imagine scripting in any other language. Be humble enough to start all over again.

Never stop learning
I’ve been an iron addict well over 20 years. I’ve reached the age that recovery takes time. I can’t compete with the young ones. Granted I can still hang, but I need to be smart about it! I know my limits, these days I’m working smarter! I intend to lift and enjoy lifting as long as possible. If that means taking it down a notch, then so be it. Lifting much like scripting is all about becoming a better version of yourself. Appreciate what you’ve achieved,accomplished and what you will accomplish. Don’t beat yourself up about what you can’t do, focus on what you can. Enjoy your glory days, and pass your knowledge on to the next generation. Never stop learning… your brain will thank you…

Well thanks for letting an iron addict reminisce and hopefully you picked up an idea or two… Some day you’ll be that guy… And the circle is complete…

Ttyl,

Urv