Categories

Monthly Archives: December 2013

The PowerShell year – 2013

This year has been a pretty good year for the PowerShell community. The highlights include:

  • PowerShell 4.0 becomes available
  • A very successful PowerShell Summit in April
  • A community hosted and judged Scripting Games – though as PowerShell is the only accepted language maybe a name change is needed?
  • PowerShell in Depth and PowerShell Deep Dives are published

The big ticket item in PowerShell 4.0 is Desired State Configuration. This functionality was extended at the end of the year with the publication of the  Desired State Configuration Resource Kit Wave 1 -  see the PowerShell team blog at http://blogs.msdn.com/b/powershell/archive/2013/12/26/holiday-gift-desired-state-configuration-dsc-resource-kit-wave-1.aspx

The most important part of the announcement is that it is wave 1 – meaning we should expect more DSC resources in the New Year.

Looking forward to 2014 what do we expect?

  • More DSC resources
  • 2014 Winter Scripting Games – this time we’re making them a team based event. Should be interesting
  • A PowerShell Summit in Seattle in April
  • A European PowerShell summit later in the year

Assuming you already know the PowerShell basics, or more, where should you be spending your PowerShell time in 2014?

If your work involves creating servers on a regular basis make sure you understand DSC

If you need to administer many servers – look to PowerShell workflow, PowerShell jobs and Scheduled jobs.  These options seem to have slipped out of the limelight lately.

Workflows are different – they use a PowerShell syntax but aren’t pure PowerShell. Some of the rules for using them are a bit strange and need some practice.

PowerShell jobs were introduced in PowerShell 2.0 but have always been overshadowed by remoting. The ability to run PowerShell jobs asynchronously and schedule them makes for a very powerful system for performing bulk tasks overnight.

The last recommendation for 2014 – learn more about CIM/WMI.  A significant fraction of the PowerShell functionality in Windows 8/2012 and later is built on WMI. If you don’t understand how it works you won’t get the best out of it. The OMI initiative is gaining traction which makes CIM an even more important technology to learn.

I’d also recommend experimenting with any of the areas of PowerShell you don’t know so well.

Finally, and most importantly, share what you learn with the rest of the PowerShell community - powershell.org is a very good place to start.

CDXML–NetworkAdapterConfiguration–Search on Index

The Win32_NetworkAdapterConfiguration class has an Index and an InterfaceIndex property. Both are suitable search properties.

The take an unsigned integer as their value – leading to this addition to the CDXML file:

 

<Property PropertyName="Index">
<Type PSType = "System.UInt32"/>
<RegularQuery >
   <CmdletParameterMetadata PSName="Index" />
</RegularQuery>
</Property>


<Property PropertyName="InterfaceIndex">
<Type PSType = "System.UInt32"/>
<RegularQuery >
   <CmdletParameterMetadata PSName="InterfaceIndex" />
</RegularQuery>
</Property>

You can use the new parameters like this:

Get-NetworkAdapterConfiguration -Index 4

Get-NetworkAdapterConfiguration -InterfaceIndex 5

 

You should see by now how much easier it is working with cmdlets like this rather than having to remember the syntax for WQL filters and even the class names.

The full CDXML file looks like this

<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='ROOT\cimv2\Win32_NetworkAdapterConfiguration'>
    <Version>1.0</Version>
    <DefaultNoun>NetworkAdapterConfiguration</DefaultNoun>

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
       
        <QueryableProperties>
           <Property PropertyName="DHCPEnabled">
            <Type PSType = "System.Boolean"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="DHCPEnabled" />
            </RegularQuery>
           </Property>
          
           <Property PropertyName="IPEnabled">
            <Type PSType = "System.Boolean"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="IPEnabled" />
            </RegularQuery>
           </Property>

           <Property PropertyName="Index">
            <Type PSType = "System.UInt32"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="Index" />
            </RegularQuery>
           </Property>


           <Property PropertyName="InterfaceIndex">
            <Type PSType = "System.UInt32"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="InterfaceIndex" />
            </RegularQuery>
           </Property>

       
        </QueryableProperties>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
</PowerShellMetadata>

 

The module manifest file hasn’t needed to be changed to add this additional functionality. One of the great things about CDXML is that once you have the basic cmdlet working it is so easy to add extra parameters.

 

The next step is to use some of the methods on the class

CDXML–NetworkAdapterConfiguration–IP Enabled

Last time we added a search parameter enabling this:

Get-NetworkAdapterConfiguration -DHCPEnabled $true

I also want to be able to search based on if the adapter if IP Enabled using:

Get-NetworkAdapterConfiguration -IPEnabled $true

This can be achieved by specifying another search parameter:

<Property PropertyName="IPEnabled">
<Type PSType = "System.Boolean"/>
<RegularQuery >
   <CmdletParameterMetadata PSName="IPEnabled" />
</RegularQuery>
</Property>

This the same as was done for DHCPEnabled except that the IPEnabled property is used.

The full XML now looks like this:

<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='ROOT\cimv2\Win32_NetworkAdapterConfiguration'>
    <Version>1.0</Version>
    <DefaultNoun>NetworkAdapterConfiguration</DefaultNoun>

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
       
        <QueryableProperties>
           <Property PropertyName="DHCPEnabled">
            <Type PSType = "System.Boolean"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="DHCPEnabled" />
            </RegularQuery>
           </Property>
          
           <Property PropertyName="IPEnabled">
            <Type PSType = "System.Boolean"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="IPEnabled" />
            </RegularQuery>
           </Property>
       
        </QueryableProperties>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
</PowerShellMetadata>

LastLogoff timestamp

I was recently asked if there was any way to fill in the LastLogoff timestamp

 

The short answer is no.  The values in the attributes related to logons are maintained by Active Directory during the logon process.

 

I wouldn’t want them to be programmable as that as would create a potential loop hole in my logging process.

 

As far as I can tell LastLogoff isn’t currently used in Active Directory though if you have access to the Exchange cmdlets you could use Get-mailboxStatistics to discover logon and loggoff times to the mailbox which would be close

Scripting Games 2014–more information

More information is available on the Games:

Logon and operational information

http://powershell.org/wp/2013/12/21/important-scripting-games-login-and-operational-information/

Events and Event authors

http://powershell.org/wp/2013/12/21/2014-winter-scripting-games-the-event-authors/

Team Foundation Tips

http://powershell.org/wp/2013/12/19/2014-winter-scripting-games-team-formation-tips/

Games schedule

http://powershell.org/wp/2013/12/16/2014-winter-scripting-games-schedule/

Registration opens 2 January 2014 with a practice event starting on 6 January

Time to get the teams organized in between the Turkey and Mince Pies

Countdown to the Scripting Games–32 days and counting

The countdown to the Winter 2014 Scripting Games has started.

Officially starting at 1am (UTC or GMT) 19 January 2014 the following dates should be noted:

2 January 2014 – registration opens

6 January 2014 – a practice event becomes available

19 January 2014 – event 1 starts

26 January 2014 – event 2 starts

2 February 2014 – event 3 starts

9 February 2014 – event 4 starts

 

Each event lasts one (1) week

As explained previously the events are designed to be tackled by teams of 2-6 people.

Coaching will be available during the Games if teams would like to use it.

 

The judging and coaching teams are separate.

 

Details from http://powershell.org/wp/2013/12/16/2014-winter-scripting-games-schedule/

£> (Get-Date -Day 19 -Month 1 -Year 2014 -Hour 1 -Minute 0 -Second 0 ) - (Get-Date) | Format-List Days, Hours, Minutes,
Seconds


Days      : 32
Hours     : 13
Minutes  : 47
Seconds : 33

 

Enjoy

Deal of the Day–17 December 2013

Manning – www.manning.com – have multiple PowerShell books as their deal of the day – today and tomorrow. The deal started at midnight ET today ( 3am GMT) and lasts for 48 hours.   Books included:

PowerShell and WMI

PowerShell in Practice

PowerShell in Depth

PowerShell Deep Dives

Windows PowerShell in Action, Second Edition

Learn PowerShell 3 in a Month of Lunches, Second Edition

Learn PowerShell Toolmaking in a Month of Lunches.

Get 50 % off these titles today and tomorrow with code dotd1217au

A new version of ADMT

A new version of the AD Migration Tool (ADMT) has been announced - http://blogs.technet.com/b/askds/archive/2013/12/13/an-update-for-admt-and-a-few-other-things-too.aspx

While not ready for download just yet at least we know its in the pipeline and supports the newer versions of Windows

CDXML–adding search parameters

Last time you saw how to create a cmdlet from the Win32_NetWorkAdapterConfiguration class:

<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='ROOT\cimv2\Win32_NetworkAdapterConfiguration'>
    <Version>1.0</Version>
    <DefaultNoun>NetworkAdapterConfiguration</DefaultNoun>

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
 
</PowerShellMetadata>

Now its time to add some parameters that can be used for searching.  This will be equivalent to performing these actions:

Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "DHCPEnabled='True'"

Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "IPEnabled='True'"

Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "Index=0"

Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "InterfaceIndex=3"

Lets start by looking at the DHCPEnabled property

£> $class = Get-CimClass -ClassName Win32_NetworkAdapterConfiguration
£> $class.CimClassProperties["DHCPEnabled"]


Name                            : DHCPEnabled
Value                             :
CimType                       : Boolean
Flags                              : Property, ReadOnly, NullValue
Qualifiers                      : {MappingStrings, read}
ReferenceClassName :

 

The parameter DHCPEnabled takes a Boolean value.  At the moment I don’t want anything clever like pipeline input – just the ability to use a parameter

This requirement translates to:

<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='ROOT\cimv2\Win32_NetworkAdapterConfiguration'>
    <Version>1.0</Version>
    <DefaultNoun>NetworkAdapterConfiguration</DefaultNoun>

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
       
        <QueryableProperties>
           <Property PropertyName="DHCPEnabled">
            <Type PSType = "System.Boolean"/>
            <RegularQuery >
              <CmdletParameterMetadata PSName="DHCPEnabled" />
            </RegularQuery>
           </Property>
       
        </QueryableProperties>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
</PowerShellMetadata>

The changes are defined by the  <QueryableProperties> tags

        <QueryableProperties>

Define the WMI property you are searching on

           <Property PropertyName="DHCPEnabled">

Define the type of the data the parameter accepts

            <Type PSType = "System.Boolean"/>

Define the query type – in this case a straight forward search

            <RegularQuery >

Define the name you want the parameter to have  - doesn’t have to match the WMI property name
              <CmdletParameterMetadata PSName="DHCPEnabled" />
            </RegularQuery>
           </Property>
       
        </QueryableProperties>

 

You can use the changed cmdlet like this:

Get-NetworkAdapterConfiguration
Get-NetworkAdapterConfiguration -DHCPEnabled $true
Get-NetworkAdapterConfiguration -DHCPEnabled $false

The full syntax on the cmldet is:

Get-NetworkAdapterConfiguration [-DHCPEnabled <bool[]>]
[-CimSession <CimSession[]>] [-ThrottleLimit <int>]
[-AsJob]  [<CommonParameters>]

The cmdlets over objects technology automatically adds these parameters:

-CimSession

-ThrottleLimit

-AsJob

-CommonParameters

Next time we’ll add the other search properties

CDXML–network adapter configuration

I’ve amended the new-cdxml function created earlier in the series:

function new-cdxml {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]$class,

[Parameter(Mandatory=$true)]
[string]$noun,

[string]$namespace = 'ROOT\cimv2',
[string]$path = "C:\Scripts\Modules\Hardware"
)

$code = @"
<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='$namespace\$class'>
    <Version>1.0</Version>
    <DefaultNoun>$noun</DefaultNoun>

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
 
</PowerShellMetadata>
"@

$file = Join-Path -Path $path -ChildPath "$class.cdxml"
Write-Verbose -Message  $file
Set-Content -Path $file -Value $code

}

 

The change is making the class and noun parameters mandatory. In PowerShell 3 & 4 you can simplify the syntax slightly:

param (
[Parameter(Mandatory)]
[string]$class,

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

[string]$namespace = 'ROOT\cimv2',
[string]$path = "C:\Scripts\Modules\Hardware"
)

 

I prefer to use the PowerShell 2.0 syntax and actually state that Mandatory=$true.  This is for 2 reasons. Firstly, its what I’m used to and it works – I haven’t got round to changing my default templates. Secondly, I prefer to use this syntax because its immediately apparent to me that the parameter is Mandatory.

This time I’ve used the Win32_NetworkAdapterConfiguration class because it enables me to introduce the use of search (filter) parameters in CDXML cmdlets; it has a number of very useful methods and it enables me to introduce the use of format files.

 

Using new-cdxml you can create the basic module

<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='ROOT\cimv2\Win32_NetworkAdapterConfiguration'>
    <Version>1.0</Version>
    <DefaultNoun>NetworkAdapterConfiguration</DefaultNoun>

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
 
</PowerShellMetadata>

 

To add this into the module manifest amend these two lines as shown:

# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
NestedModules = @('Win32_BIOS.cdxml',
                   'Win32_ComputerSystem.cdxml',
                   'Win32_DiskDrive.cdxml',
                   'Win32_NetworkAdapterConfiguration.cdxml'
                    )

# Functions to export from this module
FunctionsToExport = @('Get-Bios',
                      'Get-ComputerSystem',
                      'Get-PhysicalDisk',
                      'Get-NetworkAdapterConfiguration'
                      )

 

You now have a hardware module consisting of:

£> Get-Command -Module Hardware

CommandType     Name
-----------             ----
Function               Get-Bios
Function               Get-ComputerSystem
Function               Get-NetworkAdapterConfiguration
Function               Get-PhysicalDisk

 

The output from Get-NetworkAdapterConfiguration on my Windows 8.1 virtual machine looks like this:

ServiceName   DHCPEnabled   Index   Description
-----------        -----------         -----     -----------
netvsc             False                0          Microsoft Hyper-V Network Adapter
kdnic               True                 1          Microsoft Kernel Debug Network Adapter
tunnel             False                 3          Microsoft ISATAP Adapter
netvsc             False                4          Microsoft Hyper-V Network Adapter #2
tunnel             False                5          Microsoft ISATAP Adapter

 

Now this is the same display that Get-CimInstance produces and for my purposes it doesn’t work.  I need to create a format file to produce the display I need. I also want to be able to filter on various criteria including DHCPEnabled, IPEnabled, InterfaceIndex, Index  and Description. I also want to be able to search on any of these individually or in any logical combination