If you have a VMware ESX cluster running some Windows VMs, you’ve probably noticed very poor mouse response when on the console of your VMs. The fix is actually very simple. You need to bump up the hardware acceleration in the display preferences. You can either do it from the GUI (right click desktop -> properties -> settings -> advanced -> troubleshoot), or you can do it from Powershell:

set-itemproperty -path (((get-itemproperty "hklm:\hardware\devicemap\video")."\Device\Video0") -replace "\\Registry\\Machine","HKLM:") -name "Acceleration.Level" -value 0

What this command does is query the HKLM:\Hardware\Devicemap\Video registry branch to find the true location of your primary video device, and then sets the Acceleration.Level key to a value of 0.

The only problem with editing the registry setting directly is that Windows doesn’t automatically reload the display configuration, so the change doesn’t immediately take effect. Although it is technically possible to do that from Powershell, it isn’t easy (requires p/invoke) and you’re probably better off just rebooting the VM. :)

Share and Enjoy:
  • Digg
  • Technorati
  • Facebook
  • del.icio.us
  • StumbleUpon
  • Reddit

Using Group Policy in Active Directory, you can force the Windows Firewall to be enabled across your servers or clients, but sometimes you might not want to do that.  After all, when troubleshooting a software communications problem, it’s really easy to rule out the firewall configuration as a possible problem if you can disable it for a few minutes while you troubleshoot.

The only problem with allowing that kind of flexibility is how do you know that you remembered to re-enable the firewall on those 30 servers you worked on last week?  Well, some quick googling will show that you can use WMI to query the HNet_ConnectionProperties class and look at the IsFirewalled property.  Except….it’s always True!  Even if the firewall is disabled.  Apparently, this is because the ICS service is running so the property is a bit misleading.

So I did things the hard way.  I used Regmon to find out what registry key was flipped on/off when I enabled/disabled the Windows Firewall, and wrote a quick Powershell function to query that setting and return True or False (as type [bool]).

# returns true if windows firewall is enabled, false if it is disabled
filter global:get-firewallstatus ([string]$computer = $env:computername)
	{
	if ($_) { $computer = $_ }
 
	$HKLM = 2147483650
 
	$reg = get-wmiobject -list -namespace root\default -computer $computer | where-object { $_.name -eq "StdRegProv" }
	$firewallEnabled = $reg.GetDwordValue($HKLM, "System\ControlSet001\Services\SharedAccess\Parameters\FirewallPolicy\DomainProfile","EnableFirewall")
 
	[bool]($firewallEnabled.uValue)
	}

Update (Feb 1, 2009):

In the comments, Shay Levy reminded me of an alternate method of querying the registry that doesn’t use WMI. Here is the exact same script using the [Microsoft.Win32.RegistryKey] class. Thanks Shay!

filter global:get-firewallstatus2 ([string]$computer = $env:computername)
	{
	if ($_) { $computer = $_ }
 
	$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine",$computer)
 
	$firewallEnabled = $reg.OpenSubKey("System\ControlSet001\Services\SharedAccess\Parameters\FirewallPolicy\DomainProfile").GetValue("EnableFirewall")
 
	[bool]$firewallEnabled
	}
Share and Enjoy:
  • Digg
  • Technorati
  • Facebook
  • del.icio.us
  • StumbleUpon
  • Reddit

View/Download Get-Packet.ps1 Script

I’ve posted an updated version of my Get-Packet Powershell packet sniffer script.  It is still completely standalone (it doesn’t require any additional software to run).  New features include:

  • Added IP Version field
  • TCP flags are now stored in an array
  • New switch added to resolve IPs to hostnames
  • ESC key will cleanly exit the script
  • New switch added to generate statistics

.NET includes a method to resolve IPs to Hostnames in [System.Net.Dns]::GetHostByName(), but if the lookup fails, then there is a 5 second delay that forces the script to pause execution. I instead chose to scrape the output of nslookup since it returns much quicker.  To further decrease processing time, I cache the results in a hashtable so multiple calls to nslookup for the same host are not needed.

Using the -Statistics switch will cause the script to generate statistics after the ESC key is pressed to stop the trace.  Most of the statistics code was borrowed from Jeffery Hicks’s Analyze-Packet script.  A few basic stats will be printed to the screen with write-host, but the bulk of the data will be stored in a global $stats variable that you can access after the script has exited.  This isn’t how features would normally be implemented in cmdlets (they would be separate cmdlets), but I figured it would be ok in a script, and I have found the integration to be pretty convenient.

I had looked at adding IPv6 support, but design limitations in Windows prevented me from being able to access the raw IPv6 header.  See my earlier blog post for more details.  I also looked at adding the ability to save the capture in libpcap format, but I’m not getting the raw IP frame, so the data wouldn’t be as complete as a capture done in something like Wireshark.

Anyway, I hope you enjoy the new features!  Let me know in the comments if you would like to see any other features added.

  • EDIT: If you’re on Vista, you might need to disable the firewall to see TCP packets.  Not sure why yet. :)
  • EDIT #2: Found out why.  Add powershell.exe as an allowed application. (duh) :)

- Robbie

Share and Enjoy:
  • Digg
  • Technorati
  • Facebook
  • del.icio.us
  • StumbleUpon
  • Reddit

View/Download get-regex.ps1 Script

When I write scripts, every now and then I need to use Regular Expressions.  RegEx’s are very powerful, but I don’t use them enough to have it all memorized.  So instead of searching for my quick reference book all the time, I just made a Powershell function to display all of the info at the prompt.

Poweshell’s built in “get-help” includes some basic RegEx documentation, but it is lacking some detail, and I don’t want to have to read through all the “fluff” to get to what I want.

The output of the script looks like this:

PS C:\scripts> get-regex | ft -auto
Sequence                    Meaning                                                                      Table
--------                    -------                                                                      -----
\a                          Alert (bell), x07.                                                           Character r...
\b                          Backspace, x08, supported only in character class.                           Character r...
\e                          ESC character, x1B.                                                          Character r...
\n                          Newline, x0A.                                                                Character r...
\r                          Carriage return, x0D.                                                        Character r...
\f                          Form feed, x0C.                                                              Character r...
\t                          Horizontal tab, x09.                                                         Character r...
\v                          Vertical tab, x0B.                                                           Character r...
\0octal                     Character specified by a two-digit octal code.                               Character r...
\xhex                       Character specified by a two-digit hexadecimal code.                         Character r...
\uhex                       Character specified by a four-digit hexadecimal code.                        Character r...
\cchar                      Named control character.                                                     Character r...
[...]                       A single character listed or contained within a listed range.                Character c...
[^...]                      A single character not listed and not contained within a listed range.       Character c...
.                           Any character, except a line terminator (unless single-line mode, s).        Character c...
\w                          Word character.                                                              Character c...
\W                          Non-word character.                                                          Character c...
\d                          Digit.                                                                       Character c...
\D                          Non-digit.                                                                   Character c...
\s                          Whitespace character.                                                        Character c...
\S                          Non-whitespace character.                                                    Character c...
 
(etc...)

Enjoy!

- Robbie

Share and Enjoy:
  • Digg
  • Technorati
  • Facebook
  • del.icio.us
  • StumbleUpon
  • Reddit

 

IPv6 Ready Logo

About a year ago, I wrote a Powershell packet sniffer script that worked pretty well. I wanted to add IPv6 support to it, so I spent a good chunk of the last day learning the protocol and trying to figure out how to do it in Powershell/.NET. Unfortunately, what I found out is that it isn’t possible.

 

I basically had everything working, except for some reason I wasn’t receiving any IPv6 headers — only the payload. After lots of research (er..googling, and experimentation), I discovered that there is a design limitation in the Windows implementation of IPv6 that prevents incoming IPv6 headers from being passed to a raw socket. I also tried to get outgoing headers, but that wouldn’t work for me either. Without the header, it’s very difficult to figure out what protocol the payload is, so for now, I think I’m going to have to abandon this effort.

All is not lost though. I’ve made some other improvements to the original packet capture script and will post the new version soon.

- Robbie

Share and Enjoy:
  • Digg
  • Technorati
  • Facebook
  • del.icio.us
  • StumbleUpon
  • Reddit

View/Download jiraFunctions.ps1 Script

Atlassian Jira is a web-based bug/issue tracking software, but lucky for us, they provide a WSDL interface so that we can access it from a Powershell command line.

This script is only successful because of the work of Lee Holmes’ connect-wsdl function.  I’ve included it as part of this script for convenience.

First you will need to edit the $jiraURL variable in the script so that it points to your Jira WSDL URL.  I usually initialize most of my functions (and some variables) globally to make things easier, so after you’ve made the necessary edit, just run it from a command line.  The script will prompt you for a login/password for Jira.

Note: Some functions are incomplete/untested, so be sure to test before using in a production environment!

Connect-Jira is the first function that is called, and it establishes an initial connection to the Jira webservice.  This is the function that uses Lee’s connect-webservice function (and I honestly don’t know enough C# to understand how it works).

$global:jira = connect-jira $jiraURL

After the connection is established, you are authenticated to Jira securely using a login/password.  Thanks to Joel Bennett for the clever bits of code to securely grab the password without storing it anywhere.  There is a session ID stored in the $jiraAuthID variable that is used to identify your session.  A valid $jiraAuthID must be passed to most functions for them to succeed.  If the ID has timed out, the function calls will fail.

$BSTR = [System.Runtime.InteropServices.marshal]::SecureStringToBSTR($credential.Password)
$global:jiraAuthID = $jira.login($credential.UserName.TrimStart("\"),[System.Runtime.InteropServices.marshal]::PtrToStringAuto($BSTR))
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR);

At this point, you are dropped back to the Powershell prompt where you can call the many functions available to you.  For example:

PS C:\scripts\jira> get-jiraserverinfo
 
baseUrl     : https://server.yourdomain.com/jira
buildDate   : 9/13/2006 4:00:00 AM
buildNumber : 161
edition     : Enterprise
version     : 3.6.5
PS C:\scripts\jira> get-jiraresolution
 
description                   icon                          name                          id
-----------                   ----                          ----                          --
A fix for this issue is ch...                               Fixed                         1
The problem described is a...                               Won't Fix                     2
The problem is a duplicate...                               Duplicate                     3
The problem is not complet...                               Incomplete                    4
All attempts at reproducin...                               Cannot Reproduce              5
The bug report describes b...                               NOTABUG                       6
Issue type was a general q...                               Issue Closed                  7
PS C:\scripts\jira> get-jiraissue "WIN-113"
 
affectsVersions   : {}
assignee          : rfoust
attachmentNames   : {}
components        : {}
created           : 7/11/2008 9:12:48 PM
customFieldValues : {}
description       : Create an altiris job to push out this script/command to all windows servers.  There's a bug in the
                     powershell installer so this doesn't get done.  When complete, powershell will start up *much* fas
                    ter.  In fact, thats almost an understatement. :)
 
                    Set-Alias ngen @(
                    dir (join-path ${env:\windir} "Microsoft.NET\Framework") ngen.exe -recurse |
                    sort -descending lastwritetime
                    )[0].fullName
                    [appdomain]::currentdomain.getassemblies() | %{ngen $_.location}
 
                    For more info, see:  http://blogs.msdn.com/powershell/archive/2007/11/08/update-gac-ps1.aspx
duedate           :
environment       :
fixVersions       : {}
key               : WIN-113
priority          : 4
project           : WIN
reporter          : rfoust
resolution        :
status            : 1
summary           : Update GAC on all servers to decrease powershell startup time
type              : 4
updated           : 7/23/2008 1:40:17 PM
votes             : 0
id                : 20685

Enjoy! :)

- Robbie

Share and Enjoy:
  • Digg
  • Technorati
  • Facebook
  • del.icio.us
  • StumbleUpon
  • Reddit

View/Download Get-UnityLicense.ps1 Script

Many large companies and universities use Cisco Unity for their voicemail system. Cisco provides some sample vbscript code to programatically interface with Unity, but so far they haven’t provided any Powershell cmdlets.  This function connects via HTTP to a Unity server and returns license information as a PSCustomObject.

Note: This post refers to the full Cisco Unity, not Unity Express.

Unity provides its current license information on an XML page available through IIS. Because Powershell is built on .NET, it has very good support for HTTP and XML so this was actually a very simple function to write.

First we have to download the web page by initializing a System.Net.Webclient object, and calling the DownloadString method with the URL that we want.

$webContent = new-object net.webclient
$page = $webContent.DownloadString("http://$server/avxml/effectivelicense.asp")

The XML that is returned has some whitespace at the top of the page that needs to be stripped out.  We use a simple RegEx to strip it out so that .NET doesn’t complain about it.  Then, converting the page into an XML object is as simple as casting it with [xml].

$page = $page -replace "^.`n"
$license = [xml]$page

Finally, we just store the various XML elements in a PSCustomObject and let it pass to the pipeline.

new-object psobject | add-member -memberType NoteProperty -name LicLanguagesMax -value $license.AvXmlLicData.Licenses.LicLanguagesMax -passthru |
 add-member -memberType NoteProperty -name LicMaxMsgRecLenIsLicensed -value $license.AvXmlLicData.Licenses.LicMaxMsgRecLenIsLicensed -passthru |
 add-member -memberType NoteProperty -name LicPoolingIsEnabled -value $license.AvXmlLicData.Licenses.LicPoolingIsEnabled -passthru |
 add-member -memberType NoteProperty -name LicSubscribersMax -value $license.AvXmlLicData.Licenses.LicSubscribersMax -passthru |
 add-member -memberType NoteProperty -name LicUMSubscribersMax -value $license.AvXmlLicData.Licenses.LicUMSubscribersMax -passthru |
 add-member -memberType NoteProperty -name LicVMISubscribersMax -value $license.AvXmlLicData.Licenses.LicVMISubscribersMax -passthru |
 add-member -memberType NoteProperty -name LicVoicePortsMax -value $license.AvXmlLicData.Licenses.LicVoicePortsMax -passthru |
 add-member -memberType NoteProperty -name AvLicUtilizationSecondaryServer -value $license.AvXmlLicData.Utilization.AvLicUtilizationSecondaryServer -passthru |
 add-member -memberType NoteProperty -name AvLicUtilizationSubscribers -value $license.AvXmlLicData.Utilization.AvLicUtilizationSubscribers -passthru |
 add-member -memberType NoteProperty -name AvLicUtilizationVMISubscribers -value $license.AvXmlLicData.Utilization.AvLicUtilizationVMISubscribers -passthru

The sample output looks like this:

LicLanguagesMax                 : 2
LicMaxMsgRecLenIsLicensed       : 1
LicPoolingIsEnabled             : 1
LicSubscribersMax               : 15500
LicUMSubscribersMax             : 0
LicVMISubscribersMax            : 0
LicVoicePortsMax                : 96
AvLicUtilizationSecondaryServer : 0
AvLicUtilizationSubscribers     : 8190
AvLicUtilizationVMISubscribers  : 0

Enjoy! :)

- Robbie

Share and Enjoy:
  • Digg
  • Technorati
  • Facebook
  • del.icio.us
  • StumbleUpon
  • Reddit

I was looking for a Powershell script that would capture raw IP packets on the network and shove them into an object, but the only one I was able to find was a commercial cmdlet that was out of my budget. So, I decided that I would attempt to write my own. I figured it would be a great learning exercise (and it was), but I went into the project with the goal of avoiding any 3rd party software, to avoid compiling anything (like a cmdlet written in C#), and I didn’t want to install a driver shim. In other words, I wanted a plain ‘ol script that could be run on any computer.

I basically spent a lot of time googling and I got a lot of help from the guys over in the #Powershell IRC channel (irc.freenode.net). All of that combined with trial-and-error, I give you…. *drumroll* get-packet.ps1.

The script recognizes IPv4 TCP, UDP, ICMP, and IGMP packets (for now). The thing that took me the longest amount of time trying to figure out was how to get all packets that the network card was seeing on the wire, not just packets destined for my IP address and a particular port number. The solution was hard to find but wasn’t terribly difficult to understand.

# Create a new socket... SocketType should be Raw, and ProtocolType must be IP for promiscuous mode.
$socket = new-object system.net.sockets.socket([Net.Sockets.AddressFamily]::InterNetwork,[Net.Sockets.SocketType]::Raw,[Net.Sockets.ProtocolType]::IP)
 
# Include the IP header so we get the full packet
$socket.setsocketoption("IP","HeaderIncluded",$true)
 
# bind to a local IP address$ipendpoint = new-object system.net.ipendpoint([net.ipaddress]"$localIP",0)$socket.bind($ipendpoint)
 
# this switches the NIC driver into promiscuous mode.  This requires admin rights.
[void]$socket.iocontrol([net.sockets.iocontrolcode]::ReceiveAll,$byteIn,$byteOut)

I read somewhere that .net sockets really just uses winsock under the hood, so it really helped my understanding to read both the winsock and dotnet documentation regarding sockets on msdn. I won’t bother repeating what that documentation says here but if you’re trying to decypher this script and can’t quite figure it out, feel free to ask questions and I’ll try to explain.

Something else that I probably knew at one point but had since forgotten was that the byte order on the network wire is reversed. On the wire it is “Big Endian” and on the PC it is “Little Endian.” Wikipedia has a great explanation on Endianness. Figuring out how to interpret the IP packets was the next biggest time suck and endianness was a large part of it. Once I realized that NetworkToHostOrder didn’t support unsigned ints, I simply wrote a few functions to reverse the byte order (from “Network” to “Host”) and used BitConverter to return the correct data type.

# Takes a 2 byte array, switches it from big endian to little endian, and converts it to uint16.
function NetworkToHostUInt16 ($value) { [Array]::Reverse($value) [BitConverter]::ToUInt16($value,0) }
 
# Takes a 4 byte array, switches it from big endian to little endian, and converts it to uint32.
function NetworkToHostUInt32 ($value) { [Array]::Reverse($value) [BitConverter]::ToUInt32($value,0) }
 
# Takes a byte array, switches it from big endian to little endian, and converts it to a string.
function ByteToString ($value) { $AsciiEncoding = new-object system.text.asciiencoding $AsciiEncoding.GetString($value) }

After getting all the data out of the packets, I shove the ones I really want into a psobject. When running the script, it will be visually more appealing if you pipe the output to format-table.

PS C:\> ./get-packet.ps1 | ft

There are a lot more protocol types that I could be looking for, and I’ll probably add some of the more common ones eventually. I’ve also looked into adding support to export and import the libpcap file format, but after looking at the libpcap source code, there’s a lot of ugly in there that I might just avoid for now.

If you find any bugs or have any ideas on optimizing the code, let me know!

Enjoy!

- Robbie

Share and Enjoy:
  • Digg
  • Technorati
  • Facebook
  • del.icio.us
  • StumbleUpon
  • Reddit