On Windows PowerShell and other admin-related topics

Download TechNet Edge videos using Windows PowerShell

I recently got a question on Twitter if I could create a PowerShell script to download files from TechNet Edge. I thought this would be useful for many other people as well, so I have spent some time this weekend working on this script. I wanted to make the script as generic and re-usable as possible, so even though I started hardcoding it for downloading files from a given RSS-feed from TechNet Edge, I later on generalized it to make it easy to re-use on other websites  as well. The script is called Get-WebVideoFile.ps1, and is available on both PoshCode and the Microsoft TechNet Script Center.

How to use the script

1) The script requires PowerShell 2.0 and you must have configured your PowerShell execution policy in order to run the script. Run $host.version from PowerShell to see what version you are running. If you need help configuring the execution policy or running the script, see “Running Windows PowerShell Scripts” on Microsoft TechNet.

2) Download the script from here (PoshCode) or here (Microsoft TechNet Script Center).

3) Find the RSS URL for the category you want to download files from. On TechNet Edge you can find an overview of all categories (called tags) on this link.


In this example I have chosen the Microsoft Virtual Academy tag:


You can then find the RSS URL by clicking on the RSS icon to the right of the title on the top of the page.

4) Specify the URL on the RssUrl parameter when running the Get-WebVideoFile script:


You will get a progress bar which shows the progress for the current file:


Remember that you can also use Windows PowerShell ISE (or any 3rd party host) instead of the PowerShell console host:


More information about the script

Comment based help

At the top of the script you can see that I have added comment based help. This means you can use Get-Help to show information and example usage of the script:



You can read more about comment based help in this TechNet Magazine Article by Don Jones, as well as in the help topic about_Comment_Based_Help.


RssUrl – This is the only mandatory parameter, which provides the script the RSS feed to go through. The script download the HTML code from each RSS entry`s link, and look for a URL that matches the regular expression.

Destination – The folder the files will be downloaded to. If not specified the files will be downloaded to the current user`s Video-folder (for example C:\Users\Username\Videos\).

UseOriginalFileName – This is a switch parameter to specify that you want to use the original file names for the downloaded files. On TechNet Edge most video files got a non-descriptive name, for example e1ef34ca-cdef-463d-9c3f-94aa606bc6ab.wmv. Because of this I set the default behavior of the script to use the RSS item title as the file name.

UrlRegex – This is the regular expression that will be used to search for the video URL from the HTML code from each RSS item link. You can re-use the default regex and replace “wmv” with for example “mp4” if you want to download the MP4-versions of the videos. If you are interested in learning about Regular Expressions, I can recommend the book “Master Regular Expressions” by Jeffrey E.F. Friedl. If you want a tool to help you build the regular expression I can recommend RegexBuddy.

Verbose – This is not a parameter I have added, it is one of the common parameters in PowerShell which I want to highlight since I have added some verbose information. For example if the regular expression does not match, you can see it in the verbose output. This is a switch parameter, so you can add “-Verbose” to the script parameters to use it. You can also read more about the Verbose parameter in the about_CommonParameters help topic.

The download process

Initially when creating the script I started using the DownloadFile method of the Net.WebClient class in .NET. This worked fine, but did not provide any progress status during download. This makes it hard for the user of the script to know how long the download will take, and if anything is happening at all. I then turned to Background Intelligent Transfer Service (BITS), and the Start-BitsTransfer cmdlet which provides progress status as well as other features. For some reason the BITS jobs failed with the error message “HTTP status 404: The requested URL does not exist on the server.”. I am not sure why, but this may be because the server-side on TechNet Edge downloads does not support the necessary HTTP Requirements.

I then got a tip from Joel Bennett about his Get-WebFile function available on PoshCode. This function met my requirements, and is included at the top of the script.

The script will check the destination folder to see if the file is already downloaded, which means you can run the script several times without downloading files you already have. This is also useful when running the script as a scheduled task, which may be of interest if you want to automatically download new videos in a specific category.

Related resources

MMS 2012 Download Sessions – Offline Viewing (PowerShell script to download sessions from MMS 2012)


May 6, 2012 Posted by | Scripting, TechNet Edge, Windows PowerShell | | 3 Comments

Automate a task in System Center Virtual Machine Manager 2012 based on the “View Script” button

System Center Virtual Machine Manager has since the beginning had excellent automation capabilities in form of Windows PowerShell. In fact, everything that is performed in the SC VMM Console generates a PowerShell command which is being invoked as a job. A very useful feature in the SC VMM Console is the “View Script” button, which shows you the actual PowerShell commands that is being run. To show you how you can leverage this functionality, I am going to show you how I used it to automate one part of a new deployment.


Provisioning Logical Networks in System Center Virtual Machine Manager 2012

In System Center Virtual Machine Manager 2012 there is a concept called Logical Networks, which is defined as part of the Fabric. You can read more about Logical Networks in this article by the SC VMM team. Step-by-step guidance on how to create and assign a logical network is available in this TechNet Wiki guide by Microsoft MVP Kristian Nese.

What I want to show you in this article is how you in an easy manner can automate the process of creating and assigning virtual networks. I recently had to provision close to 100 logical networks in a new deployment, and as you can read in the mentioned articles I first needed to create the Logical Networks and then go to the Properties of every virtualization host and assign the correct Logical Network to the correct physical NIC.

In my scenario that would mean more than 1000 mouse clicks if doing the task manually. Next I will show you how to automate the creation and assignment of logical networks.


Create the Logical Network

Start the “Create Logical Network” wizard from the Fabric pane in VMM:


Creating a Network Site is not mandatory, but this is something I needed in my scenario:


Click on the “View Script” button on the Summary page (click Cancel in the wizard afterwards):



You will be presented with a PowerShell script in a Notepad window. This is the script I got:

$logicalNetwork = New-SCLogicalNetwork -Name "Backend"

$allHostGroups = @()
$allHostGroups += Get-SCVMHostGroup -ID "0e3ba228-a059-46be-aa41-2f5cf0f4b96e"
$allSubnetVlan = @()
$allSubnetVlan += New-SCSubnetVLan -VLanID 0

New-SCLogicalNetworkDefinition -Name "Oslo" -LogicalNetwork $logicalNetwork -VMHostGroup $allHostGroups -SubnetVLan $allSubnetVlan -RunAsynchronously

This above script is the what I will use as the template for my new Logical Network provisioning script. A common approach for creating multiple items is using a foreach loop, but first we need some data which the loop will iterate over. Ìf you have all your Logical Networks defined in an Excel spreadsheet, which was the case for me, you can save the spreadsheet as a comma-separated file and use that as the data source in the script. In PowerShell it is also possible to use a broad number of data sources, for example a SQL database.

After creating a CSV-file I customized the column headers in the file, which will serve as the property names for the imported objects. Here is a sample CSV-file from my lab environment:


Backend,"This is the corporate backend network","All Hosts",0,Oslo,Trunk

As you can see in my customized script there is not very much that is changed:

$networks = Import-Csv -Path C:\Import\VMM_logical_networks.csv

foreach ($network in $networks) {

$logicalNetwork = New-SCLogicalNetwork -Name $network.Name -Description $network.Description

$allHostGroups = @()
$allHostGroups += Get-SCVMHostGroup -Name $network.HostGroup
$allSubnetVlan = @()
$allSubnetVlan += New-SCSubnetVLan -VlanID $network.VlanID

New-SCLogicalNetworkDefinition -Name $network.Site -LogicalNetwork $logicalNetwork -VMHostGroup $allHostGroups -SubnetVLan $allSubnetVlan -RunAsynchronously

A brief overview of the changes:

  • On the first line we import the contents of the CSV-file using the Import-Csv cmdlet.
  • Next we iterate over each entry in the CSV-file by using a foreach loop from line 3 to 13. This means that line 4 to 12 will be repeated for every line in the CSV-file.
  • The last customization is made to the parameters of the cmdlets in the script. For example the Name property of New-SCLogicalNetwork is the value ($network.Name) of the Name property of the imported CSV objects.


Assigning the Logical Network

The final task is to assign the Logical Networks we created to the correct physical NICs of the virtualization hosts. Again we start by doing the task in the SC VMM Console:

Go into the Properties dialog of one of the virtualization hosts, select Hardware and then select a NIC.

Press the check box of two or more Virtual Networks, and the click the “View Script” button (click Cancel in the Properties dialog afterwards):


We can see that the generated script is a bit more complicated than the previous one:

$vmHost = Get-SCVMHost -ID "82b7c0f3-ed2e-4dcc-8b05-40765dba712e" -ComputerName "hpv-jr-02"

$vmHostNetworkAdapter = Get-SCVMHostNetworkAdapter -Name "Broadcom NetXtreme Gigabit Ethernet" -VMHost $vmHost

# Backend
$logicalNetwork = Get-SCLogicalNetwork -ID "b036b32a-8139-4b0e-babc-cda1e98ef2e7"
Set-SCVMHostNetworkAdapter -VMHostNetworkAdapter $vmHostNetworkAdapter -AddOrSetLogicalNetwork $logicalNetwork -JobGroup "4af63cdf-ea00-4647-b554-cc7167070f33"

$logicalNetwork = Get-SCLogicalNetwork -ID "292c0075-f81d-4af9-81f5-c775c5bcf90a"
Set-SCVMHostNetworkAdapter -VMHostNetworkAdapter $vmHostNetworkAdapter -AddOrSetLogicalNetwork $logicalNetwork -JobGroup "4af63cdf-ea00-4647-b554-cc7167070f33"

Set-SCVMHostNetworkAdapter -VMHostNetworkAdapter $vmHostNetworkAdapter -Description "" -JobGroup "4af63cdf-ea00-4647-b554-cc7167070f33" -VLanMode "Access" -AvailableForPlacement $true -UsedForManagement $true

Set-SCVMHost -VMHost $vmHost -JobGroup "4af63cdf-ea00-4647-b554-cc7167070f33" -RunAsynchronously

We will continue to use the same CSV-file as we did when creating the logical networks. You might have noticed that there was one column in the CSV-file we did not use in the first script: VMHostAdapterName. This is a property which will be used to assign the logical networks to a physical NIC on a virtualization host, based on the connection name of the network adapter. For example, I have renamed a network adapter from “Local Area Connection” to “Trunk #1”. In this case the VMHostAdapterName in the CSV-file should be “Trunk #1” for the Virtual Networks which is mapped to this physical NIC. This network adapter is configured in trunk mode, which means it is assigned multiple VLANs and thus may contain multiple Virtual Networks.

This way of performing the mapping between a physical NIC and a Virtual Network is a design decision I took when creating the script, although you may choose to do the mapping based on other properties, such as the IP-address range of the NIC. Since the environment I was working with had a consistent naming convention for the virtualization host network adapters I found this to be the most appropriate way of doing the mapping.

Before the walkthrough, I will first show you the customized version of the script the VMM Console generated:

$vmhosts = Get-SCVMHost
$networks = Import-Csv -Path C:\Import\VMM_logical_networks.csv

foreach ($vmhost in $vmhosts) {

# Create a Job Group ID
$JobGroupID = [Guid]::NewGuid().ToString()

foreach ($network in $networks) {

$vmHostNetworkAdapter = Get-SCVMHostNetworkAdapter -VMHost $vmhost | Where-Object {($_.LogicalNetworks | Select-Object -ExpandProperty Name) -contains $network.VMHostAdapterName}

if ($vmHostNetworkAdapter) {

$logicalNetwork = Get-SCLogicalNetwork -Name $

Set-SCVMHostNetworkAdapter -VMHostNetworkAdapter $vmHostNetworkAdapter -AddOrSetLogicalNetwork $logicalNetwork -JobGroup $JobGroupID

Set-SCVMHost -VMHost $vmhost -JobGroup $JobGroupID -RunAsynchronously


A brief overview of the changes:

  • On the first line we retrieve the virtualization hosts we want to iterate over. You may choose to limit the scope to a specific host group by using the –VMHostGroup parameter.
  • On the second line we import the contents of the CSV-file like we did in the previous script
  • On line 4 to 24 we create a foreach loop to iterate over all the virtualization hosts we initiated in the $vmhosts variable
  • The next thing we do is creating a job group (a GUID), which will make VMM perform all the following changes in a single job. This means that a single job will be run for each virtualization host when adding 100 Virtual Networks, instead of 100 jobs for each virtualization host. The concept of using Job Groups is described in this article in the VMM 2012 documentation on Microsoft TechNet.
  • On line 9-19 we iterate over all of the virtual networks in the CSV-file, and try to find a network adapter with a name equal to the VMHostAdapterName property of the Virtual Network defiend in the CSV-file.
  • Next, an if statement is used to determine if a network adapter was found. If the statement is evaluated to $true the actual change is being committed to the network adapter (this is the same as ticking the checkbox in the dialog box in the screenshot above).
  • When the inner foreach loop is finished the job will be commited by the command on line 21.
  • The same steps will be repeated until the outer foreach loop is finished.

The last recommendation I want to provide is to copy the script generated by the “View Script” button to a PowerShell editor like the Windows PowerShell ISE:


As you can see the script in the above screenshot is much easier to read than the following due to features such as syntax coloring and brace matching:




Overview of Scripting in VMM

Getting Started with Virtual Machine Manager

System Center: Virtual Machine Manager Engineering Team Blog

April 17, 2012 Posted by | Scripting, System Center Virtual Machine Manager, Virtualization, Windows PowerShell | | 4 Comments

2012 Scripting Games

The Microsoft Scripting Guys is hosting the 2012 Scripting Games April 2 – April 13 2012. The Scripting Games started out several years ago as a scripting competition based on VBScript. After the introduction of Windows PowerShell the Scripting Games did both a VBScript and a PowerShell track for a few years, until last year when VBScript was phased out in advantage of Windows PowerShell.

We can see the same thing happening in terms of automation capabilities in both Microsoft and non-Microsoft products. When we also look at the massive PowerShell capabilities coming in Windows 8 and Windows Server 8, we can see that PowerShell has turned into an essential skill for IT Professionals.

The Scripting Games is an excellent opportunity to get started with the scripting capabilities in Windows PowerShell. If you are new to PowerShell, the Beginner track is the recommended track for your first year participating in the Scripting Games. For more experienced scripters there is an Advanced track with more challenging tasks. Note that using features in the current beta of Windows PowerShell 3.0 is allowed in the Scripting Games submissions.

For those who want an introduction to PowerShell before the Scripting Games begin, Scripting Guy Ed Wilson will host a 5-series Live Meeting called “Windows PowerShell for the Busy Admin” beginning March 12, 2012.

Like last year, I will participate in the Scripting Games as a judge, which will be great fun! For those interested in learning PowerShell I highly recommend to take the time to participate in the Scripting Games, as it is a great learning experience. If your on Twitter, remember to use the 2012 Scripting Games Twitter tag #2012SG.

Good luck to all participants!


2012 Scripting Games Resources

2012 Windows PowerShell Scripting Games: All Links on One Page

2012 Scripting Games: Frequently Asked Questions

2012 Scripting Games Judging Criteria Revealed

Announcing the PowerShell Judges for the 2012 Scripting Games

TechNet Radio podcast: Announcing the 2012 Scripting Games

PowerScripting Podcast: Episode 177 – Scripting Guy Ed Wilson on the 2012 PowerShell Scripting Games

Official Scripting Guys Forum

The Scripting Guys on Facebook

The Scripting Guys on Twitter

March 11, 2012 Posted by | Scripting, Scripting Games, Windows PowerShell | | Leave a comment

Introducing the PowerShell Network Adapter Configuration module

For a Windows administrator, working with network adapters is a common task. A common approach many companies use is configuring servers with static IP addresses (IPv4) and clients using DHCP. The IP address is just one of many properties of a network adapter, as we also have properties like subnet mask, default gateway, DNS server search order and so on. Configuring these properties is usually performed during the initial setup of a computer, either manually or by a deployment mechanism.

The configuration of a network adapter is mostly static, however, from time to time some properties might need to be changed. In example the subnet on a network is expanded to meet new requirements, and thus the subnet mask property must be updated on computers not using DHCP. Another scenario is the setup of new DNS servers, with a decision not to keep the existing DNS servers` IP addresses. I recently faced the last scenario, where several hundred servers configured with static IP addresses needed to have their DNS configuration updated. Using Windows PowerShell the task can be automated, even if we need to perform the task on 10, 100 or 1000 servers. However, the more computers a script is run against, the more important it is to implement proper error handling and logging to keep track of which computers is updated.

The above task is just one of many potential tasks for configuring a network adapter. Since I was unable to find any existing PowerShell module/library for working with network adapters on Windows systems, I decided to create a project on Codeplex:


The PowerShell Network Adapter Configuration module

The PowerShell Network Adapter Configuration (PSNetAdapterConfig) module is a PowerShell module for working with network adapters on Windows-based computers. The module is using Windows Management Instrumentation (WMI) to retrieve and configure properties of network adapters.

The current release of the module makes use of the following WMI-classes:

The module currently contains 4 functions:

  • Get-DNSServerSearchOrder – get the DNS client settings for a network adapter (the property name is DNSServerSearchOrder)
  • Get-NetConnectionId – get the name of a network adapter (the property name is NetConnectionId)
  • Set-DNSServerSearchOrder – change the configured DNSServerSearchOrder. This function contains two parameter sets, one for replacing the current DNSServerSearchOrder property value, the other for adding/removing IP addresses from the current value
  • Set-NetConnectionId – change the name of a network adapter. In example, change the name from “Local Area Connection” to “Server VLAN 42”

I will add functions to the module when I find time, but I also hope that people in the community will contribute by either improving the existing functions, providing suggestions or creating new functions.

When downloading a PowerShell module from the internet (typically a zip-file), beginners often get into problems because they don`t know that the file first needs to be unblocked (Right-click the zip-file->Properties->Unblock). To overcome this challenge I created a Windows installer (MSI) file which is easy to install and does not need to be unblocked:


The default install path is %userprofile%\Documents\WindowsPowerShell\Modules, and the user have the option to override the module path.

The installer was created using Windows XML Installer (Wix), based on Chad Miller`s blog-post Building A PowerShell Module Installer.

When the module is installed, we can use Import-Module to import the module, and Get-Command to list the available commands:


As we can see there is also an alias for each of the commands (functions).

By using Get-Help we can see available parameters along with their descriptions, as well as several examples:


The functions supports both ValueFromPipeline and ValueFromPipelineByPropertyName, which means we can leverage the PowerShell pipeline. Have a look at example 3 on the above image to see how computers can be retrieved from Active Directory using Get-ADComputer, and then piped directly into the Set-DNSServerSearchOrder function.

The functions outputs PowerShell objects, which mean we can use regular PowerShell techniques to work with the data, in example converting the objects to HTML or CSV. I typically use Export-Csv to output the data to CSV-files which in turn can be converted to Excel spreadsheets:



The functions is using a try/catch construct, using the following logic:

  1. Ping the computer, if unsuccessful the property “Connectivity” on the output object is set to “Failed (ping”)
  2. Connect to the computer using WMI, if unsuccessful the property “Connectivity” on the output object is set to “Failed (ping”)
  3. The property “Connectivity” on the output object is set to “Successful” if step 1 and 2 succeeds
  4. Retrieve or change the applicable properties using WMI

When working with a large number of computers we can use Sort-Object in PowerShell to filter the output objects based on the Connectivity property, or the sorting functionality in Microsoft Excel if the output objects is piped to a CSV-file.


The final example I will show is using the Set-NetConnectionId function. On a test-computer we have a network adapter named “Local Area Connection 5”:


Using Set-ConnectionId we can specify the subnet for which network adapter to perform the change on (the above network adapter has an IP address of and specify the new name of the network connection:


When the command has run we can see that the connection name for the adapter has changed:


One additional feature that might be included to this function is the ability to provide a hash-table with a mapping of subnets and NetConnectionIds, which will make it easy to create a consistent naming convention for network adapters.

As a final note, all functions has a Logfile parameter, allowing us to log error message to the specified file.



  • Windows PowerShell 2.0
  • ICMP (ping) and WMI firewall openings from the computer running the module to the target computers
  • Administrator permissions on the target computers

To avoid the firewall requirements, a workaround is running the functions from a PowerShell script locally on target computers using a software distribution product like System Center Configuration Manager.
Another option is to run the functions over PowerShell remoting.


Download and feedback

The module is available for download on the Codeplex project site Please use the Discussions and Issue Tracker sites on the project site to report bugs and feature requests.



The functions is too long to walkthrough in a blog-post, so I will direct you to the following resources to get started working with advanced functions and modules in PowerShell:

An Introduction to PowerShell Modules by Jonathan Medd.

An Example ScriptModule and Advanced Function by Don Jones.

Ten tips for better PowerShell functions by James O`Neill.

Maximize the reuse of your PowerShell by James O`Neill.

November 22, 2011 Posted by | Remote Management, Scripting, Server management, Windows PowerShell | , , , , | 1 Comment

Hyper-V: How to unbind a physical NIC from a Virtual Switch using WMI and PowerShell

If you`re not already familiar with networking in Microsoft Hyper-V I would recommend you to have a look at this whitepaper from Microsoft, which described how networking works in Hyper-V.

The following solution will describe a problem which might occur when configuring virtual networks in Hyper-V. Consider the following scenario:

  • You`re about to configure a new external virtual network in Hyper-V using Hyper-V Manager remotely from another computer. This is a common scenario when working with the Core edition of Windows Server 2008/2008 R2.
  • When selecting the physical NIC to bind to the new virtual network, you choose the adapter which you are remotely connecting to the Hyper-V host through.

What happens in this scenario is that the Virtual Switch Management Service is binding the external Ethernet port for the selected NIC to the Microsoft Windows Virtualization network subsystem. What normally should happen next is that the converted Ethernet port should be bound to the new virtual switch you are creating. However, this never happens since the NIC you are remotely managing the Hyper-V host through is no longer available in the parent operating system. This leaves the NIC in an “orphaned” state, since you cannot use the NIC in the parent operating system, and it`s not in use by any virtual networks.

To resolve this issue, whether using the full GUI version or the Core version of Windows Server, you need to manually unbind the the Ethernet port. There is an UnbindExternalEthernetPort available on the Msvm_VirtualSwitchManagementService WMI class, which is fully documented in this article on MSDN.

To invoke the WMI method we can use Windows PowerShell. To ease the procedure I`ve created a PowerShell function you can use if you ever come into the need for manually unbinding an external Ethernet port in Hyper-V:


Function Select-List
    Param   ([Parameter(Mandatory=$true  ,valueFromPipeline=$true )]$InputObject, 

    begin   { $i= @()  }
    process { $i += $inputobject  }
    end     { if ($i.count -eq 1) {$i[0]} elseif ($i.count -gt 1) {
                  $Property=@(@{Label=“ID”; Expression={ ($global:Counter++) }}) + $Property
                  format-table -inputObject $i -autosize -property $Property | out-host
                 $Response = Read-Host “Select NIC to unbind”
                  if ($response -gt “”) { 

function Remove-HVExternalEthernetPort {

$ExternalEthernetPort = Get-WMIObject -class “Msvm_ExternalEthernetPort” -namespace “root\virtualization” | Select-List -Property name

$HVSwitchObj = Get-WMIObject -class “MSVM_VirtualSwitchManagementService” -namespace “root\virtualization”

if ($ExternalEthernetPort) {
else {
throw “An error occured. Choose a valid ExternalEthernetPort from the provided list”


Note: The Select-List function is a modified version of the Select-List function available in the PowerShell Management Library for Hyper-V available on CodePlex (see link below).

You can either paste the function into a PowerShell session or save it into ps1-file and dot source it. When done you can invoke the function like this:


When you`ve entered the index number for the NIC you want to remove, a return value of 0 indicates the operation succeeded. Any other value indicates an error (look at the previous mentioned MSDN-article for more information).


More resources on managing Hyper-V using PowerShell

PowerShell Management Library for Hyper-V – this is an excellent PowerShell module for managing Hyper-V available on CodePlex

System Center Virtual Machine Manager 2012: Scripting

System Center Virtual Machine Manager 2008 R2: Scripting

Hyper-V WMI Using PowerShell Scripts

Script: Determining Virtual Switch Type Under Hyper-V

August 30, 2011 Posted by | Hyper-V, Hyper-V R2, Scripting, Virtualization, Windows PowerShell | , , | 1 Comment

Getting starting with Cisco UCS PowerShell Toolkit

Cisco – widely known as a networking infrastructure vendor – entered the blade server market in 2009. Their offering is called Unified Computing System, described by Gartner as a fabric-enabled, enterprise-class platform with good integration of networking, virtualization, management tools and storage. On the 2011 Gartner Magic Quadrant for Blade Servers they`re defined as a visionary vendor, and it will be interesting to see if they can challenge the 3 leaders Dell, IBM and HP.

The Cisco Unified Computing System is quite different from traditional blade systems, in that the server profiles (so called service profiles) is independent from the physical blade servers. An example to describe what this means is that a physical blade server might fail and be replaced, while the server profile keeps unique ID`s like MAC addresses, World Wide Names (WWN`s) and so on. If using boot from SAN rather than local disk drives, physical interaction is not required to get the system back online if a spare blade server is available.


The UCS core components

  • Blade Chassis – Blade server enclosure
  • Cisco UCS Manager – Embedded into the Fabric Interconnect. Provides management capabilities
  • Cisco UCS fabric interconnect – Provides networking (Ethernet/Fibre Channel) and management for connected blades and chassis`
  • Fabric Extenders – Provides connection between the interconnect fabric and the blade enclosures

A photo showing the Cisco Unified Computing System architecture is available here ( In regards of management, all aspects of Cisco UCS can be managed through an XML API. This makes it possible for 3rd parties to offer management solutions, and integration with other products. An example of a 3rd party product is the Cisco UCS Iphone/Ipad application for managing and monitoring the system. Links for more information on the management model and the XML API is available in the resources section in the bottom of this article.


Cisco UCS PowerShell Toolkit

Based on a customer request from an early adaptor, Cisco provided PowerShell support for managing their UCS product through the XMP API. With the Microsoft automation strategy in mind, this was an excellent choice. It will make integration into products like System Center Orchestrator (formerly Opalis) very easy, and the also make the product attractive for enterprises. The PowerShell administration tool is available as a module part of the Cisco UCS PowerShell Toolkit.

A great way to learn using the Cisco UCS PowerShell Toolkit is downloading the Cisco UCS Emulator. This is a virtual machine image which can be imported into VMware Player or VirtualBox. When the VM is up and running you can access both the UCS Manager (http URL is shown when the VM has started) and the XML API. A great feature is that you can import the configuration from a production UCS to simulate administration changes in a lab environment.

Next, you can download the latest versions of both the Cisco UCS PowerShell Toolkit (aka UCSMPowerTool) and the PowerShell Toolkit User Guide from this website.

The installer will by default put the files in %programfiles%\Cisco\UCSMPowerToolkit:


CiscoUCSPS.dll is the assembly which can be imported as a module in Windows PowerShell 2.0 and later. You can either double-click LaunchUCSPS.bat or invoke StartUCSPS.ps1 from an existing PowerShell session to get started. Alternatively you can use Import-Module from an existing PowerShell session like this:
Import-Module “C:\Program Files (x86)\Cisco\UCSMPowerToolkit\CiscoUCSPS.dll”

I would suggest rather than installing to the Program Files folder (which requires administrative privileges), that Cisco generates a module manifest and install the module to the default PowerShell module directory (C:\Users\<username>\Documents\WindowsPowerShell\Modules).

When the module is imported we can use Get-Command with the –Module parameter to list all command inside the CiscoUCSPS module:


The current version of the module contains 149 cmdlets, so all commands are not shown in the above screenshot.

The first thing we need to do is connect to an instance of the UCS Manager. If using the Cisco UCS Emulator you can view the management  IP address when the virtual machine has started:


We then use the Connect-UCSM cmdlet to connect to the UCS Manager:


The default credentials for the UCS Emulator is config/config.

Next we can start exploring cmdlets like Get-Blade and Get-Vlan. Note that by default the cmdlets outputs a lot of information for each object, so I`ve picked out a few properties to show using Format-Table:


Going further it`s easy to automate things like adding VLAN and assigning it to a vNIC template:



Although the PowerShell coverage isn`t 100% yet, it`s possible to administer all aspect of the UCS directly through the XML API from PowerShell using the Invoke-XmlCommand cmdlet.



Cisco Unified Computing

A Platform Built for Server Virtualization: Cisco Unified Computing System

Cisco Unified Computing Forums

Automating Cisco UCS Management with Windows PowerShell

PowerScripting Podcast – Josh Heller from Cisco on UCS and PowerShell

Cisco UCS Manager XML API Programmer’s Guide

Cisco UCS Manager API Management Information Model

Cisco Developer Network: Unified Computing

Managing your Cisco UCS from an iPhone or iPad

July 23, 2011 Posted by | Scripting, Virtualization, Windows PowerShell | , , | 2 Comments

Adding printer drivers from a print server using Windows PowerShell

Managing printer drivers in a Remote Desktop Services (formerly Terminal Services) environment can be a challenge for administrators. There are many ways to ease this challenge, including third party solutions such as ThinPrint and UniPrint. When “thick” drivers are used on the RDS servers, all printer drivers must be installed locally on every server. Citrix XenApp has a printer driver replication feature which makes it possible to distribute printer drivers from a source server to one or more destination servers in a farm.

There might be situations where none of the mentioned solutions can be used for various reason, i.e. financial costs. A common way to solve this problem is to map all printer connections from a specified print server using administrative credentials during the initial setup of each RDS server. This solves the problem, but it can be time consuming as all printers that uses the same driver is being installed. Even though the driver is already installed on the local computer, it takes some time to process each printer connection.

I recently faced this challenge, as the installation of all printer connections from a few specified print servers took 30-40 minutes using a legacy script. I then wrote an advanced function in PowerShell to make the procedure more effective. This was accomplished by installing a printer connection only for unique printer drivers.
An example: A print server has 500 shared printer objects, while there is only 10 unique printer drivers. It would make more sense to add a printer connection (in order to install the driver) to 10 printer objects rather than 500, given the time consumed by installing a printer connection.

The function is available for download from here.

Sample usage and output:




There is a switch option added to the function called Clean. If this parameter is specified the function will also remove all mapped printer connections for the current user.

The function doesn’t`t provide any log options. However, it produces PowerShell objects, so it would be easy to pipe the output to a file.
An example on how to export the output objects to a csv-file:


But what about printer drivers added to the print servers after the function is run on an RDS server? One way to solve this could be adding the PowerShell function to a script-file which is set up as a scheduled task to run i.e. once a day on every RDS server.  If the scheduled task is set up using Group Policy Preferences, it will be automatically created on every new RDS server that is added later on. Beside scheduling the task to run at specified intervals, the print server administrator may also invoke the scheduled task remotely on every RDS server whenever a new print driver is added to a print server. The details on how to do this is previously described in this blog-post.

Since the function might be run several times on the same computer, it also checks if the driver to be installed is already in place on the local computer. This means that after the first run, only printer drivers added to the print server after the first run is actually installed. This makes the script more effective, and depending on the number of shared printer objects on the specified print server, it shouldn’t`t run for many seconds.

Coming back to the before mentioned example (~600 printer objects, ~50 unique drivers) where it took 30-40 minutes to install printer drivers from a print server, when using the Add-PrinterDriver PowerShell function the execution ran for 4 minutes. After the first run, subsequent executions ran for  20 seconds.

July 3, 2011 Posted by | Print management, Remote Desktop Services, Scripting, Terminal Services, Windows PowerShell, Windows Server 2008, Windows Server 2008 R2 | , , , , | 5 Comments

Use Windows PowerShell to get antivirus product information

Windows Security Center has been available in Windows client operating systems since Windows XP SP2. This is a useful feature for monitoring the overall for security status for the system, including antivirus, antimalware and firewall protection. In situations no monitoring software like System Center Operations Manager is in place to monitor the security health on client computers, one option is to use Windows Management Instrumentation. There is a WMI namespace called root\SecurityCenter2 which exposes information from the Windows Security Center, like what antivirus product is installed on the system.

I`ve created PowerShell function to query computers for information on what antivirus is installed as well as the current status for antivirus definitions and real-time protection:

function Get-AntiVirusProduct {
param (
[parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)

$AntiVirusProduct = Get-WmiObject -Namespace root\SecurityCenter2 -Class AntiVirusProduct  -ComputerName $computername

#Switch to determine the status of antivirus definitions and real-time protection.
#The values in this switch-statement are retrieved from the following website:

switch ($AntiVirusProduct.productState) {
"262144" {$defstatus = "Up to date" ;$rtstatus = "Disabled"
"262160" {$defstatus = "Out of date" ;$rtstatus = "Disabled"
"266240" {$defstatus = "Up to date" ;$rtstatus = "Enabled"
"266256" {$defstatus = "Out of date" ;$rtstatus = "Enabled"
"393216" {$defstatus = "Up to date" ;$rtstatus = "Disabled"
"393232" {$defstatus = "Out of date" ;$rtstatus = "Disabled"
"393488" {$defstatus = "Out of date" ;$rtstatus = "Disabled"
"397312" {$defstatus = "Up to date" ;$rtstatus = "Enabled"
"397328" {$defstatus = "Out of date" ;$rtstatus = "Enabled"
"397584" {$defstatus = "Out of date" ;$rtstatus = "Enabled"}
default {$defstatus = "Unknown" ;$rtstatus = "Unknown"

#Create hash-table for each computer
$ht = @{}
$ht.Computername = 
.Name = $AntiVirusProduct.displayName
$ht.ProductExecutable = $AntiVirusProduct.pathToSignedProductExe
$ht.‘Definition Status’ = 
.‘Real-time Protection Status’ = $rtstatus

#Create a new object for each computer
New-Object -TypeName PSObject -Property $ht



Sample output:


The root\SecurityCenter2 namespace isn`t documented on MSDN, so it`s hard to find information on the properties and methods we find in the different classes in the namespace.

The productstate property of the AntiVirusProduct class is exposed as a integer value, which needs to be converted to a hexadecimal value. Then the different bytes in the value contains information in regards to definition updates and real-time protection. More information on this is available here. I haven`t found a complete reference to all possible values, the best I could find is available here.

The above function outputs Windows PowerShell objects, so it`s possible to filter the output i.e. based on the “Definition Status” property.  The computername parameter also supports value from pipeline to make it easy to get the computers to query from i.e. Active Directory without using a foreach construct. A few examples:

#Get antivirus product information for all computers in the specified OU/container
Import-Module ActiveDirectory
Get-ADComputer -SearchBase "CN=Computers,DC=contoso,DC=local" -Filter * | Select-Object -ExpandProperty name | Get-AntiVirusProduct

#Filter using Where-Object to get all computers where the Definition State is not "Up to date"
Get-AntiVirusProduct -computer (Get-Content computers.txt) | Where-Object {$_.‘Definition Status’ -notlike ‘Up to date’}


The root\SecurityCenter2 namespace is available on Windows Vista SP1 and above. Windows Security Center is not available on server operatingsystems, meaning that the root\SecurityCenter2 namespace also isn`t available. In Windows XP SP2 the namespace is called root\SecurityCenter, but the properties are not the same as in root\SecurityCenter2. It`s possible to get the function work on Windows XP, but you would need to customize it to match the properties available in the root\SecurityCenter namespace.

I would encourage you to add error handling before using this function in a production environment, i.e. adding a test to check if the remote computer is available and allowing RPC-communication. If you would like to explore the other classes in the root\SecurityCenter2 namespace for working with firewall and antispyware products, you can start by exploring the available classes like this: Get-WmiObject -Namespace root\SecurityCenter2 -List

June 12, 2011 Posted by | Desktop management, Scripting, Windows 7, Windows PowerShell, Windows Vista | , | Leave a comment

Enable Persistent Mode for Cluster Resource Groups using the PowerShell Failover Clustering module

In Failover Clustering in Windows Server 2008 R2, Persistent Mode is intended to allow resource groups to come online on the node which an admin last moved them to. This setting is enabled by default when a virtual machine is created with Failover Cluster Manager. If you create virtual machine via System Center Virtual Manager this setting is not enabled.

By default, cluster roles have this setting disabled, except for Hyper-V virtual machine cluster roles, which have this enabled by default. This setting is useful when the cluster is shutdown and later started, in order to better distribute the resources across the nodes and allow them to come online faster, as they were likely spread across the nodes before the cluster was offlined. Otherwise, all the resources will attempt to restart on the first nodes which achieve quorum and compete for resources. This only applies to a group if it did not failover after being placed by the administrator. If a group has failed over since the last administrator placement, it is brought online on the node which the administrator last move it to.

Reference and more info regarding the Auto Start, Persistent Mode and Group Wait Delay features is available on the Clustering and High-Availability blog.

Auto Start can be enabled/disabled in bulk by marking all Cluster Resource Groups in Failover Cluster Manager and selecting “Enable auto start”/”Disable auto start”.

For Persistent Mode the only available option in Failover Cluster Manager is to right click each Cluster Resource Group and selecting/de-selecting the checkbox for “Enable persistent mode”:


To change this setting for all Cluster Resource Groups in an automated fashion you can use the Failover Cluster module for PowerShell, which I wrote an introduction to here.

Here is an example on how you can do this:

Import-Module FailoverClusters
$clustergroups = Get-ClusterGroup -Cluster cluster01.domain.local
foreach ($clustergroup in $clustergroups) {
#To enable persistent mode: x To disable persistent mode: 4294967295

Although you can change the Auto Start setting in bulk in Failover Cluster Manager you might also want to do this in an automated fashion:

Import-Module FailoverClusters
$clustergroups = Get-ClusterGroup -Cluster cluster01.domain.local
foreach ($clustergroup in $clustergroups) {
#To enable Auto Start: 1 To disable Auto Start: 0

You can also change the Group Wait Delay cluster-wide property from the PowerShell Failover Clustering module, how to do this is explained in the above referenced blog-post from the Clustering and High-Availability blog.

For the next version of System Center Virtual Machine Manager I would expect that Persistent Mode is enabled by default, since Microsoft do recommend customers to enable this setting.

Update 08.12.2011: The value of the DefaultOwner property for configuring Persistent Mode is the number of the node you want to be the default owner. In example a value of 1 means the first node in the cluster.

June 3, 2011 Posted by | Failover Clustering, Hyper-V, Hyper-V R2, Scripting, Windows PowerShell, Windows Server 2008 R2 | , | 3 Comments