Update: MDT 2012 Beta 1

I recently posted about the release of MDT 2012 Beta 1 and wasn't too impressed with it. I have to say that my feelings are starting to change with two new blog posts from Michael Niehaus.


The cross-platform support means that instead of having to use two separate boot methods (x86 vs x64) to deploy your operating systems, you can now just use the x86 CD or USB and your x64 task sequences will be available.  Two items to note:

  • Booting to an x64 environment and deploying x86 is still not supported.
  • Booting to an x86 environment to deploy an x64 image means that you will need to upload setup files for both instances of that OS (e.g. Win 7 SP1 - 6.1.7601.17514) x86 and x64.

Now on the the good stuff...UEFI support. We've all grown to know and love the BIOS and have used it since the dawn of time (or so it seems).  UEFI is about to change all of that.  The BIOS has certain limitations that UEFI has been designed to eliminate.

  • 16-bit code (where most OSes are now 32-bit or 64-bit)
  • 1MB of addressable memory (regardless of how much the computer actually has)
  • Slower option ROM initialization
  • 2.2TB boot disk limitation (an MBR limitation)

UEFI has been deployed in many of the newer hardware models, but has been set to 'Legacy BIOS' mode for backwards compatibility.  MDT 2012 will allow you to take advantage of 'native' UEFI, which addresses the issues listed above.  The first two changes that most IT pros will notice are the removal of the 2.2TB boot disk limitation and the improved boot times.  As the UEFI standard matures, we should see an even larger improvement in boot times, especially when matched with SSDs.

For more information of the UEFI standards, visit http://www.uefi.org/specs/esp_registry.

Add code snippets to Powershell ISE

I have been looking for a user-friendly way to add code snippets to Powershell ISE to reduce typos and time spent copy/pasting.  Borrowing a page from Jeffery Hicks' blog, I took it a step further and used multi-line comments to add large code snippets to the ISE for creating new scripts.  As an example, I often write scripts that take advantage of the Quest ActiveRoles AD Management snapin.  The code below allows me to use ALT + F5 as a hotkey to insert this code into the ISE quickly and easily.


 $QADTools = @'
  function Add-QADTools
  {
  $Quest = Get-PSSnapin Quest.ActiveRoles.ADManagement -ErrorAction silentlycontinue
  if ($Quest)
    {
       Write-Debug "Quest.ActiveRoles.ADManagement Snapin loaded"
    }
  if (!$Quest)
    {
       Write-Debug "Loading Quest.ActiveRoles.ADManagement Snapin"
       Add-PSSnapin Quest.ActiveRoles.ADManagement
       if (!$?) {"Need to install AD Snapin from http://www.quest.com/powershell";exit}
    }
  }
  Add-QADTools
  '@

  $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add("Insert QAD Tools", `
{$psise.CurrentFile.Editor.InsertText($QADTools)},"ALT+F5") | out-Null


To implement this into the ISE, you will need to modify/create your Powershell ISE profile.  To find your user profile, you will need to browse to C:\Users\%USERNAME%\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1 and paste the above code into the .ps1 file.  This code will also add a new menu item to the Powershell ISE named 'Add-ons' with a menu item named 'Insert QAD Tools' as shown below.



Retrieve PC make and model info from WSUS

I came across a scenario where I needed to get the make and model of all of the client systems in my environment for reporting.  There are a few routes that I could take to retrieve this information (Inventory, WSUS, AV), and after briefly checking over each of them, it looked like WSUS was kept the most up-to-date for my purposes.


$Server = "wsusservername"
$Results = "C:\wsusmodels.csv"

[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") |
out-null

$WSUS = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($Server,$False)

$computerScope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope
$computers = $WSUS.GetComputerTargets($computerScope)
 
$Computers | 
Sort-Object Model |
Select-Object fulldomainname,ipaddress,make,model |
Export-CSV -Path $Results -NoTypeInformation

At the beginning of the script, we set some variables to determine the WSUS server that we will be connecting to and the location where we want to output the results.  We then load the assemblies for WSUS and connect to the server.

[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") |
out-null
$WSUS = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($Server,$False)

Once connected to the server, we need to create a computer target scope and then query a list of all computers in that scope.


$computerScope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope
$computers = $WSUS.GetComputerTargets($computerScope)

Now that we have a list of computer objects in the $Computers variable, we want to sort the objects based on the computer model, select the properties we want to report on, and export them to the CSV that was specified in the $Results variable at the beginning.

Now you have a CSV with a list of all of the computers in your environment (that report to that particular WSUS server) and their IP address, make, and model.  Happy reporting!

Convert DNS client cache into a Powershell object

I was watching the TechEd video The Network Files, Case #53: Diagnosing Diseases of DNS and began thinking about an easy way to troubleshoot local DNS client cache.  The first command that came to mind was 'IPConfig /DisplayDNS', but it is a hassle to scroll through all of the output looking for what I wanted.  I ended up writing a short script to convert the results into a Powershell object that I could then work with easily.

Function Get-DNSClientCache{
$DNSCache = @()

Invoke-Expression "IPConfig /DisplayDNS" |

Select-String -Pattern "Record Name" -Context 0,5 |
    %{
        $Record = New-Object PSObject -Property @{
        Name=($_.Line -Split ":")[1]
        Type=($_.Context.PostContext[0] -Split ":")[1]
        TTL=($_.Context.PostContext[1] -Split ":")[1]
        Length=($_.Context.PostContext[2] -Split ":")[1]
        Section=($_.Context.PostContext[3] -Split ":")[1]
        HostRecord=($_.Context.PostContext[4] -Split ":")[1]
        }
        $DNSCache +=$Record
    }
    return $DNSCache
}


The script begins by invoking the IPConfig command that we all know and love.  A typical DNS record looks similar to the one below.

Invoke-Expression "IPConfig /DisplayDNS" |

     docs.google.com
    ----------------------------------------
    Record Name . . . . . : docs.google.com
    Record Type . . . . . : 1
    Time To Live  . . . . : 78138
    Data Length . . . . . : 4
    Section . . . . . . . : Answer
    A (Host) Record . . . : 74.125.226.98


Now that we have the information that we want, we need to weed out extraneous lines.  The first item that I wanted to capture was the record name.  The results of the Invoke-Expression are piped to the Select-String cmdlet with a pattern of "Record Name" and a context of '0,5'.  This command searches every line from the pipeline that matches the pattern, then shows zero lines before the match and five afterwards.

Select-String -Pattern "Record Name" -Context 0,5 |

 >     Record Name . . . . . : docs.google.com
        Record Type . . . . . : 1
        Time To Live  . . . . : 80174
        Data Length . . . . . : 4
        Section . . . . . . . : Answer
        A (Host) Record . . . : 74.125.226.98

We now have a group of objects from the pipeline with the information that we want, we can loop through them and create some Powershell objects.  This is done with the use of the ForEach (%) alias, New-Object PSObject and property splatting.  For the record name property, I can take the match of the Select-String, split it between the colon and set the property 'Name' to the item after the colon.  For the rest of the properties, the script has to pull the information from the postcontext of the match, which is then split and the property assigned to the items after the colon.

    %{
        $Record = New-Object PSObject -Property @{
        Name=($_.Line -Split ":")[1]
        Type=($_.Context.PostContext[0] -Split ":")[1]
        TTL=($_.Context.PostContext[1] -Split ":")[1]
        Length=($_.Context.PostContext[2] -Split ":")[1]
        Section=($_.Context.PostContext[3] -Split ":")[1]
        HostRecord=($_.Context.PostContext[4] -Split ":")[1]
        }
        $DNSCache +=$Record
    }


Once each of the objects is created, it is added to the $DNSCache array that we created on the first line of the function.  The function then returns that array as a Powershell object that can be filtered, sorted and otherwise modified.

    return $DNSCache

An example that could be used is shown below.

    Get-DNSClientCache | Sort Name | Format-Table Name,TTL,HostRecord -Autosize

As I believe most Powershell users can attest in regards to work, "I've got 99 problems, but Powershell's not one."

Microsoft previews Windows 8 Metro UI on a touchscreen

Below is a preview of Microsoft Windows 8 (v.Next) running on a tablet with a touch-screen interface. Looks pretty fluid in their demo, but I wonder how it will handle multi-screen setups.  Should be pretty interesting to see which direction Microsoft decides to take.

Full story from Microsoft...


TechEd 2011 Powershell videos

There were some good Powershell related sessions at this year's TechEd conference.  Unfortunately, there seems to have been fewer than at TechEd 2010, which is odd considering the uptake in users that it has seen in the past year.  Some of the sessions from this year include:

Client

Server

You can watch the videos at the links above or download the slides/videos.   If you are already familiar with Powershell and you want a quick way to download TechEd Sessions automatically by using PowerShell, head on over to ScriptingGuys blog.

MDT 2012 Beta 1 Released

Microsoft Deployment Toolkit 2012 Beta 1 has been released. Some of the changes in this version:
  • New menus during capture/deployment.
  • More verbose info when executing task sequences.
  • Support for SCCM 2012
  • Various bug fixes.
From what I have seen so far, there is not much reason to upgrade unless you are planning to implement SCCM 2012. The rest of the items seem like nice-to-haves rather than needs or feature sets.