Seattle PowerShell Script Club – Thurs Nov 19th

I am happy to announce that the Seattle PowerShell Script Club will be meeting on Thursday, Nov 19th at 818 Stewart St, Seattle WA from 7:00 PM to 9:00 PM and a good chance of heading out for beers when we’re done.

James Brundage has released his Windows PowerShell Pack. James and I thought we would start off with a couple examples of how to use WPK to create rich WPF based visualizations of data that is collected with PowerShell.  From there, we can go pretty much anywhere you want to.

Please leave a comment if you plan on attending. Please Register Here

Hope to see you there!

Andy

iSCSI, iscsicli, and WMI, Oh My!

I have been doing a lot of work with clustering Hyper-V lately and our storage is all iSCSI. Without going into all the gory details, iSCSI supports multipathing. My iSCSI SAN has two heads, each head has 3 NIC’s. On my Hyper-V hosts, we have two NIC’s that are used for iSCSI. Each NIC has a “target” for each IP on each head. Some quick math and you realize that’s a lot of connections, and a pain the butt to configure when you have a ton of nodes using this configuration. So naturally I started looking at scripting and didn’t find any cmdlets to work with iSCSI. However, there is a tool called ISCSICLI.

To add a an iSCSI target you can use the QAddTargetPortal command. Assuming your SAN’s iSCSI IP address is 192.168.168.10 you would use this command

iscsicli QAddTargetPortal 192.168.168.10

That’s fine, but what if you want to specify a source IP Address. This is pretty straight forward using the iSCSI Control Panel. In advanced settings you can choose both the “Microsoft iSCSI initiator” and the Initiator IP.

image

It turns out QAddTarget is “Quick Add Target” which gives you very few options. You can also use AddTargetPortal.

image

So there are a few things you should know. TargetPortalAddress is the IP address of the SAN you are connecting to. TargetPortalSocket is not really the socket, but just the port number, which is typically 3260. Normally a socket consists of an IP Address and a port number. The HBA name actually refers to Initiator Adapter. In this case it would be “Microsoft iSCSI Initiator.” Finally we get to the Port Number. It turns out that this port number is what is mapped to a source IP Address. The problem was that I could not find any documentation telling me how this port number was associated with an IP address on the server. At first I thought it might be the index of an interface, but quickly learned that was not the case, as you could have multiple IP’s on one interface anyway.

When something doesn’t show up in the GUI, I go exploring with WMI and PowerShell. It turns out there is a ton of iSCSI info buried in the root\wmi namespace

image

Looking around I found a msIScsi_portalinfoclass.

image

The PortalInformation property looked like it had some good info in it as well so I went digging into that.

image

Sweet! I see IPAddr and a port number. This looks promising. But when I crack open IPAddr I don’t see what I was expecting to see

image

Seriously.. since when is 1865687562 an IP V4 address? I was so close and then remembered that there is an IPAddress type in System.Net. Let’s just test something out here.

image

Woo Hoo! Given this I can now write my Get-IscsiPortNumber function in PowerShell.

001
002
003
004
005
006
007
Function Get-IscsiPortNumber {
$query = "select portalinformation from MSiSCSI_PortalInfoClass" 
$portalInfo = get-wmiobject -namespace root\wmi -query $query
$eScriptBlock ={([Net.IPAddress]$_.ipaddr.IPV4Address).IPAddressToString}
$customLabel = @{Label="IpAddress"; expression = $eScriptBlock}
$portalInfo.portalInformation | select port,$customlabel
}

Now that we have that info, we can use it in our iscsicli command

iscsicli addtargetportal 192.168.168.10 3260 ROOT\ISCSIPRT\0000_0 2 * * * * * * * * * *

Oh yeah, the ROOT\ISCSIPRT\0000_0 means MS Iscsi Initiator. There are some login flags as well that you would probably want to set for multipath as well.

image

So if your port number is 2 the final command would be

iscsicli addtargetportal 192.168.168.10 3260 ROOT\ISCSIPRT\0000_0 2 * 0x2 * * * * * * * *

Comparing Installed Hotfixes on Servers

This week I had the need to scan several systems and see which hotfixes were installed on which machines and also figure out which hotfixes I needed to install to make sure all machines were identical. Now that PowerShell V2 has been RTM’d in windows 7 and is included in the Release Candidate of the Windows Management Framework, I am going to go with V2 features. However, this script could be ported to V1 if need be.

As I was thinking about this problem, there were a few tools in the toolkit I thought I could use. The first is the new cmdlet, get-hotfix. This is just a wrapper of Win32_QuickFixEngineering but its nice to have it abstracted up to the cmdlet level. The second tool I thought of using is compare-object. I have known about this cmdlet but haven’t had a real opportunity to use it much. It’s actually very powerful but it does take a bit of neuron firing to wrap your head around how it works.

The way I set this is up allows me to compare two servers.  I also have a credential parameter that is used to access servers so I can do my part in supporting the principle of Least Privilege and not be logged in with a Domain Admin account all the time.

So I pull the list of installed hotfixes from each server and select only the HotfixId property. This will make using the compare-object cmdlet a bit easier. If we do a get-member on compare-object we see that it outputs a PSObject with 2 noteproperties, a InputObject and a SideIndicator.

image

From the help on compare-object we find this description of the SideIndicator property:

The result of the comparison indicates whether a property value appeared only in the object from the Reference set (indicated by the <= symbol), only in the object from the Difference set (indicated by the => symbol) or, if the IncludeEqual parameter is specified, in both objects (indicated by the == symbol).

Well that does the job but frankly its output is difficult to easily interpret at first glance. The beauty of PowerShell is that if you really don’t like the way something works, you can easily work around it. In this case, I created a new array of custom objects that have three properties: KB, the name of the first server, and the name of the second server. (Lines 19 and 22)

Then I foreach’d (the new verb of the day) through the collection of compared hotfixes and switched on the “SideIndicator” property. I did this to make the output more clear so users of the script would not have to interpret all the arrows and equal signs generated by compare-object.

Here is a sample of the output:

image

I used Write-Host to generate some text output but I also get back an object that I can slice and dice later on.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
Function Compare-InstalledHotfix {
param (
[parameter(Mandatory=$true,Position=0)]
$server1,

[parameter(Mandatory=$true,Position=1)]
$server2, 

[parameter(Mandatory=$true,Position=3)]
[Management.Automation.PSCredential]
$credential
)

$server1HotFix = get-hotfix -computer $server1 -Credential $credential | select HotfixId
$server2HotFix = get-hotfix -computer $server2 -Credential $credential | select HotfixId

$comparedHotfixes = compare-object $server2HotFix $server1HotFix -IncludeEqual

$result = @();

foreach ($c in $comparedHotfixes) {
    $kbinfo = "" | select KB,$server1,$server2
    $kbinfo.KB = $c.InputObject.HotfixId
    switch ($c.SideIndicator)
    {
    "==" {
            write-host -ForegroundColor Green "Both servers have $($c.InputObject.HotfixId)"
            $kbinfo.($server1) = $true
            $kbinfo.($server2) = $true
            $result += $kbinfo
         }
        
    "=>" {
            write-host -ForegroundColor Yellow "$server1 has $($c.InputObject.HotfixId) but $server2 doesn't"
            $kbinfo.($server1) = $true
            $kbinfo.($server2) = $false
            $result += $kbinfo
          }
         
    "<="  {
            write-host -ForegroundColor Magenta "$server2 has $($c.InputObject.HotfixId) but $server1 doesn't"
            $kbinfo.($server1) = $false
            $kbinfo.($server2) = $true
            $result += $kbinfo
          }
    } # End Switch
  } # End foreach
   $result
 } # End Function

This code is also available on the TechNet Code Gallery and up on PoshCode

Debugging using PowerShell ISE102

In my last post I gave a high level overview of how to get started with debugging in PowerShell 2.0, using the new Integrated Scripting Environment. In this installment, we are going to explore some of cmdlets that can be used to manipulate breakpoints.

First,  lets do some discovery. Whenever I am looking for cmdlets to work with something in particular, i use the get-command cmdlet with wildcards to help my search.

image

So from this it looks like we can get, set, enable, disable, and remove breakpoints. When we are setting breakpoints, you can specify the line and column you want to break on, but that can get really tedious. This is what the ISE does for you automatically when you toggle breakpoints. However, I find it much more useful to break when ever a variable is accessed.

Let’s use a basic function to demonstrate this.We’ll create a function foo and then set a breakpoint for the $c variable.

image

When we execute this code and call function foo, we get the output below. Notice that $a and $b is set, and that we break when we hit $c. One thing to note, when we specify the variable, we do not use the $ in front of the variable. This is the same as specifying the –outvariable common parameter for other cmdlets.

image

Last but not least, let’s take a look at how to navigate this “nested” prompt. If you type “?” or “h”, you will get the following information It is interesting that the “nested>” prompt displays this when you hit “?.” Under normal circumstances, the “?” is an alias for where-object, as we can see when we type ? at a normal prompt.

image

I hope this helps you with debugging your scripts.

Debugging using PowerShell ISE 101

I have always found the origin of words to be fascinating.  Apparently, the terms bug and debugging in regards to computers are attributed to Admiral Grace Hopper in the 1940’s.

While she was working on a Mark II Computer at Harvard University, her associates discovered a moth stuck in a relay and thereby impeding operation, whereupon she remarked that they were "debugging" the system.

When I first started scripting and writing a little code, the concept of debugging something seemed really hard. However, I have found that with a few simple steps I can debug most of my scripts pretty quickly.

Ninety nine percent of the time, debugging scripts requires being able to watch a variable at some point in a script or a function. Have you ever written a function and thought, “If only I knew what x was before y started messing with it?”

The PowerShell Integrated Scripting Environment makes this pretty easy. You can set a breakpoint on any line in the ISE using the Debug Menu and choosing “Toggle Breakpoint.” or by using the F9 shortcut key.

image

When you toggle a breakpoint on and then run the script, the script will stop at that point. You should note that at this point, the highlighted line has not been executed yet.

Here’s what it looks like when you hit a breakpoint. You get thrown into a nested prompt where you can poke around and look at any variables you want to. Notice the >>> prompt and notice $b has not yet been set, but $a has.

 image

Now that you are paused right around the line of code you want to check out, you can use the “Step Into” Feature.

This will execute the next line of code in the script (the highlighted line) and then stop.

image

Now you can see that $b has been set but $c doesn’t have a value yet.

image

You can continue to step through as much as many lines as you need to until you see something that is not quite right.

This is just the beginning of what we can do in regards to debugging scripts and functions. In the next couple weeks I plan to share more as I learn about debugging and the ISE. Just to whet your appetite, you can run the command get-command –noun psbreakpoint to see what kinds of goodies await!

PowerShell 2.0 for Vista and Server 2008

The release candidate for the Windows Management Framework is now available on the Microsoft Connect web site. The framework includes PowerShell 2.0, WinRM 2.0 and BITS 4.0. There are actually two downloads, one for PS and WinRM and another for Bits that make the whole framework.

Download it here:

https://connect.microsoft.com/windowsmanagement/Downloads

Seattle PowerShell Script Club #2 9/3/2009

I am happy to announce that Avanade will be hosting the second Seattle PowerShell Script Club on Thursday, September 3rd at 7:00 PM. You can register here.

What is a PowerShell Script Club?

Script Clubs are like a hands on lab with no set topic or teacher. You bring an idea for a script, and ask your fellow PowerShell users for help getting the script written.

James Brundage, from the PowerShell at team at Microsoft, will be joining us for the evening.

About Seattle PowerShell Script Club

1. You Always Talk About Script club
2. You Always Talk About Script Club
3. If Someone asks for Help, And You Can Help, You Help
4. Two People Help One Person at One Time
5. One Module Per Person Per Night
6. All Scripts, All PowerShell
7. Scripts will be as short as they can be
8. If This is your First time at Script Club, You Have to Script

Dynamic Binary Modules Follow Up

There was a very interesting post over on the PowerShell team blog on Dynamic Binary Modules where Nigel Sharples describes how to run a cmdlet on a remote machine if you have the source code to the cmdlet and don’t want to deal with any intermediate assembly files to clean up.

I went and tried to do this straight away on my local machine without the remoting bit. I copied some cmdlet source code from MSDN. As a Systems Engineer, I haven’t written many compiled cmdlets in C# but I have edited a few for my liking and written one or two when script just wouldn’t cut it. One thing I have learned is that you always need a Snapin to register your cmdlet. So you have your namespace with a class for your snapin and then a class for each cmdlet that you create.

The bottom line here is that with dynamic modules you don’t need to create a Snapin class for your cmdlet. The only other tweak is that I used the –language parameter on Add-Type to specify CSharpVersion3 so I could use automatic properties and not have to explicitly write the getter and setter for the parameter “Name.”

[string]$code = @"
using System.Management.Automation; 

namespace SendGreetingDemo1
{

  [Cmdlet(VerbsCommunications.Send, "Greeting")]
  public class SendGreetingCommand : Cmdlet
  {
    [Parameter(Mandatory=true,Position=0)]
    public string Name {get;set;}
    
    protected override void ProcessRecord()
    {
      WriteObject("Hello " + Name + "!");
    }
  }
}
"@            
            
$assembly = (Add-Type -TypeDefinition $code `
          -Language CSharpVersion3 `
          -passthru ).Assembly            
$assembly | Import-Module

Remote Desktop mstsc /admin

For some reason back when Vista came out, MS changed the /console switch from /console to /admin for MSTSC.exe which is used to connect to remote desktop sessions.

I find myself using /admin when there are already two users logged on and I can’t get in without knocking someone off.

A friend of mine showed me a nifty trick that I thought was worth sharing.

You can use the /admin switch in the Remote Desktop window itself. You don’t have do go back to the run menu or a cmd PowerShell prompt and run mstsc /console.

image

To Compile or Not Compile, that is the question

A few weeks ago I had the pleasure of speaking at Tech Summit for Avanade. Tech Summit is sort of like an internal Tech Ed for Avanade Employees. My talk, of course, was all about PowerShell V2 and how to leverage the features like Remoting, Modules, and Advanced Functions.

Advanced Functions essentially allows PowerShell users to leverage nearly all the features that are available to a developer writing a Cmdlet in C# in functions written in PowerShell script.

After the talk, one question that was brought up was “If you can leverage all of these features in Advanced Functions, at what point would you convert over to C# (or VB .NET) and write a full blown compiled binary Module.

The first is all about performance. Well written compiled code will almost always out perform well written interpreted code. There are a ton of factors here that can come into play, but as a general rule, binaries will be faster than script.

The second reason you may want to stick with compiled code is if you want to include a provider with your Module. A provider presents any kind of data store to a PowerShell user in the same way they are presented the filesystem. You can do things like set-location, new-item, set-itemproperty, cd, ls, md, etc etc. Just as an example, the PowerShell Community Extensions has a provider for Active Directory.

If you are a sys admin that has never cracked open Visual Studio, you obviously will start off with Advanced Functions. However, I would really like to point out that the glide path to compiled C# from Advanced Functions is not super steep. There is a ton of documentation on Beginner Development and how to write your first Cmdlet. So if you are interested at all in learning, I say go for it and jump in with both feet. Even if you are not looking to be a full time software developer, looking at and understanding how a compiled cmdlet is written will bring a deeper understanding to how you use PowerShell.