Learn How to Create Custom Column Heads for PowerShell Out-GridView

One of my co-workers, who shall remain nameless (but it rhymes with Jalcolm Meffrey), asked a good question today-namely “How do I take this custom formatting from a “Format-Table” command and use it in the gridview control (Out-GridView). It took me a couple of minutes, but the internet bestowed her bounties upon me once again. And, no I’m not talking about going to the hoochie-mama sites.

I found this old posting from Ed Wilson, “The Scripting Guy”. Thank you Ed!

Learn How to Create Custom Column Heads for PowerShell Out-GridView – Hey, Scripting Guy! Blog – Site Home – TechNet Blogs.

For those of you who won’t/can’t be bothered to read it, basically it boiled down to “Don’t use format-table, use select-object, and build your columns using the -f operator syntax”.

With some minor modifications, you turn this:

Get-CimInstance -ClassName Win32_LogicalDisk  |
Where-Object DriveType -eq 3 |
Format-Table @{n=’DriveLetter’;e={$PSItem.DeviceID}},
             @{n=’FreeSpace(GB)’;e={$PSItem.FreeSpace / 1GB};formatString=’N2′},
             @{n=’Size(GB)’;e={$PSItem.Size / 1GB};formatString=’N2′},
             @{n=’Type’;e={$PSItem.Description};width=5} -AutoSize

Into this:

Get-CimInstance -ClassName Win32_LogicalDisk  |
Where-Object DriveType -eq 3 |
Select-Object -Property @{Label=’DriveLetter’;Expression={$PSItem.DeviceID}},
    @{Label=’FreeSpace(GB)’;Expression={“{0:N2}” -f ($PSItem.FreeSpace / 1GB)}},
    @{Label=’Size(GB)’;Expression={“{0:N2}” -f ($PSItem.Size / 1GB)}},
    @{Label=’Type’;Expression={$PSItem.Description}} |  Sort-object ‘FreeSpace(GB)’ | Out-Gridview

 

If you were so inclined, you could swap out “Out-Gridview” for “Format-Table” or whichever output command you needed.

Thanks Jalcolm (if that is your real name) for giving me something to dig into and solve!

 

Aussie! Aussie! Aussie! Joy! Joy! Joy!

If you’re interested in Microsoft’s cloud offerings, then you’ve probably been aware that they have been building two Australia datacentres for their cloud services (Azure and Office365). The good news is that they went live over the weekend. You can now choose Australia East and Australia Southeast as Azure locations. Now, what this will mean for NZ based Azure clients remains to be seen. Time will tell how services hosted in these datacentres will perform, especially around provisioning and management. If you’ve spent any time with Azure you’re aware that not all datacentres are created equal, or at least they don’t appear that way. I’m hoping that response is closer to what I get when I use US/Europe locations and less like what I get when I use Asia locations.

But before all you down under cloud subscribers rush out to change the location of your storage accounts, vms, services etc., remember that not all parts of Azure get rolled out across all locations at the same time. Here’s a quick example.  Below you can see that I ran the get-azurevmimage PowerShell cmdlet to see what VM images are available to me to create virtual machines. I didn’t really care what the images are, I just wanted to see how many there were.  Then I ran the command again and added a filter to make sure that I only included images that are available in either of the two Australia locations.  There’s about a third of the VM Images that are not available in the Australia locations.

Now, what exactly does this mean for you? It depends. Maybe nothing. Maybe everything. But it might be worth taking a look around the details of the resources and features before you start moving stuff over willy-nilly. Doubly so if you are script and preview feature dependent in your Azure consumption. Measure twice, cut once.

However, on the whole I think this will be a good think for Microsoft’s cloud customers in this neck of the woods. For both technical and non-technical reasons. To find out how Microsoft NZ thinks this will benefit NZ customers, click here: http://www.microsoft.com/en-nz/news/NewMicrosoftAzureGeo.aspx.

 

 

 

 

 

 

Using PowerShell to Register MOC VMs

A few weeks ago my friend Telmo blogged about a very elegant solution for handling the VMs that MOC courses use. I was really impressed with what he came up with.  If you are an MCT then I would definitely recommend reading that post. Thanks Telmo!

You can find it here: http://telmosampaio.wordpress.com/2013/09/01/bulk-import-vms-for-moc-classes

That made me think about some simpler scripts that I have written that may also be of use for registering VMs for any environment. I did make some tweaks to use it specifically for registering MOC VMs, but these scripts are easily portable for any environment where you want or need to bulk import VMs.

The code below gives you a script that will do two main tasks:

1. Create some standardized private virtual switches in Hyper-V. The names match the names that the vast majority of MOC VMs use. So there are more switches in there than you would likely need, but it is easily adjusted to modify the name and number of switches being created.

2. Enumerate and import all the VMs that are found in a given path. For this to work you need to feed the name of the parent folder path where all of the VMs reside. If you forget to specify a path when you run the script, there is a basic inline help that is triggered explaining the syntax.
I put a 5 second delay between each import. I have found that if I don’t then I sometimes get strange errors on the VM imports. It feels like the script is running faster than the Hyper-V administration services can process the requests. When I put in a 5 second delay, that problem basically disappears.

I’ve put the code in here twice, one version for Windows 2008 (& R2) Hyper-V servers and a version that will run on Windows Server 2012.

Windows Server 2008 Hyper-V
(requires that the Hyper-V PowerShell module from codeplex has been installed. I didn’t get fancy by doing a check, I just load it up in the first line.)

import-module HyperV
If (!$args){
” “
“Usage of the script is as follows:”
“<path>\importvm.ps1 <VM parent folder>”
” “
“<VM Parent folder> is the path to the directory that holds the Hyper-V virtual machine directories.”
“This script will automatically register all VMs that are in that path and create two private virtual switches if required.”
}
else{
#Create the private network switches
“Create the ‘Private Network’ and ‘Private Network 2’ virtual switches if required”
$switchlist = get-vmswitch | where {$_.Name -ilike “Private Network*”}
If (!$switchlist){
new-vmprivateswitch “Private Network”
“Private Network has been created.”
new-vmprivateswitch “Private Network 2”
“Private Network 2 has been created”
new-vmprivateswitch “Private Network A”
“Private Network Ahas been created.”
new-vmprivateswitch “Private Network B”
“Private Network B has been created”
}
else{
“Private Network switches may already exist. Confirm that the one you require is in the list below.”
“If it is not, you may need to create it manually.”
$switchlist
}
#List the folders in the Drives directory for the course and map them to an array.
$vms = get-childitem $args | where {$_.mode -eq “d—-“}
#Parse the array and import each VM
foreach ($vm in $vms){
import-vm -path $vm.FullName
start-sleep -Seconds 5
}
get-vm | format-table Name,State,Status -AutoSize

}

Windows Server 2012

If (!$args)
{
” “
“Usage of the script is as follows:”
“<path>\importvm.ps1 <VM parent folder>”
” “
“<VM Parent folder> is the path to the directory that holds the Hyper-V virtual machine directories.”
“This script will automatically register all VMs that are in that path and create two private virtual switches if required.”
}
 
else
{
#Create the private network switches
“Create the Microsoft Learning virtual switches if required”
$switchlist = get-vmswitch -SwitchType Private | where {$_.Name -ilike “Private Network*”}
If (!$switchlist)
{
new-vmswitch “Private Network” -SwitchType Private
“Private Network has been created.”
new-vmswitch “Private Network 2” -SwitchType Private
“Private Network 2 has been created.”
new-vmswitch “Private Network A” -SwitchType Private
“Private Network A has been created.”
new-vmswitch “Private Network B” -SwitchType Private
“Private Network B has been created.”
}
else
{
“Private Network switches may already exist. Confirm that the one you require is in the list below.”
“If it is not, you may need to create it manually.”
$switchlist
}
#List the folders in the Drives directory for the course and map them to an array.
$vms = Get-ChildItem $args -Recurse | where Name -ilike “*.exp”
 
#Parse the array and import each VM
foreach ($vm in $vms)
{
“`nImporting {0}” -f $VM.FullName
import-vm -path $vm.FullName
start-sleep -Seconds 5
}
 
get-vm | format-table Name,State,Status -AutoSize
 
 
}
 

Hopefully, this will get you started down the path to scripting more of your common Hyper-V tasks.

Cheers,

James

Enabling Data Dedup in Windows 8

I run a lot of Hyper-V VMs on my Windows 8 laptop, and my second hard drive is getting full, with all of my inactive vhd files.  I was thinking “It’s too bad Windows 8 doesn’t have volume deduplication like Windows Server 2012.” But I decided to have a bit of a nosy around the internet to see if there was a 3rd party solution.

Lo and behold! (And really, it shouldn’t surprise me by now, but it did a little bit anyway.) I found a really useful site that taught me how to hack the 2012 Dedup into my Win8 laptop.

NOTE: Doing this will put your computer in an unsupported state (due to mixing and matching SKUs of the windows code). It is up to you to assess the risk/reward equation of these actions.

Here’s the link:

http://www.scconfigmgr.com/2013/04/13/enable-deduplication-for-your-lab-environment-in-windows-8/

One of the dism commands is a little hard to copy/paste from his website, so here it is:

dism /online /add-package /packagepath:Microsoft-Windows-VdsInterop-Package~31bf3856ad364e35~amd64~~6.2.9200.16384.cab /packagepath:Microsoft-Windows-VdsInterop-Package~31bf3856ad364e35~amd64~en-US~6.2.9200.16384.cab /packagepath:Microsoft-Windows-FileServer-Package~31bf3856ad364e35~amd64~~6.2.9200.16384.cab /packagepath:Microsoft-Windows-FileServer-Package~31bf3856ad364e35~amd64~en-US~6.2.9200.16384.cab /packagepath:Microsoft-Windows-Dedup-Package~31bf3856ad364e35~amd64~~6.2.9200.16384.cab /packagepath:Microsoft-Windows-Dedup-Package~31bf3856ad364e35~amd64~en-US~6.2.9200.16384.cab

And since there is no gui for dedup in Windows 8, here’s a link to the online PowerShell help for the dedup cmdlets:

http://technet.microsoft.com/en-us/library/hh848450.aspx

I Got Picked for TechEd! And there was much rejoicing. yay.

I was chosen to speak at TechEd New Zealand this year. I’ll be doing some exam-prep sessions and helping out in the Certification Centre on what I like to call “Day 0”, Tuesday prior to the opening Keynote speaker. I’m also doing a session on “Top 10 Ways to Conquer Your Fear of PowerShell” during the main event.

If you are thinking of going and haven’t registered yet, get yourself to the TechEd NZ site for all the details. I hope to see you there!

Adding the Lync Import-CsRgsConfiguration and Export-CSRgsConfiguration cmdlets to your Lync Management Shell

Sorry I missed a week. L I’ll make up for it with multiple posts this week. I promise.

First post isn’t a major topic, but it does address a minor annoyance of mine: having to run a PowerShell script to add the Import-CSRgsConfiguration and Export-CSRgsConfiguration cmdlets. When I fire up the Lync 2010 Management Shell, I want all the cmdlets I need available to me.

So here’s the fix:

  1. If you haven’t already done so, download and install the Lync 2010 Resource Kit tools. Assuming that you likely have put them on a Lync server (and in the default location), you should have a folder C:\Program Files\Microsoft Lync Server 2010\Reskit.
  2. From that folder, find the PowerShell script that adds the Response Group Service import and export cmdlets. It is cleverly named RgsImportExport.ps1. Copy that file.
  3. Navigate to the Lync Management Shell module directory, C:\Program Files\Common Files\Microsoft Lync Server 2010\Modules\Lync. Paste the RgsImportExport.ps1 file into that folder.
  4. In that same directory there should be a file named Lync.psd1. Find that file and open it for editing.
  5. Find the “Nested Modules” line and add ,”RgsImportExport.ps1″ to the end of that line. When finished the line should look like this:
    NestedModules=”Microsoft.Rtc.Management”,”Microsoft.Rtc.Rgs.Management”,”init.ps1″,”RgsImportExport.ps1″
  6. Save the changes and close the file.
  7. From here on out, when you open the Lync Management Shell on the computer to which you’ve done this, the Import-CSRgsConfiguration and Export-CSRgsConfiguration cmdlets should be loaded and at your disposal.

One thing to note, if you want the cmdlets available on multiple Lync servers you will need to do the steps above on each server.

Managing PowerShell 3.0 Updateable Help

***Author’s Note:  I was in a rush and didn’t properly preview the graphics for this post in my browser. If you are finding them hard to read, try using your browser’s zoom-in capability. I found that if I zoomed in a bit, the text in the graphics became legible.  Sorry. :(***

Updateable Help is one of the new features of PowerShell 3.0. The biggest benefit of Updateable Help is the improved accuracy of the inline help, especially across patches/service packs/module additions. While I have to admit that the inconsistencies that would creep in were not a major issue for me personally, I can see how it would create frustration. So we’re going to look at some of the basics of using and managing help for PowerShell 3.0

Using Help

First first—I’m going to assume that if you’re reading this blog that you don’t me to tell you how to get help for PowerShell cmdlets. But you will notice that if you have a computer that has not gotten updated help (and out of the box, it won’t have), you’ll see that a normal Get-Help cmdlet will return the basic list of switches.

You’ll also notice that in the Remarks Section it tells you that the full help has not been downloaded. When you add the –Detailed switch to your Get-help command, the results are not much different. Each switch gets its own line, but the detail you are likely looking for is not there. Again, the Remarks section is telling you to get the updated help. Obviously, getting the updated help is a valid option, but not the only option.

There is a new switch for Get-Help, -Online. Assuming that the computer from which you are running powershell has an internet connection, this allows you to get the detailed help you need, without forcing a full update of the help files. It will open a web browser session and take you to the TechNet Library page for the help for the cmdlet you indicated.

Getting the Help onto Your Machine

That might be fine for module-specific cmdlets that I don’t use often, or while tweaking a script on a server (as opposed to writing a script in whatever environment you normally use), where you don’t really need the help there all the time. However, on the machine that you DO want the help at hand more readily you really want the help files on your machine. Microsoft has provided Update-Help for this.

For the help to update properly I’ve found that I need to make sure I am running the PowerShell console under the Administrator User Account Control (right-click, Run As Administrator).

Once I’ve done that, then I can keep it really simple with the cmdlet Update-Help

If you look at my results you’ll notice a couple of things.

  1. I didn’t run this with the appropriate UAC so some of the help files didn’t update. Easily fixed. Open a PowerShell Console in the correct context and that goes away.
  2. There were a couple of other errors about DTD files and incorrect URIs. Those have to do with the help files not being available properly from the Microsoft servers. Instances of those errors should drop over time. If you want a detailed explanation of what exactly is happening, read this: http://bit.ly/SoMnIB . It explains it all quite well. So we’ll ignore those for the moment.

There are additional switches for the Update-Help cmdlet that allow you more control over what is going on. For instance, the –Module switch allows you to update the help only for a specific module. Take the time to explore those switches and see which ones may be of use to you.

How Do I Update Help if my server doesn’t have access to the Internet?

That was the first question that popped into my head when I first came across this idea of Updateable Help. The solution is reasonably straightforward and done in four steps.

  1. From a machine with internet access (and the appropriate modules you want the help for) run Update-Help.
  2. From the same machine run the Save-Help cmdlet. Save-Help will copy the help files to a directory of your choosing. Much like Update-Help, you can use a –Module switch to only save the help files for a specific module. The main parameter you need to provide is the parent directory where you want the files saved. In the example below I only saved the help for the Hyper-V module.
  3. Somehow transport the directory with all the help files to the computer(s) that don’t have internet access. Network share, portable drive of some sort, whatever works for you really.
  4. On the isolated machine, run Update-Help –SourcePath <path to folder that holds the help files> -Module <Name(s) of modules that have help files in that directory>

You can see in the screen shot below how steps 1-3 work. You will notice that I created a folder to hold the help files, and then ran Save-Help only for the Hyper-V module (for the sake of simplicity). I then displayed what files were put in the destination path.

  1. Once I had done that I can transfer the .cab and .xml files to the remote machine. In this instance I created a folder called “HyperVHelp” on the destination machine and put the files that folder. Once I had done that I ran Update-help. You will note that I used the –Module switch to keep it simple. Had I not done that, my screen would have been filled with red as it tried and failed to update the help for all known modules. The Hyper-V help would still update, but all the error messages are a bit off-putting. So I only updated the module I had help files for.

I ran the Update-Help command a second time, just to show you what can happen if I try to update help files that are currently up-to-date. As you can see, nothing major happens, so there’s no big concerns in that space.

Review

As you can see, the process for updating and managing PowerShell’s help is not terribly difficult. With a bit of practice and planning you should be able to develop and implement a plan for keeping your PowerShell inline help current and useful.