Categories

Monthly Archives: March 2014

DSC resource kit wave 3

Desired State Configuration (DSC) is the new server configuration and compliance mechanism that ships with PowerShell 4.0 and Windows Server 2012 R2.

Resources are the way you perform configuration. Now you have more options with the release of wave 3 of the DSC resource kit.

Details from http://blogs.msdn.com/b/powershell/archive/2014/03/28/dsc-resource-kit-wave-3.aspx

Last few days to register

Reaching the end of March there’s not much time left to register for the PowerShell Summit NA 2014 -

http://powershell.org/wp/community-events/summit/powershell-summit-north-america/summit-registration/

 

as its coming up fast.

See you there.

Discovering namespaces

Next point on the journey of discovery through CIM is finding the namespaces installed on a machine.  I showed how to do this using Get-WmiObject in PowerShell and WMI but this time round decided to come up to date and use Get-CimInstance

function get-cimnamespace {
param (
[string]$namespace = 'root/cimv2'
)

Get-CimInstance -ClassName __NameSpace -Namespace $namespace |
select @{N='Name'; E={"$($_.CimSystemProperties.NameSpace)/$($_.Name)"}}

}

This simply searches for instances of the __NameSpace class in a given starting name space. Default is root/cimv2.  By using select-object to create a calculated field I can append the name of the namespace to the current namespace to get the full path.

Next time I’ll show how to use recursion to dig through the namespaces we’re discovering to find any namespaces they contain.

Improving CIM/WMI method discovery

I recently showed how to create a function that could be used to simplify the use of Get-CimClass.

In this version I’ve added some features:

- parameter validation

- namespace

- try-catch round getting the class information.

This turns the code into:

function Get-CimMethod {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[Alias("Class")]
[ValidateNotNullOrEmpty()]
[string]$classname,

[ValidateNotNullOrEmpty()]
[string]$namespace = 'root/cimv2',

[Alias("Name")]
[ValidateNotNullOrEmpty()]
[string]$methodname

)

try
{
$class = Get-CimClass -Namespace $namespace -ClassName $classname -ErrorAction Stop
}
catch
{
  Throw "Class: $classname NOT FOUND"
}

if ($methodname)
{
  $class.CimClassMethods[$methodname].Parameters
}
else
{
  $class.CimClassMethods
}

}

The module and function can be used like this:

Import-Module CimInvestigation -Force
Get-Command -Module CimInvestigation
Get-CimMethod -classname Win32_Process
Get-CimMethod -classname Win32_Process -methodname Create
Get-CimMethod -classname Win32_Process -methodname Create -namespace root/cimv2

Deal of the Day–26 March 2014

Tomorrow – 26 March – several PowerShell books will feature in Manning’s Deal of the Day:

PowerShell in Depth 2E

PowerShell and WMI

PowerShell Deep Dives

 

All highly recommended and full of PowerShell goodness

A little bit of community

One thing I really like about the PowerShell community is the number of people who share information and the way that allows us to incrementally increase our knowledge and skills. This can lead to the situation where you can take ideas from two very separate people, from two different times and put them together to get something different.

I was reading my friend Jason’s blog post - http://powershell.org/wp/2014/03/23/new-tools-in-my-toolbox/ and when I got to the bit about using PowerShell to start Internet Explorer:

PS> Start iexplore www.bing.com

Start is an alias for Start-Process and I remembered something Ed Wilson (The Scripting Guy) once told me about using single letter aliases for his common activities.

Many people are aware of aliases within PowerShell and how they can cut down typing when you are working interactively. What isn’t so widely realised is that you can define aliases for non-PowerShell commands.

So in the interests of absolute brevity let define a new alias S that provides an even shorter way to use Start-Process:

New-Alias -Name S -Value Start-Process

You can test it by trying

s notepad

You should get an instance of notepad started.  This makes starting Internet Explorer as simple as:

s iexplore www.bing.com

Alternatively, you can cut out the use of Start-Process. Define an alias for Internet Explorer

New-Alias -Name I -Value 'C:\Program Files (x86)\Internet Explorer\IEXPLORE.EXE'

Try it using

i

And a new instance of IE will start

This means that you can start IE in a particular web site very quickly for example:

i www.bing.com
i amazon.co.uk

Single letter aliases are a great way to minimise your typing. If you want them to be always available then add them to your profile

Discovering CIM/WMI methods and parameters

As you’ve probably gathered I spend a lot of time working with, and investigating, CIM (WMI) classes. CIM and WMI will be treated as synonymous for these articles.

If you want to discover the methods available on a CIM class you can do this:

$class = Get-CimClass -ClassName Win32_Process
$class.CimClassMethods

If you want to drill down into an individual method you then have to do this:

$class.CimClassMethods["Create"].Parameters

We end up with a two stage process. Firstly discover the available a methods and then discover the parameters on the method.

 

In a busy session this can turn into a lot of typing. You can short-circuit some that if you using the Get-CimMethodParameter from the CIM Utilities modules that can be downloaded from http://gallery.technet.microsoft.com/scriptcenter/CimUtilities-56d9dd99

To my mind it only supplies an answer to the last part of the problem. There is a hidden method – Get-CimMethod – that does the first step but as its not published it doesn’t help us.

I decided that its time to re-write the module to work the way I want.  This provides an opportunity to go over the functionality of Get-CimClass, Advanced functions and modules.

To define my problem:

I want a cmdlet that:

  • provides a list of methods on a WMI class
  • provides the parameters of a specific method
  • the standard output of Get-CimClass is acceptable
  • work with any namespace
  • work with remote machines
  • not concerned about pipeline input at this stage (may add later)
  • not concerned about outputting parameters as a hash table ( though may add later)

I’ll start with a simple function to perform the first two requirements.

function Get-CimMethod {
[CmdletBinding()]
param (
[string]$classname,

[string]$methodname

)

if ($methodname)
{
  $class = Get-CimClass -ClassName $classname
  $class.CimClassMethods[$methodname].Parameters
}
else
{
  Get-CimClass -ClassName $classname | select -ExpandProperty CimClassMethods
}

}

I decided to save this as a psm1 file (module file) and called the module CimInvestigation.

In PowerShell 3 & 4 the module autoloads so I can do this:

Get-CimMethod -classname Win32_NetworkAdapter

Get-CimMethod -classname Win32_NetworkAdapter -methodname setpowerstate

Next time I’ll turn this into more of an advanced function with some validation and error checking

DSC, Windows 2012 R2 and GA

Windows 2012 R2 GA (General Availability) occurred in October 2013. Downloads of the Windows 2012 R2 RTM release were made available on MSDN before that time however there were some changes made between RTM and GA that have a significant impact on Desired State Configuration – it breaks on most code you will find.

The answer is to install some updates.

As an absolute bare minimum you should install the GA update – KB2883200 (Note that KB 2894029 and KB 2894179  are included in the KB2883200 download)

http://support.microsoft.com/kb/2883200

http://www.microsoft.com/en-us/download/details.aspx?id=40774

 

When you install Windows 2012 R2 check that KB2883200 has bee installed. If not download and install.

I’d also recommend that you install KB2884846 (you also get KB2898742) – the October 2013 update rollup.

http://support.microsoft.com/kb/2884846

http://www.microsoft.com/en-us/download/details.aspx?id=40771

 

There is also a March 2014 update rollup -  KB2928680 – this important because it fixes the AD cmdlet issue

http://support.microsoft.com/kb/2928680

http://www.microsoft.com/en-us/download/details.aspx?id=42160

 

If you want to get the best out of Windows 2012 R2 make sure you install these updates. Matching updates are available for Windows 8.1 as well.

Where’s the value

PowerShell is object based – its the one fact that is mentioned in very introduction to PowerShell – and its the use of objects that gives PowerShell its reach and power.

The use of objects has one tiny drawback. When you want the actual value of a property you have to do slightly more work.

This is representative of a typical PowerShell expression

£> Get-Process powershell | select Path

Path
----
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

Now if you want the value of path itself to use elsewhere you have to do one of three things:

£> $proc = Get-Process powershell
£> $proc.Path
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

OR

£> $path = Get-Process powershell | select -ExpandProperty Path
£> $path
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

OR

£> $proc = (Get-Process powershell | select Path).path
£> $path
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

The first one gives you an object to work with.  If you want other properties you can access them later.

The other two options give you a variable containing just the information you need – the value of the Path property.

Which one works best  - depends on what you are doing.  I use all three techniques on  a regular basis though tend to prefer using option 2 to option 3 – mainly because I find it easier to read when I come back to the script weeks, months or even years later.

Give me a break

Having shown how to use continue last time I thought I’d show the opposite functionality this time and demonstrate how to jump out of a loop.

You do this using the break command.  The following examples show how it works. What do you think the output of these loops will be?

FOR loop

for ($i=1; $i -le 6; $i++){
  if ($i -eq 4) {break}
  $i
}

WHILE loop

$i = 0
while ($i -lt 6){
$i++
if ($i -eq 4) {break}
$i
}

DO loop

$i = 0
do {
$i++
if ($i -eq 4) {break}
$i
} while ($i -lt 6)

$i = 0
do {
$i++
if ($i -eq 4) {break}
$i
} until ($i -ge 6)

FOREACH loop

$numbers = 1..6
foreach ($number in $numbers) {
if ($number -eq 4) {break}
$number
}

If you said the output would be

1

2

3

You were correct.

THIS NEXT ONE WILL WORK

1..6 |
foreach {
if ($psitem -eq 4) {break}
$psitem
}

Though you want to think carefully before terminating a pipeline like this.