Wednesday, August 14, 2013

Using C# to manage an Extreme XOS based switch via SNMP

This is to provide an example of a plug-in I wrote for the Green Monster System to manage an Extreme Networks XOS based switch.  This includes devices like the 350, 450 and BD10k and the like.

Most of these commands were determined via many hours with network sniffer as the MIBs do not expose the OIDs used here.

The SNMP commands are performed via a base class that uses Nsoftware's SSNMP library.  That class is not included because of licensing.

If you need help or have questions feel free to send me mail.

        public bool createVlan(int tag, string name)
        {
            // Query to get the next available index for this switch
            int index = getAvailableIndex();
            if (index == -1)
                return false;

            // Set 1.3.6.1.4.1.1916.1.2.1.2.1.1.Index value = index type=integer
            // Set 1.3.6.1.4.1.1916.1.2.1.2.1.2.index value = Vlan Name Type=String
            // Set 3.6.1.4.1.1916.1.2.1.2.1.10.index value=vlantag Type=integer
            SNMPDataCollection request = new SNMPDataCollection();
            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.1.2.1.1." + index, index, SNMPBase.datatypes.integer));

            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.1.2.1.2." + index, name, SNMPBase.datatypes.str));
            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.1.2.1.10." + index, tag, SNMPBase.datatypes.integer));
            return sendSNMP(request);
        }
        public bool deleteVlan(int tag)
        {
            int index = getVlanIndexID(tag);
            if (index == -1)
                return false;

            return sendSNMP("1.3.6.1.4.1.1916.1.2.1.2.1.6." + index, 6);
        }

        public bool addPortToVlan(int tag, int ifIndex, bool isTagged)
        {

            //get the slot and port info for the ifIndex :
            string slotdata;
            if (getSNMP("1.3.6.1.2.1.31.1.1.1.1." + ifIndex, SNMPBase.datatypes.str, out slotdata) == false)
                return false;

            if (slotdata.IndexOf(":") == -1)
                return false;

            int slot = Convert.ToInt32(slotdata.Substring(0, slotdata.IndexOf(":")));
            int port = Convert.ToInt32(slotdata.Substring(slotdata.IndexOf(":") + 1));

            //Get the Vlan's Index ID
            int vlanIndex = getVlanIndexID(tag);

            if (vlanIndex == -1)
                return false;

            int tagged;
            if (isTagged)
                tagged = 1;
            else
                tagged = 2;

            // Create the byte array that will hold the bits for the port we are going to modify in the vlan
            int maxportsperslot = getMaxPortsperSlot();
            if (maxportsperslot == -1)
                return false;
            byte[] changearray = GeneratePortByteStream(port, maxportsperslot);

            // Set 1.3.6.1.4.1.1916.1.2.6.2.1.1.. x 00000000000040 (bit mask of ports to add)
            // set 1.3.6.1.4.1.1916.1.2.6.2.1.2..Type=integer Value =1 or 2 (1=tagged 2=untagged)
            // Set 1.3.6.1.4.1.1916.1.2.6.2.1.3.. Type=integer Value=4 

            SNMPDataCollection request = new SNMPDataCollection();
            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.6.2.1.1." + vlanIndex.ToString() + "." + slot.ToString(), changearray, SNMPBase.datatypes.str));
            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.6.2.1.2." + vlanIndex.ToString() + "." + slot.ToString(), tagged, SNMPBase.datatypes.integer));
            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.6.2.1.3." + vlanIndex.ToString() + "." + slot.ToString(), 4, SNMPBase.datatypes.integer));
            return sendSNMP(request);
        }

        public bool addFirstPorttoVlan(int tag, int ifIndex, bool isTagged, string vlanName)
        {
            //Extreme allows empty vlans so create the vlan then add the ports
            bool response = false;
            response = createVlan(tag, vlanName);
            if (response == false)
            {
                return false;
            }

            //add the port
            response = addPortToVlan(tag, ifIndex, isTagged);
            if (response == false)
            {
                return false;
            }
            return true;
        }
        public bool removePortFromVlan(int tag, int ifIndex)
        {
            //get the slot and port info for the ifIndex
            string slotdata;
            if (getSNMP("1.3.6.1.2.1.31.1.1.1.1." + ifIndex, SNMPBase.datatypes.str, out slotdata) == false)
                return false;

            int slot = Convert.ToInt32(slotdata.Substring(0, slotdata.IndexOf(":")));
            int port = Convert.ToInt32(slotdata.Substring(slotdata.IndexOf(":") + 1));

            //Get the Vlan's Index ID
            int vlanIndex = getVlanIndexID(tag);

            if (vlanIndex == -1)
                return false;

            //Create the byte array that will hold the bits for the port we are going to modify in the vlan
            int maxportsperslot = getMaxPortsperSlot();
            if (maxportsperslot == -1)
                return false;
            byte[] changearray = GeneratePortByteStream(port, maxportsperslot);

            //Set 1.3.6.1.4.1.1916.1.2.6.2.1.1.. x 00000000000040 (bit mask of ports to remove)
            //set 1.3.6.1.4.1.1916.1.2.6.2.1.2..Type=integer Value =3
            //Set 1.3.6.1.4.1.1916.1.2.6.2.1.3.. Type=integer Value=4

            SNMPDataCollection request = new SNMPDataCollection();
            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.6.2.1.1." + vlanIndex.ToString() + "." + slot.ToString(), changearray, SNMPBase.datatypes.str));
            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.6.2.1.2." + vlanIndex.ToString() + "." + slot.ToString(), 3, SNMPBase.datatypes.integer));
            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.6.2.1.3." + vlanIndex.ToString() + "." + slot.ToString(), 4, SNMPBase.datatypes.integer));
            return sendSNMP(request);
        }

       public bool? isPortInVlan(int tag, int ifIndex, bool tagged)
        {
            string slotdata;
            if (getSNMP("1.3.6.1.2.1.31.1.1.1.1." + ifIndex, SNMPBase.datatypes.str, out slotdata) == false)
                return null;

            int slot = Convert.ToInt32(slotdata.Substring(0, slotdata.IndexOf(":") + 1));
            int port = Convert.ToInt32(slotdata.Substring(slotdata.IndexOf(":") + 1));

            Byte[] vlanMembers;
            if (getVlanMembers(tag, slot, tagged, out vlanMembers) == false)
                return null;

            return isPortMember(port, vlanMembers);

        }

        public Raw_VlanMemberCollection GetVlanMembers(int tag)
        {
            Raw_VlanMemberCollection data = new Raw_VlanMemberCollection();

            //get the number of slots 
            string getData;
            if (getSNMP("1.3.6.1.4.1.1916.1.1.2.1.0", SNMPBase.datatypes.integer, out getData) == false)
            {
                data.isErrorState = true;
                return data;
            }
            int slots = -1;
            if (Int32.TryParse(getData, out slots) == false)
            {
                System.Threading.Thread.Sleep(1000);
                //Failed to get valid data from switch.  Try again
                if (getSNMP("1.3.6.1.4.1.1916.1.1.2.1.0", SNMPBase.datatypes.integer, out getData) == false)
                {
                    data.isErrorState = true;
                    return data;
                }
                if (Int32.TryParse(getData, out slots) == false)
                {
                    throw new TimeoutException("Failed to contact Switch IP " + this.DeviceIP + " via SNMP, the switch might be down or busy.  Try again later or contact the admin");
                }
            }
            if (slots == -1)
                throw new ArgumentOutOfRangeException("Failed to lookup correct slot information for device at IP" + this.DeviceIP);

            int vlanIndex = getVlanIndexID(tag);
            if (vlanIndex == -1)
            {
               // data.isErrorState = true;
                return data;
            }

            NetworkPortCollection Ports = getPorts();
            // we have to process vlan memberships for each slot
            for (int slot = 1; slot <= slots; slot++)
            {
                //Get Tagged vlan members for slot
                Byte[] vlanMembers;
                if (getVlanMembers(tag, slot, true, out vlanMembers) == false)
                {
                    data.isErrorState = true;
                    return data;
                }

                ArrayList members = GetMemberPorts(vlanMembers); //Get a list of each port number based on mask


                foreach (int p in members)
                {
                    NetworkPort port = Ports.Find(delegate(NetworkPort o) { return o.slotNumber == slot && o.portNumber == p; });
                    if (port != null) //we found our port lets update the membership
                    {
                        Raw_VlanMember member = new Raw_VlanMember();
                        member.isTagged = true;
                        member.tag = tag;
                        member.port = port.portNumber;
                        member.slot = port.slotNumber;
                        member.PortifIndex = port.ifIndex;
                        member.VlanifIndex = vlanIndex;
                        data.Add(member);
                    }
                }

                //Get un-Tagged vlan members for slot
                if (getVlanMembers(tag, slot, false, out vlanMembers) == false)
                {
                    data.isErrorState = true;
                    return data;
                }

                members = GetMemberPorts(vlanMembers); //Get a list of each port number based on mask
                // Ports = getPorts();

                foreach (int p in members)
                {
                    NetworkPort port = Ports.Find(delegate(NetworkPort o) { return o.slotNumber == slot && o.portNumber == p; });
                    if (port != null) //we found our port lets update the membership
                    {
                        Raw_VlanMember member = new Raw_VlanMember();
                        member.isTagged = false;
                        member.tag = tag;
                        member.port = port.portNumber;
                        member.slot = port.slotNumber;
                        member.PortifIndex = port.ifIndex;
                        member.VlanifIndex = vlanIndex;
                        data.Add(member);
                    }
                }
            }
            return data;
        }
        public VlanCollection getVlans()
        {
            VlanCollection Vlans = new VlanCollection();

            //Get All the Vlans
            SNMPDataCollection data = walk("1.3.6.1.4.1.1916.1.2.1.2.1.10");
            if (data.isErrorState == true)
            {
                Vlans.isErrorState = true;
                return Vlans;
            }
            foreach (SNMPData obj in data)
            {
                string vlanTag = obj.value.ToString(); //each value will be a vlan
                string oid = obj.oid;
                int ifIndex = Convert.ToInt32(oid.Replace("1.3.6.1.4.1.1916.1.2.1.2.1.10.", string.Empty));

                //Will include 4095 which is the Management Vlan
                Vlan vlan = new Vlan();
                vlan.tag = Convert.ToInt32(vlanTag);
                vlan.ifIndex = Convert.ToInt32(ifIndex);
                vlan.name = getVlanName(vlan.tag);
                Vlans.Add(vlan);
            }

            return Vlans;
        }
      public bool setVlanIPAddress(int vlanTag, string ipAddress, string NetworkMask)
        {
            int vlanIfIndex = getVlanIndexID(vlanTag);
            if (vlanIfIndex == -1)
                return false; //unable to find vlan index

            if (ipAddress == string.Empty)
                return clearVlanIPaddress(vlanIfIndex); // doing a cleanup


            if (NetworkMask == string.Empty)
                return false; // dont allow a null network mask

            SNMPDataCollection request = new SNMPDataCollection();
            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.4.1.1.1." + vlanIfIndex, ipAddress, SNMPBase.datatypes.ipAddress));
            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.4.1.1.2." + vlanIfIndex, NetworkMask, SNMPBase.datatypes.ipAddress));
            sendSNMP(request);

            request = new SNMPDataCollection();
            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.4.1.1.3." + vlanIfIndex, 1, SNMPBase.datatypes.integer)); //activate the IP
            return sendSNMP(request);

        }

        public string getVlanIPAddress(int vlanTag)
        {
            int vlanIfIndex = getVlanIndexID(vlanTag);
            if (vlanIfIndex == -1)
                return string.Empty; //unable to find vlan index
            string result;
            getSNMP("1.3.6.1.4.1.1916.1.2.4.1.1.1." + vlanIfIndex, SNMPBase.datatypes.ipAddress, out result);
            return result;
        }
        public string getVlanNetworkMask(int vlanTag)
        {
            int vlanIfIndex = getVlanIndexID(vlanTag);
            if (vlanIfIndex == -1)
                return string.Empty; //unable to find vlan index
            string result;
            getSNMP("1.3.6.1.4.1.1916.1.2.4.1.1.2." + vlanIfIndex, SNMPBase.datatypes.ipAddress, out result);
            return result;
        }
        public bool setVLanIPForward(int vlanTag, bool Enabled)
        {
            if (getVlanIPAddress(vlanTag) == string.Empty)
                return false; //no ip Set

            int vlanIfIndex = getVlanIndexID(vlanTag);
            if (vlanIfIndex == -1)
                return false; //unable to find vlan index

            int value = Enabled == true ? 1 : 2; // 1 = enabled, 2 = disabled

            SNMPDataCollection request = new SNMPDataCollection();
            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.4.1.1.4." + vlanIfIndex, value, SNMPBase.datatypes.integer));
            return sendSNMP(request);
        }
        public bool? getVlanIPForward(int vlanTag)
        {
            if (getVlanIPAddress(vlanTag) == string.Empty)
                return false; //no ip Set
            int vlanIfIndex = getVlanIndexID(vlanTag);
            if (vlanIfIndex == -1)
                return false; //unable to find vlan index

            string value;
            if (getSNMP("1.3.6.1.4.1.1916.1.2.4.1.1.4." + vlanIfIndex, SNMPBase.datatypes.integer, out value) == false)
                return null;
            if (value == "2")
                return false;
            else
                return true;

        }

        private bool clearVlanIPaddress(int ifIndex)
        {
            //check to see if a ip is set
            string state;
            if (getSNMP("1.3.6.1.4.1.1916.1.2.4.1.1.3." + ifIndex, SNMPBase.datatypes.integer, out state) == false)
                return false;

            if (state == string.Empty) //no ip set
                return true;

            SNMPDataCollection request = new SNMPDataCollection();
            request.Add(new SNMPData("1.3.6.1.4.1.1916.1.2.4.1.1.3." + ifIndex, 6, SNMPBase.datatypes.integer)); //delete the IP Address
            return sendSNMP(request);
        }
#region "internal methods"

        /// 
        /// Query switch for member array of a given Vlan, slot and tag
        /// 
        /// 
        /// 
        /// 
        /// Extreme Vlan member array
        private bool getVlanMembers(int tag, int slot, bool isTagged, out Byte[] members)
        {
            //Get the Vlan's Index ID
            members = new Byte[0];
            int vlanIndex = getVlanIndexID(tag);
            if (vlanIndex == -1)
                return false;

            int tagged;
            if (isTagged)
                tagged = 1;
            else
                tagged = 2;


            return getSNMP("1.3.6.1.4.1.1916.1.2.6.1.1." + tagged + "." + vlanIndex + "." + slot, out members);

        }

        /// 
        /// Process Byte Array to determine member ports
        /// 
        /// 
        /// Returns an array for port numbers for a MemberByteArray
        private ArrayList GetMemberPorts(Byte[] memberbytes)
        {
            //Find out which bit positions are set in a byte.  Based off which position and byte we are in we can determine the port number
            //ie bit 7 in byte 0 = port 1
            //ie bit 0 in byte 0 = port 8
            ArrayList members = new ArrayList();

            int bytecoute = 0;
            int portNumber = 0;
            int result = 0;

            foreach (Byte b in memberbytes)
            {
                if (memberbytes[bytecoute] == 0)
                {
                    bytecoute++; // No ports where active in the Byte
                }
                else // if we have port membership in the Byte lets see which ports
                {

                    for (int i = 0; i < 8; i++) // Loop through each bit 
                    {
                        result = memberbytes[bytecoute] & PORTMASKARRAY[i]; // Is each bit value (port) in the array?
                        if (result == PORTMASKARRAY[i])
                        {
                            portNumber = i + 1 + bytecoute * 8;
                            members.Add(portNumber); // Add the portnumber to our returned list
                        }
                    }
                    bytecoute++;
                }
            }
            return members;
        }

        private int getVlanIndexID(int tag)
        {
            bool triedagain = false;

        tryagain: ;
            //walk to get the vlans
            SNMPDataCollection data = walk("1.3.6.1.4.1.1916.1.2.1.2.1.10");
            if (data.isErrorState == true)
                return -1;

            foreach (SNMPData item in data)
            {
                if (Convert.ToInt32(item.value) == tag)
                    return Convert.ToInt32(item.oid.Replace("1.3.6.1.4.1.1916.1.2.1.2.1.10.", ""));
            }
            if (triedagain == false)
            {
                triedagain = true;
                System.Threading.Thread.Sleep(100);
                goto tryagain;
            }
            return -1; //Could not find the tag
        }

        private static bool isPortMember(int portnumber, Byte[] membershipstream)
        {
            //Determine the port number we are working with for the given slot
            //Mod by 1000 to remove slot number; set remainder to portnumber
            portnumber %= 1000;

            Byte[] PORTMASKARRAY = { 128, 64, 32, 16, 8, 4, 2, 1 };
            return (membershipstream[(portnumber - 1) / 8] & PORTMASKARRAY[(portnumber - 1) % 8]) != 0;
        }

        /// 
        /// Extreme Byte Stream generation, used for modifing port membership in Vlan
        /// 
        /// portnumber to add/remove from vlan
        /// 
        private Byte[] GeneratePortByteStream(int portnumber, int MAXPORTSPERSLOT)
        {
            //Determine the port number we are working with for the given slot
            //Mod by 1000 to remove slot number; set remainder to portnumber
            //portnumber %= 1000;


            Byte[] holdingByte = null;

            //Create an Array to hold the changing value
            int bytesNeeded = MAXPORTSPERSLOT / 8 + (MAXPORTSPERSLOT % 8 <= 0 ? 0 : 1);
            holdingByte = new byte[bytesNeeded];

            //Determin which byte we are working with
            int byteposition = (portnumber - 1) / 8;

            //Mod to find the bit we are working with 
            int maskindex = (portnumber - 1) % 8;

            //Set the value in our Holding array for the corisponding bit
            holdingByte[byteposition] |= PORTMASKARRAY[maskindex];

            return holdingByte;
        }

        private int getMaxPortsperSlot()
        {
            //Get Max ports per Slot
            string data;
            if (getSNMP("1.3.6.1.4.1.1916.1.1.2.3.0", SNMPBase.datatypes.integer, out data) == false)
                return -1;

            return Convert.ToInt32(data);
        }

        private int getAvailableIndex()
        {
            string data;
            if (getSNMP("1.3.6.1.4.1.1916.1.2.2.1.0", SNMPBase.datatypes.integer, out data) == false)
                return -1;

            return Convert.ToInt32(data);
        }

        private string ConvertToHex(object bytearray)
        {

            byte[] ba = (byte[])bytearray;

            StringBuilder hex = new StringBuilder(ba.Length * 2);
            foreach (byte b in ba)
                hex.AppendFormat("{0:x2}", b);
            return hex.ToString();
        }
        #endregion

    }
}

Post 1: Building a cross platform network switch automation system

Note: I have had this info in a pending publish state for a while and decided to finally post it. 


When I was a team member at the Enterprise Engineer Center (http://www.microsoft.com/en-us/eec/default.aspx) we use a mix of network equipment (and Power PDUs, KVM, Servers and SAN).  The EEC hosts customer “engagements” to test/validate scale, proof of concept and features.  The facility has 7 customer labs and security is a number 1 priority. The EEC has multiple levels of security to isolate customer environments from each other, our team systems, and the Microsoft corporate network.  Vlans are used extensively as part of the isolation system and as part of testing customer scenarios.  Some test environments may only have 1 Vlan others may have 25.  Vlans are created and deleted as required for the scenarios being tested. As “the networking guy” I was called to action regularly to help resolve connectivity issues with Vlans that spanned multiple switches.  Many times the issues were caused by a single interface missing its Vlan configuration (tagged or untagged).   While the fix for issues was very easy finding which interface was incorrectly configured proved to be very time consuming. 

To increase the complexity the EEC uses a mix of network switch vendors depending on our partnership and features offered by each.  We also have a large variety of server equipment from multiple partners. These servers can be pre-release systems or a single system that fits a custom need.

As the EEC started its major remodel in 2008 we viewed this as a great time to improve our systems and processes.

In 2008 I started work on a project codenamed Green Monster (GM).  The goals of Green Monster were

1. Reduce the manual process required to perform network vlan and Layer 3 changes by creating automation framework
2. Support a diverse list of equipment manufacturers (network, power, kvm, servers)
3. Create a database of equipment inventory to replace excel spreadsheets
4. Create a database of network and power port to server mappings
5. Provide an automated system to power systems on/off
6. Create a near zero touch OS deployment environment for Engagement build out/setup
7. Abstract hardware vendor and network design from users (UI or script interface)


Development of Green Monster was to be done as a side project.  I was the PM, Dev and for the most part the tester.  Many of my teammates helped with feature feedback, DB design ideas and testing. They also provided a large list of features and ideas for future versions.

Green Monster consists of a WCF Service that performs all the automation logic, DB interaction and device integration. The frontend is a C# UI that consumes the WCF service.  OS imaging was done with WDS and some in-house scripts written by a co-worker.

I will be posting information about specific features and provide code snips on how I interact with devices over the network.

Wednesday, August 7, 2013

Migrating TFS (2010 or 2012) Personal Queries from one project to another via Powershell

The powershell script below can be saved run on a users system to migrate their personal TFS Queries from one project to another.  This is useful when migrating from TFS 2010 to TFS 2012.

You will need to update the script Source and Target Server URLs, TPC and Projects.  I went down the path to hard code them and not take them as arguments so users did not have to enter anything.  The script will throw errors if the query being migrated is not valid on the target project.
function ProcessQueryItem ($queryFolder, $parentFolder, $sourceProjectName)
{
 $newItem = $null
 foreach ($subQuery in $queryFolder)
 {
  if ($subQuery -is [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder])
  { 
   $newItem = new-object Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder -ArgumentList    @($subQuery.Name)
   if (-not $parentFolder.Contains($subQuery.Name))
   {
    Write-Host "Adding Query Folder $subQuery"
    $parentFolder.Add($newItem);
    $WIStoreRight.Projects[$RightProject].QueryHierarchy.Save()
    ProcessQueryItem $subQuery $newItem $sourceProjectName
   }
   else
   {
    Write-Host "Query Folder "$subQuery.name" already exists" -foregroundcolor Yellow
   }

  }
  else
  {
   Write-Host "Creating query "$subQuery.Name
   $oldDef = [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition]$subQuery
   $queryText = $oldDef.QueryText.Replace("$sourceProjectName\", "$RightProject\")
   $queryText = $queryText.Replace("[System.IterationPath] under '" + $sourceProjectName + "'", "[System.IterationPath] under '" + $RightProject +"'");
   $newItem = new-object Microsoft.TeamFoundation.WorkItemTracking.Client.QueryDefinition -ArgumentList @($subQuery.Name,$queryText)
      
    if ($parentFolder.Contains($subQuery.Name) -ne $true )
    {
    $parentFolder.Add($newItem)
    $WIStoreRight.Projects[$RightProject].QueryHierarchy.Save()
    }
    else
    {
    Write-Host "Query Definition $subQuery already exists" -foregroundcolor Yellow
    }
  
  }
 }
}

[URI]$Projecturileft = "http://sourceServer:8080/tfs/SourceTPC/"
$leftProject = "SourceProject"
[URI]$ProjecturiRight = "http://targetServer:8080/tfs/TargetTPC/"
$RightProject = "TargetProject"

[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.WorkItemTracking.Client')
[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.Client')
[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.Server')

$tfsleft = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($Projecturileft) 
$WIStoreleft = $tfsleft.GetService([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore]) 
$WIStoreleft.RefreshCache($true)
$WIStoreleft.SyncToCache() | out-null

$LeftQuerystore = $WIStoreleft.Projects[$LeftProject].QueryHierarchy

$tfsRight = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($ProjecturiRight) 
$WIStoreRight = $tfsRight.GetService([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore]) 
$WIStoreRight.RefreshCache($true)
$WIStoreRight.SyncToCache() | out-null
foreach ($queryFolder in $LeftQuerystore)
{
 if ($queryFolder.IsPersonal)
 {
  $RightMyQueriesFolder = [Microsoft.TeamFoundation.WorkItemTracking.Client.QueryFolder]$WIStoreRight.Projects[$RightProject].QueryHierarchy["My Queries"];
  
  ProcessQueryItem $queryFolder $RightMyQueriesFolder $leftProject
  Write-Host "Personal Queries Migrated"
 }
}

Monday, July 15, 2013

How to use WIQL to query for work items in TFS 2012 via the URL

These days I spend a large amount of time in TFS 2012. 

In TFS 2008 and 2010 users could use the q.aspx page to run a query using WIQL as defined by the 2010 WIQL spec (http://msdn.microsoft.com/en-us/library/bb130306(v=vs.100).aspx). Ken O' Bonn has a great post on this at http://blogs.msdn.com/b/kenobonn/archive/2009/05/28/how-to-link-directly-to-tswa-2008-or-2010-beta1-work-items-or-queries.aspx

However in TFS 2012 the URLs for everything changed and I was unable to find any information on how to accomplish the same task. How can you provide a URL to users that queries for work items without writing and saving a query to the TFS server. 

The key is I don't want to save a query to TFS.   

So after some trial and error I found the way!

http://<ServerAddress>:8080/tfs/<TPC Name>/<Project>/_workitems#_a=query&wiql=<WIQL>

An example:

http://tfstest:8080/TPC1/project1/_workItems#_a=query&wiql=select id, [System.areapath] from workitems

The WIQL for 2012 is defined at http://msdn.microsoft.com/en-us/library/bb130306.aspx#language






Tuesday, May 28, 2013

Why solar (PV) in Seattle Washington ROCKS!

I just had my 4.3kW solar array installed on my home in Seattle.  The upfront cost is a little high but I should still be able to pay off the system in less than 8 years.  This is possible thanks to Washington States amazing Solar credits.

Seattle City Light (and other Washington residence) pay amazingly low energy rates for residential our power. Even with this low rate people installing solar panels can relatively quickly get a good ROI on their panels.

  • Seattle has the lowest rate compared to the top 25 largest cities in the US.
  • The 2013 rate for SCL customers is $.0466/kWh for the first 10kWh. 
  • The national average rate is $0.129/kWh  and people in New York pay ~$0.209/kWh

How can I pay back my panels so fast?

The Washington State Solar generation incentive program.  While not the exact name it is a Performance-Based Incentive that gives the array owner a dollar amount for every kW they generate no matter if they use that power in their home or send it back to the power grid.  The current incentive is in place until June 30th  2020. 

In short this incentive give me $.54/kWh I generate on-top of my reduced power bill and any Net metering (where I sell power back to my power company).  I get the full 54 cents because my Itek Solar Panels and BlueFrog inverters are MADE IN WASHINGTON.  If you have non-Washington made components the incentive drops significantly

Many other states don't provide such an incentive nor do they give you full price on the net metering.  But Washington does!  Yet another reason why living in Seattle ROCKS. 

Other State Example:
My partner's parents have a ~7kW system at their home on Oahu Hawaii.  This system generate power for ~10 hours a day and significantly lowers their power bill.  Hawaii Power Company (HECO) current rate is ~$.32/kWh.  This is 7 times higher than the rates I pay in Seattle.  At that rate they are still expected to pay off their system in ~5 years.  This very high rate (and rebates) is the only way the $40k+ system can pay for its self in a timely fashion.




Friday, April 26, 2013

Getting 4.3kW of Solar Panels in Seattle!

I know people say it rains a lot in Seattle. Truth is that it "mists" a lot and is just gray more often than not. 

But either way the SUN is there to give everyone free energy if they want it. 

My new home finally has enough roof space for Solar Panels (PV) that will let me make the investment worth while. 

Puget Sound Solar had the best price and was able to get an install date that was before the June 30th 2013 Washington sales tax exception cut off.  Will Sumner from Puget Sound Solar came out and went up onto my roof to do his survey.  He answered all my questions and was able to point me to Puget Sound Cooperative Credit Union for my zero down low rate loan for the full project. 

My install date is currently May 14th 2013. 

I am going with the Itek 240W modules and the BlueFrog APSYC500-MIW micro inverters.  This will get me the .54 /kWh all Washington incentive and provide 4.3kW of capacity.  All parts are made in Washington!!

I expect full payback in less than 8 years!  WOOT WOOT. 

Puget Sound Solar has sent me a few forms I needed to complete and then mail a check to Seattle City Light for my production meter.  Everyone has been great and after meeting with the Project Manager Jacob Hanson today everything seems to be on track!

My Bee Hive Warning sign

I got the sign below from http://www.bbhoneyfarms.com/store/

They were cheap and have done a great job to warn people that I have a hive.

They also let people know Bees are not out to hurt anyone.  Just don't mess with their home.




Caution
No Trespassing
Honeybees

TFS 2012 how to get Last Known good build via Powershell

The following script will return the last successful build on a given build definition. 

Save the following to a .ps1 file

$project = "testproject"
[URI]$Projecturi = "http://tfsserver:8080/tfs/DefaultCollection/"
function Wait-GetLKGBuild {
 [CmdletBinding()]
 PARAM (
  [Parameter(Mandatory=$true)]
        [string]$buildDefinitionName
    )

    [void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.Build.Client')
    [void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.Client')

 $tfs = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($Projecturi)
    $buildserver = $tfs.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer])
         
    $rbBuildDefinition = $buildserver.GetBuildDefinition($project, $buildDefinitionName)
 $build = $buildserver.GetBuild([Uri]($rbBuildDefinition.LastGoodBuildUri));
  New-Object PSObject -Property @{
                Buildnumber = $build.BuildNumber; 
    Requestedfor = $build.RequestedFor;
                Status = $build.Status;           
                CompilationStatus = $build.CompilationStatus;           
                Start = $build.StartTime;           
                End = $build.FinishTime;           
                DropLocation = $build.DropLocation;           
                SourceGetVersion = $build.SourceGetVersion;           
                }           
         }
}
Wait-GetLKGBuild $buildDefinitionName

My first Bee hive 2013

2013 is now the first year that I live in a house with enough room to have a bee hive.  On April 20th 2013 I picked up by bee package from the Ballard Bee Company. 

My queen and her ~10,000 followers seem to be doing well.

At day 2 I opened the hive to make sure the queen made it out of her cage by eating through the mini-marshmallow.  She made it out. 

I will open the hive again on day 7 to see if she has started laying eggs.

Here are some pictures. 



Sunday, February 5, 2012

Home Circuit Power Monitoring - Part 2

It has been about 6 months from when I installed per circuit power monitoring in my home (http://www.mikepoulson.com/2011/07/new-home-power-monitor.html).

In January 2012 I started injecting all my power data into a SQL DB (SQL Express).  This has allowed me to use Tableau (www.tableausoftware.com) to analyze the utilization.

Here is an example of that power consumption in my House. 


You can see my office plugs (where my Media Center is located) is my #1 consumer of power.  You can see that the TV and Kitchen outlets are in second place.

I used the data shown here to determine that my 1st floor lights use a lot of power.   This weekend I replaced those 400 Watts of lights with new LEDs (Phillips Ambient LED, http://www.amazon.com/Philips-409904-Dimmable-AmbientLED-12-5-Watt/dp/B004IUMGV4).

You can see from the graph below how much power I used to watch the "BIG GAME".

Based off this and a power cost of $.09/Kwh it cost ~$.24 to watch the game.
(539 watts /1000 = .539Kw * 5 hours = 2.70KwH * .09 = $.245)

This does not include the cost of beer, snacks, the cookies, steaks or stress. 

To get this to work I use tenEcmServer and tenEcmDB from http://tenholder.net/tenWare2/tenEcmServer/default.aspx.  The tenEcmDB needed a little modification to work with SQL Server.  By default it works with SQLLight.  With the tenEcm components I can monitor my BrulTech equipment and provided extensive reporting on it.

Wednesday, October 5, 2011

Not a big fan of new Microsoft Touch mouse

I upgraded from the Microsoft Touch Arch mouse to the new TouchMouse.  I must say I am not a fan.

The new mouse looks nice and all but does not work as well as I would like.


The new TouchMouse has a single button.  It utilizes touch sensors to detect if you are using the left or right finger to press down.  The problem that I have it is I rest my fingers on my mouse.  This causes the mouse to think I am using the multi-touch (two finger) to minimize or maximize windows. It also sometimes thinks I am pressing the right button when I press the left.

10 Years from last post

 Well world!   After the last almost 10 years I have been up to a few things in life and work.  Most recently I was working at Microsoft on ...