Transitioning From VB Script to Powershell

VB Script is still around and will be for quite a while yet.  But current Windows technology is all about Powershell.  As well it should be, as PS is vastly superior in many, many ways.

However, a lot of us still have old VB scripts hanging around, probably doing production work... and what I’m about to show you may be the trickiest part of porting those old scripts over into Powershell. 

As you probably know, Powershell fully harnesses the power and flexibility of .NET, while VB Script was only capable of working with COM objects.  Almost everything that can be done with COM objects can be done faster and easier with .NET.  (For the foreseeable future at least - I hear COM is making a bit of a comeback in Windows 8...)  However, Powershell is still fully capable of working with COM objects too.  What that means is that those of you who are still more comfortable with VB script or have a lot of script to port over in a hurry, well, you don’t have to worry about finding .NET equivalents for those COM objects. (Even if there might be a better, more Powershell-native way of doing it.) 

Let’s take Microsoft Cluster Services for example.  Here’s what you would see in a VB script that deals with cluster resources: 


Set oCluster = CreateObject("MSCluster.Cluster")


 In Powershell it’d be something like this: 


$cluster = New-Object –COMObject MSCluster.Cluster


 Now  you have your cluster object.  Want to see what all members it has?  (The properties of it + its methods/what all it can do?) 


$cluster | Get-Member


 Alright well I see that $cluster is basically an object collection that has, among other things, a ResourceGroups object in it, so let’s open that up: 


$ResourceGroups = $cluster.ResourceGroups


 And then do a $ResourceGroups | Get-Member to see what we can do with that: 


PS C:\Users\ryan> $resourceGroups | Get-Member

   TypeName: System.__ComObject#{f2e60706-2631-11d1-89f1-00a0c90d061e}

Name                MemberType Definition
----                ---------- ----------
Delete              Method     void Delete ()
Move                Method     Variant Move (Variant, Variant)
Offline             Method     Variant Offline (Variant)
Online              Method     Variant Online (Variant, Variant)
Cluster             Property   ISCluster Cluster () {get}
CommonProperties    Property   ISClusProperties CommonProperties () {get}
CommonROProperties  Property   ISClusProperties CommonROProperties () {get}
Handle              Property   ULONG_PTR Handle () {get}
Name                Property   string Name () {get} {set}
OwnerNode           Property   ISClusNode OwnerNode () {get}
PreferredOwnerNodes Property   ISClusResGroupPreferredOwnerNodes PreferredOwnerNodes () {get}
PrivateProperties   Property   ISClusProperties PrivateProperties () {get}
PrivateROProperties Property   ISClusProperties PrivateROProperties () {get}
Resources           Property   ISClusResGroupResources Resources () {get}
State               Property   CLUSTER_GROUP_STATE State () {get}

So hopefully this is starting to pique your interest.  With this sort of information you could easily script out whether all the cluster resource groups were on the correct nodes, and even move them if need be.  Pretty neat stuff.

I leave you with this - don't you hate it when this happens?

F'ed up log

2012 Scripting Games Post-Game

So I finished up my participation in the 2012 Scripting Games Advanced category a few days ago. They haven't finished all the grading yet, but all the events have been completed. (10 total scripts in 10 business days.) Here are few of my takeaways:

  • It was 100% Powershell, so it really should have been called the Powershell Games, but I realize Ed's blog used to have a lot of VB Script on it too before PS really came into the spotlight, so I guess the name is sort of legacy. His blog is not known as "Hey, Powershell Guy!" after all. Besides, I don't know of anyone else holding a similar event, so I guess he gets to use whatever name he wants.
  • I don't think there's any chance of me winning first place in the Advanced category, but I should (hopefully) finish in the top 10. Which, I guess isn't all that bad considering how many participants there were from all over the world. Leaderboards should be viewable here, but like I said the grading is not finished yet and so the leaderboards are still going to be changing.
  • The Games were reasonably challenging, and I did learn a few new tricks and best practices along the way. For instance, creating my own custom objects, and adding those to a collection of objects, has become much more natural for me. I will probably post all of the scripts I wrote and some commentary about them in a later post - I want to make sure the deadlines for the Games are completely passed before I do that.
  • Even though several days were given to complete each event, I turned in my submission for each event on the same day it was released. I have a pretty single-track mind when it comes to things like finishing code. It's often all I can think about or concentrate on until I finish, especially if there's any sort of deadline involved. Not only that, but I have other things like a job which also demand my time and energy -- unlike those damn Germans with their 6 days off for Easter holiday and 2 months a year of vacation. (Just teasing, Germany.)
  • I felt like a couple of the scenarios were not very well-defined. One could start scripting for the scenario given, but then several hours later go back and see several confused reader's posts, asking for Ed to clarify a certain piece of the scenario, and then after reading Ed's responses, do something differently in your own script. Even worse, I saw some inconsistency in the way different judges judged people's scripts. For instance, Ed posted the official rules and grading criteria before the games began. One of those grading criteria was "avoid using aliases." I think that's perfectly reasonable, as aliases are good for quick, interactive commands, but when writing a long, complex script, aliases often make it even harder for someone else to follow. (Aliases are things like "?" instead of "Where-Object" or "gci" instead of "Get-ChildItem.") But, browsing the judge's comments of other people's scripts, I would see a judge commenting on the participant's "excellent use of aliases!" So in that regard I don't feel like all the judges were on the same page, which is unfortunate, because it seems like only 1, and maybe sometimes 2, of the ~35 total judges ever grade any one script, so depending on exactly which judge you get will significantly impact your score.
  • I don't like a judge giving me a score on my script, but not leaving any comments at all. (Especially if it's a crappy score like 3/5.) That said, I understand that the judges are all just volunteers that have their own lives, and there are hundreds of participants, so the judges are overworked and probably in a hurry.

So all in all, even if my comments above sound negative, I'm really meaning them to be constructive. I did enjoy the 2012 Scripting Games and I'm really happy that Ed put forth the time and effort (which I know must have been substantial) to organize them!

ORS - Office Rageface Sender


If you work in an office in a corporate environment like I do, you're probably familiar with Microsoft Office Communicator, often referred to as OCS. These days they call it Lync -- but it's still most widely known as OCS. Anyway, it's an IM client that you can use to communicate with your bosses... and for them to see when you're taking a bit too long of a lunch break. The one thing it doesn't do, however, is quickly paste pictures for others to see. A picture is worth a thousand words, right? So I set out this last weekend to remedy this situation.

What I ended up with a couple days later is what I'm calling ORS - or Office Rageface Sender. A coworker of mine is very fond of those ragefaces that seem to be all the... rage... lately, but it's difficult to make those jokes without actually being able to show the relevant picture to go with it. 

Currently, ORS is a network application, but only works within your current subnet, because it uses UDP broadcasts as a "discovery" mechanism to discover peers on the network (i.e. other people also running ORS) to populate your contact list. In addition, TCP port 9068 is used for direct communication. 

Upon launching ORS for the first time, you will be asked for your nickname. You can change it at any time by clicking the status bar at the bottom of the main window. Your nickname will be saved in the registry so it won’t ask you every time you launch the app. The effects of duplicate nicknames on the network hasn’t been thoroughly explored, (hey I’m only one guy) but they should be minimal as communications are typically IP-based. 

Also when you launch ORS for the first time, it will create an Images folder at the same location where the executable is running. Dump all your favorite images here. Optimally, they should be as close to 512x512 as possible, as they will be displayed in a 512x512 window. However, images larger than that will be automatically scaled down to fit. Images smaller than that will be centered (not stretched.) 

When you right-click on a person’s name in the main window, a context menu will pop up which contains a list of all the images currently in your Images directory. This list and context menu is dynamic, so you don’t need to relaunch the app every time you modify the contents of your images directory. By clicking an image name over a contact, that image will be displayed on their screen in real-time. 

If the recipient does not currently have the image that you are trying to send them, you will automatically send it to them over TCP, it will be saved to their own Images directory, and then displayed normally. If they already have the same image (as determined by name,) that local image will be displayed. If two users have the same filename in their images directory but are actually different pictures, then the recipient will see a different image than the one you intended. 

The application minimizes to the system tray. You can right-click the icon to exit the app, or just close the form. 

If you’d like to give this a try when you’re in the same broadcast domain with one or two other people, you can download the program at the very end of this post. I very much welcome bug reports, feature requests, etc. You probably don't want to run this with a bunch of people you don't trust, as it would be possible for them to flash pictures of boobs on your screen if they wanted to.


Finally, here are some stats on how much broadcast traffic each client sends, just to prove how nominal it is. About 1 packet every 10 seconds. 

Avg packets/sec 0.128
Avg packet size 75 bytes
Avg bytes/sec   9.587

ORS.exe (93.00 kb)

The Logitech G9x Mouse


I need to write a new post - it's been too long!

So I got a new mouse a few weeks ago. My old trusty Basic Microsoft Optical mouse was still chugging along just fine after a couple years of abuse, but the buttons were getting a little loose. So I decided it was time for an upgrade. After a little research, I settled on the Logitech G9x Laser Gaming mouse. Now, along with my Das Keyboard, I have an embarrassing amount of money invested into my input devices. I'll try to hit on most of the pros and cons.

I have to say, I'm pretty impressed with it. It has two interchangeable shells to better fit your hand. I've been using the fatter of the two. I feel like I have too much of a "claw" grip on the mouse when I use the smaller shell, which ends up tiring my hand, but on the other hand (no pun intended,) the left outer edge of the bigger shell sort of scrapes on my mousepad as I pick up the mouse at an angle to drag it back over to the left. (You know, when you've veered too far to the right on your mouse pad and you need to pick the mouse up and bring it back to center.) The effect is not terrible, but it's something that my old mouse didn't do. I just need to train myself to pick my mouse up at a flatter angle when I need to move it around the mousepad.

The two buttons on the side are something else I was not accustomed to, but I've already grown fond of them. I always used to steer clear of any mouse that had extra buttons. I used to just want a left button, a right button, and a mousewheel and that's it. I just knew that I would always be accidentally hitting any extra buttons. Well, it just takes a little getting used to and you learn to like them. I very rarely hit them on accident. They are amazingly handy for web browsing, as I use that back button a lot. I already can't believe that I used to drag my pointer up to the browser's back button every time I wanted to move back a page. That said, going back in my web browser is pretty much all I've used the side buttons for so far.

The scroll wheel is probably my least favorite thing about this mouse. It does have a hardware toggle button on the bottom of the mouse for if you want the wheel to scroll smoothly, or if you want that "bump bump bump" feeling as you scroll it. Well, I'm one of those people that definitely needs the bumps/tactile feedback, so you click this little "microgear" button on the bottom of the mouse and there it is. However, the middle mouse button (pushing down on the mouse wheel) is extremely difficult. In fact it takes so much force to depress the middle mouse button, that you can pretty much forget about precisely pointing at something small on the screen and middle-clicking it without the wheel or the entire mouse moving, or both. I don't know if disengaging the microgear would make that any better. It doesn't matter, because I can't have my scroll wheel being all loosey goosey anyway. Maybe it'll loosen up over time, as my keyboard has. Also, the wheel has left and right play too... see those little arrows on the sides of the mousewheel? Yeah, that sucks. Ironically it's not hard at all to accidentally actuate the left or right action. I have no use for that. I do accidentally hit those all the time, which interrupts the middle-click scroll if you're one of those people that like to middle-click on a page and then pull the pointer down to scroll down the page. Luckily, with the configuration software I was able to map those left and right actions to do nothing... which leads me to:

The software. I'm a minimalist, at least when it comes to my computer. I'm one of those people who almost never has icons on their desktop. That means I do not want to install more software on my computer and have another useless system tray icon sitting down there just to be able to configure my bloody mouse. However, there are some things that you can only do with that proprietary software, such as change the LED colors (I changed mine from red to blue to match my keyboard and monitor,) and re-map all those non-standard buttons. But luckily, all your configuration changes are saved inside the mouse, so once you've got it set up how you like it, you can uninstall the software for good. Even unplugging the mouse and using it on a different computer doesn't reset the custom settings. Furthermore, if you have internet access, the mouse's basic functionality is plug and play as Windows can automatically download a G9x driver from Windows Update.

The mouse also comes with this tin full of 4-gram and 7-gram weights. There is a slide-out tray inside the mouse that you can actually fit these weights into in various configurations to precisely give your mouse the weight that you desire. Now maybe I'm just not pro enough to really realize the benefit of this, but it just doesn't really make much difference to me. My hand seems to be able to adjust just fine to whatever weight the mouse is. However, I could see how weights could mitigate that overcompensation you get in games when you try to react quickly.  The jury is still out on this feature.

Now, I want to talk about the thing that really makes the mouse awesome. It's the DPI switch just under the left mouse button. Having the ability to increase and decrease the sensitivity on the fly has basically added a whole new dimension for me, particularly in certain games.  Imagine a game of Battlefield 3 where you can slow your mouse down to the precision of a surgeon's scalpel when scoped in, and then bring it back up to speed when you zoom out and go back to running around, all without ever taking your eyes off the game? It's pretty amazing. You may not all agree on all the design decisions employed by this mouse, but all mouse manufacturers should take note of this great feature.

C# applications with "install" or "setup" in the name and Application Compatibility

Hello ladies and gents.

I've been busy the past few days creating a very complex (for me) .NET application in C#. I want to talk about an issue that I banged my head on for a few hours, because the solution is out there and easy to find on the internet, but every person who posted the answer on a forum or MSDN article was making an assumption that I knew something already that I didn't know in order to arrive at the solution, and so that missing piece of knowledge was keeping me from joining the ranks of those who knew how to solve this problem. What can I say, I'm a novice programmer.

I'm using Visual Studio 2010, and I have created a C# project. I'm using Windows 7 64bit. This project that I have created has the word "install" in the name. Apparently, any time that Windows Vista or 7 see the user executing a program that has the word "setup" or "install" in it, it triggers something deep within the bowels of Windows to cough up this incisive message:

appcompat*Thank you that's very helpful now go away*

I don't like the principle behind this behavior. I have read that this box will only pop up if you have the magic word in your executable name and that executable does not add an entry to the Add/Remove Programs list by the time it exits, which could indicate a failed installation. Or it could indicate nothing went wrong at all, which from my experience is the case 100% of the time. In fact I'd be scared to hit that "Reinstall using recommended settings" button, because I definitely have no idea what that might do. Furthermore I've read that some install applications do put a new entry in the Add/Remove Programs list and yet it still generates this popup.

I've been using Windows Vista and Windows 7 for a long time, and I have never once found this to be helpful in any way. But now this behavior has really gone and annoyed me by popping up every time I test during my development.

So I started researching the problem and I was immediately led to believe that this could be easily solved by editing the manifest file in my application's project in Visual Studio. Here is what you add to your manifest file to make it not show that Program Compatibility popup:

<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
      <!--The ID below indicates application support for Windows Vista -->
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
      <!--The ID below indicates application support for Windows 7 -->
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>

OK... I can't find my manifest file. I've looked through all the menus and tabs and buttons here in Visual Studio... hrm... maybe I just need to edit this installer.manifest file that's sitting in the same output directory as my application and then rebuild it! Nope, that didn't work. It just seems to wipe out my changes and revert the file to default every time I build the solution... my project settings were set to "Embed manifest with default settings."  So even though the default manifest was there in the output directory, any modifications you make to it just get wiped out.

Finally, I realized that I just need to generate a new manifest file for myself. In the Solution Explorer pane, right-click your project and choose "Add --> New Item..." and add an "Application Manifest File." It should pop up under the Resources folder in your project, whether you already had one or not. Now you can edit that manifest to your heart's content, and the changes will not get wiped out. You'll notice that the section of XML I pasted above sort of already exists in your new manifest file, so just use your head and paste in only the couple of relevant lines in the right places. ;)  You will also notice that if you go back to your Project's properties, you should see it pointing at the manifest file you just created, instead of saying "Embed manifest with default settings."

No more "Program Compatibility Assistant" popup!  I feel like an idiot sometimes...

Now  that you know about creating and editing your own application manifest file, you are well on your way to doing other things with it, such as having the application request its own administrator access from UAC, instead of, say, simply checking to see whether the current user is an administrator or not, and then having the application say "Sorry, you're not an administrator so I won't run.  Please try executing the program again by right-clicking on my icon and choosing 'Run as administrator...'" Which unfortunately I have seen too many times. Follow up with this article.