Winter Scripting Games 2014: Practice event…my way

The practice event named Server Inventory is now over and the submitted entries will be judged by very experienced Powershell pratitioners: Don Jones, Jason Helmick, Jeffery Hicks, Ed Wilson and Richard Siddaway.

There are always multiple ways to solve a problem and here’s my way 😀
This event could be written as a script (vs. a module or a function). I’ve decided to write it for Windows 2012 or Windows 8 or above platforms.

It may not be very explicit in the first requires statements but the DnsClient module is available on Windows 8 or above and the ActiveDirectory module is available if you install RSAT on a Windows 8 or if you enable the feature on the Windows server.

Add-WindowsFeature -Name RSAT-AD-PowerShell -Restart:$false


As it’s a script, the execution policy should also be modified so that it allows running scripts.

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

I didn’t add the #Requires -RunAsAdministrator but I validated administrator privileges in the Begin block like this:

using what I previously did in this post.

As I see the event, it could be split into 3 parts.

  1. The network part
  2. I’m not the network guy and I don’t like to reinvent the wheel, so I borrowed two functions from Powershell MVP Dr. Tobias Weltner and Carlos Perez:

    I’ve added a comment based help and some strong parameter validation.

    Now that I could return an array of IP addresses from the subnet submitted in a CIDR notation, I created a workflow to get the name of computer from its IP Address and its operating system version.

    I’ve used the new cmdlet Resolve-DnsName that can be found in the DnsClient module. I’ve also used the ActiveDirectory that store the operating system version as soon as I had the computername.

    As you can see, I’ve chosen to test the Powershell remoting of each server with the Test-WSMan cmdlet because my inventory method is based on remoting. That also means that a recent version of Powershell is installed on each server and the the remoting is configured appropriately. In my case, the default TCP port 5985 would be used and should be also allowed in firewall incoming rules…

    To extract the operating system build from AD in a more standard way, I’ve used a regular expression and the following link help me to write it.

    I did this because you can guess the service pack from the build number as of Windows Vista.
    The main process block in my script is that short:

    I’ve used the following resource to implement it: a must read.

    In the end block of the script, I exported the active and inactive IP Addresses in CSV format like this:

  3. The inventory part
  4. There are many ways to gather the inventory data. I’ve tried to show some of them depending on the target operating system and its version of powershell. I’ve chosen to use fan-out remoting capability provided by the Invoke-Command cmdlet combined with its ability to use jobs.

    Last year, I discovered what the server manager was doing behind the scene and used this technique to gather data on Windows 2012 servers. To query whether Exchange, SharePoint, SQL or IIS were installed, I used the services way.

    Another more classic way to gather inventory data on recent Windows Server editions is the following:

    Another way to know if SQL, IIS and SharePoint are installed consists in loading their snap-in except for Exchange (I couldn’t find a common denominator)

    And there’s also the registry way:

    To query when the last hotfix was installed, the most reliable way isn’t through the WMI Win32_QuickFixEngineering class or the Get-Hotfix cmdlet but with the Microsoft Update comobject like this:

    (New-Object -ComObject Microsoft.Update.Session).            
    CreateUpdateSearcher().            
    QueryHistory(0,1) |            
     Select -ExpandProperty Date

    And for fun there’s another way to gather inventory data, with systeminfo.exe. Either you convert its output to CSV (see this Power Tips) or using a regular expression (I used this in Scripting Games 2012):

    Instead of waiting for jobs to complete without displaying progress this way:

    Get-Job | Where Name -match 'InvScan_' |             
     Wait-Job -Timeout -1 | Out-Null

    … I did the following to display some progress:

    While (Get-Job | Where Name -match 'InvScan_' | Where State -eq 'Running') {            
     $Total = (Get-Job | Where Name -match 'InvScan_') ;            
     $completed = (Get-Job | Where Name -match 'InvScan_' | Where State -eq 'Completed') ;            
     $WPHT = @{            
        Activity = 'Waiting for scan inventory to complete' ;            
        Status = ('{0} over {1}' -f $Completed.Count,$Total.Count) ;            
        PercentComplete = (($Completed.Count)/($Total.Count)*100) ;            
     }            
     Write-Progress @WPHT            
     Start-Sleep -Seconds 1            
    }
  5. the visualisation part
  6. I didn’t want to install Office on a server just to be able to create the powerpoint presentation. I created a parameter switch dedicated for this part. So, on a Windows 8 or 8.1 workstation with at least Office 2010 installed, using the switch would just read the results of the inventory saved in a share and create the slides.

    To create charts, I thought it would be easier to save the chart as an image rather than creating data in Excel and then create the chart in Powerpoint linked to it.

    I found the following article about charting with PowerShell that helped me build the images and create my ConvertTo-Pie function. To create the second function New-PPTXFile, I found the inspiration in the following code posted by JayKul on poshcode.org

    My powerpoint presentation has 2 slides that look like this:

I’ve uploaded my solution for the practice event as a public gist available on this link
It’s probably not perfect but I had fun and learned many things 😀
As I write these last lines, the first event of the Winter Scripting Games has already been published, so, it’s your turn now.

Advertisements

Game plan for high performing team

I’ve borrowed both the title of this post and the following picture from Don Carew, Eunice Parisi-Carew and Ken Blanchard to illustrate what your team will go through for each event of the Winter Scripting Games.

Note: I’ll use italics whenever I quote the above authors or someone else.
(TDS = Team Development Stage)

There are two key variables. Productivity is the team’s ability to work together and achieve results. Morale is the team’s motivation, confidence and cohesion.

After each team member read the whole event description (including the criteria used by the judges for scoring), you and your team should immediately go through the first stage (TDS1) called orientation where productivity is low (you didn’t write any code yet) and morale is moderately high. Team members are moderately eager and have high expectations. They need direction and have some anxiety about their roles and their connections with the team.

To go through phase 1, you and your team will need to adopt a structuring approach. I think that you’ll need to:

  1. Identify the main goal of the event
  2. For the practice event, the main goal could be: inventory servers by scanning an IPv4 subnet, gather data like the CPU, RAM,…installed components and save data to files in a reusable format.

  3. Identify skills among your team
  4. Some team members may be more familiar than others about the network part. They should know what a CIDR is. Some may be more familiar with WMI,…

  5. Divide to conquer
  6. You should split each problem into tasks and create one function to achieve one task. Each function should do one single thing and do it well.

  7. Clarify roles
  8. Make sure that each member in your team has had a role assigned, i.e. is responsible for writing the function that does this…

Now each team member starts his journey and writes some code 😀 …

… and your team is actually slowly moving toward phase 2 (TDS2) called dissatisfaction.

Productivity is low to some. Skills and knowledge are slowly developping. Some results are occuring. Morale is low. There is a discrepency between expectations and reality. Team members have feelings of anger, frustration, confusion and discouragement.

This is in my opinion the most difficult phase to overcome.
As soon as you feel that morale is at its lowest point, it means that you matured enough to share your code on the scripting games site and get the help of coaches.

Coaches will do their best to provide high quality support and direction to your team. Resolving is the keyword for this phase. But don’t get me wrong. Some conflicts may arise among your team. You’re on your own to solve these conflicts. My last advice about this situation is that you’ve to listen and you can also use a tool like the “ladder of inference to avoid jumping to conclusions”. The following article provides some tips that may help you.

List the Windows Service Hardening firewall rules

I’ve seen recently the following knowledge base article http://support.microsoft.com/kb/2761899 about Hyper-V VMM service fails and Event ID 14050 is logged when dynamicportrange is changed in Windows Server 2012

I was surprised that not everybody uses Powershell especially when running on Windows 2012 server.

I’ll show how to replace the following vbscript from KB2761899

'This VBScript adds a port range from 9000 to 9999 for outgoing traffic
'run as cscript addportrange.vbs on the hyper-v host

option explicit

'IP protocols
const NET_FW_IP_PROTOCOL_TCP = 6
const NET_FW_IP_PROTOCOL_UDP = 17

'Action
const NET_FW_ACTION_BLOCK = 0
const NET_FW_ACTION_ALLOW = 1

'Direction
const NET_FW_RULE_DIR_IN = 1
const NET_FW_RULE_DIR_OUT = 2

'Create the FwPolicy2 object.
Dim fwPolicy2
Set fwPolicy2 = CreateObject("HNetCfg.FwPolicy2")

'Get the Service Restriction object for the local firewall policy.
Dim ServiceRestriction
Set ServiceRestriction = fwPolicy2.ServiceRestriction

'If the service requires sending/receiving certain type of traffic, then add "allow" WSH rules as follows
'Get the collection of Windows Service Hardening networking rules

Dim wshRules
Set wshRules = ServiceRestriction.Rules

'Add outbound WSH allow rules
Dim NewOutboundRule
Set NewOutboundRule = CreateObject("HNetCfg.FWRule")
NewOutboundRule.Name = "Allow outbound traffic from service to TCP 9000 to 9999"
NewOutboundRule.ApplicationName = "%systemDrive%\WINDOWS\system32\vmms.exe"
NewOutboundRule.ServiceName = "vmms"
NewOutboundRule.Protocol = NET_FW_IP_PROTOCOL_TCP
NewOutboundRule.RemotePorts = "9000-9999"
NewOutboundRule.Action = NET_FW_ACTION_ALLOW
NewOutboundRule.Direction = NET_FW_RULE_DIR_OUT
NewOutboundRule.Enabled = true
wshRules.Add NewOutboundRule

'end of script

…with a 3 lines Powershell script using the exact same approach.

$rule = New-Object -ComObject HNetCfg.FWRule -Property @{
    Name = "Allow outbound traffic from service to TCP 9000 to 9999"
    Direction = 2
    Enabled = $true
    ApplicationName = "$($env:systemdrive)\WINDOWS\system32\vmms.exe"
    ServiceName = "vmms"
    Protocol = 6
} 
$rule.RemotePorts = "9000-9999"
(New-Object -ComObject HNetCfg.FwPolicy2).ServiceRestriction.Rules.Add($rule)

It isn’t actually done in 2 lines because of the intricacies related to the INetFwRule interface comobject

Now that I created the rule how do I list these new firewall rules?

There are actually two ways.
Either using ComObject

(New-Object -ComObject HNetCfg.FwPolicy2).ServiceRestriction.Rules

…or using the built-in Powershell commands of the NetSecurity module as we run on a Windows Server 2012 😀

Get-NetFirewallRule -PolicyStore ConfigurableServiceStore

If there’s a way to query these rules, there must be a way to create these rules.

And…here’s the one-liner (split in two lines using splatting for a better readability)

$HT = @{
    DisplayName = "Allow outbound traffic from service to TCP 9000 to 9999"
    Direction = "Outbound"
    InterfaceType = "Any"
    Action =  "Allow"
    Protocol =  "TCP"
    Service = "vmms"
    Program = "$($env:systemdrive)\WINDOWS\system32\vmms.exe"
    Enabled = "TRUE"
    RemotePort = "9000-9999"
    PolicyStore = "ConfigurableServiceStore"
}
New-NetFirewallRule @HT

Note that you can see the rule added in the registry as well under the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\SharedAccess\Parameters\FirewallPolicy\RestrictedServices\Configurable\System key (Source: http://blogs.technet.com/b/voy/archive/2007/04/02/network-restrictions-for-service-hardening.aspx )

Let’s have a look at the PolicyStore parameter.

Get-Help Get-NetFirewallRule -ParameterName PolicyStore

While the help states that …

— ActiveStore: This store contains the currently active policy, which is the sum of all policy stores that apply to the computer. This is the resultant set of policy (RSOP) for the local computer (the sum of all GPOs that apply to the computer), and the local stores (the PersistentStore, the static Windows service hardening (WSH), and the configurable WSH).

…my experience shows that the static and configurable WSH are not part of the ActiveStore.
Maybe that’s why these 2 stores are at same level as the Persistent and ActiveStore.

# "VMMSAllowRDPIn" isn't in ActiveStore            
Get-NetFirewallRule -Name "VMMSAllowRDPIn" -PolicyStore ActiveStore            
            
# but it's in the ConfigurableServiceStore            
Get-NetFirewallRule -Name "VMMSAllowRDPIn" -PolicyStore configurableServiceStore            
            
# And you cannot get it like like this...            
Get-CimInstance -Namespace root/StandardCimv2 -ClassName MSFT_NetFirewallRule |            
? InstanceID -match "VMMSAllowRDPIn"

and I still wonder how I can get it? 😦