Sunday, October 9, 2011

Increasing the size of your VirtualBox drive

Ok, so I never got round to finishing the Migrator.Net post. It's almost there but things got a bit busy and it fell by the wayside. Tonight though, I ran into a little wrinkle that I thought I'd blog about before I forget or lose interest.

I've been playing around with MSDeploy quite a bit, and needed a Server 2008 R2 install as a test machine. I cranked an instance up in Virtual Box, but only gave it a 10GB dynamically resizing drive.
This was the same stupid mistake I've made before, but I didn't remember until too late, that rather than starting at 10GB and dynamically expanding upwards, this would limit my dynamic drive to a MAX of 10GB.

I know, I know, I'm a dick, 10GB is not enough and never would be. Two hours after creating it I ran out of space and wanted to upsize. The idea of creating a new disk and reinstalling everything, or mucking around with some partitioning/clone tool made me bored and angry (borgry?) just thinking about it.

Then I came across this post on how to easily increase your VirtualBox drive size. It works like a bloody charm.

Basically, you make yourself a new VM with a bigger drive and the same settings as your original except set the IDE controller to be PIIX3.

Then set the drive of the new VM as the primary IDE slave on your small VM, and boot the old small VM back up.

Download Acronis Easy Migrate. It's a commercial product but has a 15-day trial, which is long enough to recover from your stupidity. Install it on the original VM, start it up, choose to Clone Drive, click next through the rest of the wizard, and it will copy the contents of your old VM to your new drive, just like that. You don't even have to know or care what it's doing.

Took about 5 mins to copy my 10GB to my new 30GB drive.  Then I just deleted the old disk and booted up into my nice, spacious new one. Ahhhhhh. Relief, and only half an hour out of my day.
 

Wednesday, September 21, 2011

Upcoming posts

Soo… Things have been a little quiet on the blog front. In the past few months I've sat exams, moved countries, changed jobs and renovated our house (*not in that order) and motivation for sitting in front of a computer in my personal time has been low. I say low, but actually, I mean non-existent.

Anyway, getting my new team and environment set up has given rise to a lot of fun new research and fires that have needed fighting. As a result, I have a long list of things that I'll probably be blogging about in the near future. 

On "The List"
  • WCF NetMSMQBinding and WAS activation
  • Dependency injection with WCF/MVC and the Unity 2.1 application block
  • Build and test install w/ TeamCity
  • WiX
  • some other stuff that I'll add as it comes up
Looking forward to it

Now that's out of the way, can I just mention that keyboards in my newly-adopted country have important keys in the WRONG PLACES? Why oh why would you put the @ key where the colon should be? And the hash where the speech marks should be? Don't even get me started on the stupid little Shift key. What makes it worse is that my workmates don't even realize how wrong it all is. They're perfectly happy touch-typing away while I'm still swearing and hunting for the damn backslash...

Saturday, June 18, 2011

Getting Skim notes to appear in a PDF on your IOS device

Having passed my Flex 4 ACE exam yesterday (84%, apparently I still need to work on my AIR), I'm on to studying for my first Microsoft MCPD exam, the MCTS prereq 70-536.


The first thing I realised this morning, is that the ebook that I'm studying from has errors. No biggie, I found the errata list, and decided to use Skim to modify the PDF with the correct details.


All was sweet, Skim is awesome, but when I exported my PDF with embedded notes and synced it to my iPhone, the notes didn't show. Meh. It'd show fine in Preview (although the thumbnail was still incorrect), but not on my iPhone.


How to fix:
  • Open the PDF in Skim
  • File > Print > expand PDF dropdown > Open PDF in Preview
  • In Preview, save the file as a new PDF
  • Sync to your IOS device
The notes will now be visible.

Cheers, poster at macworld.com, for the info.

Tuesday, May 31, 2011

Setting SSL port bindings in IIS7 with Installshield 2011

Improved code formatting at my new blog: http://growlycode.wordpress.com/2012/03/22/setting-ssl-port-bindings-in-iis7-with-installshield-2011/

Ok, so it's another non-Flex-related post, but I've been doing a lot of .NET work lately, so I'm going to sneak a bit of it in here.

I finally solved the issue I was having setting HTTPS port bindings in InstallShield 2011.

First off, you can't do this via the InstallShield UI for IIS 7. There's an option "SecureBindings" under "Other IIS Properties" in the InstallShield website UI, but this only works for IIS 6. If you want pure, unadulterated IIS 7 support, you need a custom action (CA) that manually sets the port using InstallScript or VBScript.

Caveat emptor!! I am not a windows installer developer. It took me a lot of trial and error to get this going.
If you have a suggestion of a more correct or nicer way of doing things, please leave me a comment.

In the meantime, in the hope that it will save someone else from having to do the same thing, here is what I eventually came up with:

Create an InstallScript CA, called SetSecurePortBindings
This CA will need to be "Deferred" in order to run after the IIS installation is done.
In deferred mode, you won't have access to any non-public installer properties, so if you're setting your ports from properties (e.g. [MYSITE_HTTPS_PORT]) that you set from a config or user dialog input, you'll need to make sure that you store any props you need in your deferred CA in the CustomActionData property for that CA.
I scheduled the custom action After InstallServices but any time after IIS install should be fine. My CA calls the SetSecurePortBindings function.




SetSecurePortBindings then makes a call to ensure that the current IIS version is not IIS 6 (we only support IIS6 and 7). If it is, the function will return, as the values will be set via the SecureBindings entry. If not, the function proceeds to read the site names and port numbers from the CustomDataAction. As I have a number of sites to handle, I have passed a delimited list of properties and am using the string tokeniser function to parse them out into a list.  Then, for each SiteName;PortBinding pair, I call the SetSecurePortBinding(hMSI, siteName, httpsPort) function. 


export prototype SetSecurePortBindings(HWND);
prototype SetSecurePortBinding(HWND, STRING, STRING);
prototype int IISRTGetIISVersion();

/**
 * Sets secure http port bindings using AppCmd.exe. Required for IIS7.
 * This script should be called from a Deferred Custom Action (After InstallServices in my case) and therefore
 * will need to extract any installer properties from the CustomActionData property.
 * The CustomActionData property is populated via a property-set CA (After InstallInitialize),
 * which sets the values of the properties that need to be passed along into a property by the
 * same name as the utilizing CA.
 */
function SetSecurePortBindings(hMSI)
    STRING customActionData, name, httpsPort;
    LIST listProps;
    NUMBER nvSize, nResult, nTokenCount, nCount;
    int nIISVersion;
begin
    SprintfMsiLog("SetSecurePortBindings: %s", "Entered SetSecurePortBindings");   
    if MAINTENANCE != TRUE
    then
        nvSize = 256;
       
        SprintfMsiLog("SetSecurePortBindings: %s", "Non-maintenance operation, proceeding with CA");   

        // If IIS, return, this will be handled by the SecureBindings IIS6 Metabase compatibility
        // module
        nIISVersion = IISRTGetIISVersion() ;
        SprintfMsiLog("SetSecurePortBindings: Detected IIS version '%i'", nIISVersion);   

        if (nIISVersion == 6) then
            SprintfMsiLog("SetSecurePortBindings: IIS6 detected. Returning, as, this will be handled by the SecureBindings IIS6 metabase entry", "");   
            return ERROR_SUCCESS;
        endif;

        // CustomActionData stores the sites and https ports to be configured, in a ; delimited list
        // e.g. Sitename1;*:443:;Sitename2;*:444:
        MsiGetProperty (hMSI, "CustomActionData", customActionData, nvSize);
       
        // Split the properties on the semi-colon delimiter
        listProps = ListCreate (STRINGLIST);
        if (StrGetTokens (listProps, customActionData, ";") > 0) then
            SprintfMsiLog("SetSecurePortBindings: Failed to get tokens from CustomActionData content %s", customActionData);   
        else
       
            nTokenCount = ListCount(listProps);
            SprintfMsiLog("SetSecurePortBindings: Found %i tokens in CustomActionData content %s", nTokenCount, customActionData);   
           
            // Iterate through each block of two (name;port) and call the SetSecurePortBinding method
            nCount = 0;
            while (nCount < nTokenCount)

                if (nCount == 0) then
                    ListGetFirstString(listProps,name);
                else
                    ListGetNextString(listProps,name);
                endif;
                ListGetNextString(listProps,httpsPort);
               
                SetSecurePortBinding(hMSI, name, httpsPort);   
                nCount = nCount + 2;
               
            endwhile;
        endif;
    else
        SprintfMsiLog("SetSecurePortBindings: %s", "Maintenance operation. Skipping...");   
    endif;
end;


/**
 * Returns IIS version detected via registry key
 */
function int IISRTGetIISVersion()
    NUMBER nResult, nVersion, nType, nSize;
    STRING szName, szValue;
begin

    SprintfMsiLog("SetSecurePortBindings: %s", "Attempting to find IIS major version");   

    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE );

    szName = "MajorVersion";

    nSize = -1;
    nType = REGDB_NUMBER;
    nResult = RegDBGetKeyValueEx("SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters", szName, nType, szValue, nSize);
    if (ISERR_SUCCESS != nResult) then
        return nResult;
    endif;

    nResult = StrToNum(nVersion, szValue);
    if (ISERR_SUCCESS != nResult) then
        return nResult;
    endif;

    RegDBSetDefaultRoot(HKEY_CURRENT_USER );

    return nVersion;
end; 
The SetSecurePortBinding function calls the appcmd.exe util (the new MS-sanctioned way to interact with IIS7) to set the secure port for the named site.

/**
 * Calls AppCmd.exe to set https port bindings
 */
function SetSecurePortBinding(hMSI, svSiteName, svHttpsBinding)
    STRING strMsg, svCall, svCmd, svProg, svParms[500], svOut;
    NUMBER nResult, nLineNum, n;

begin

    SprintfMsiLog("SetSecurePortBindings: Attempting to set port bindings for site '%s' to %s", svSiteName, svHttpsBinding);   

    // IIS 7 setup
    // Check for the correct application pool first
    svCmd = "cmd";
    svProg = " /C " + WINDIR ^ "system32" ^ "inetsrv" ^ "appcmd.exe";
    svCall = " set site /site.name: "+svSiteName+" /+bindings.[protocol='https',bindingInformation='"+svHttpsBinding+"']";   
    svParms = svProg + svCall;
   
    SprintfMsiLog("SetSecurePortBindings: Executing 'cmd %s'", svParms);
    nResult = LaunchAppAndWait(svCmd, svParms, WAIT | LAAW_OPTION_HIDDEN);

    if ( nResult == -1 ) then
        SprintfMsiLog("SetSecurePortBindings: Failed to set set binding. Return value %i", nResult);
        return nResult;
    endif;
   
    SprintfMsiLog("SetSecurePortBindings: %s", "Binding successfully set");
   
    return ERROR_SUCCESS;
end;

Monday, May 30, 2011

How to fix "The specified service has been marked for deletion"

Well, chances are, you're trying to uninstall a windows service.
This error tends to happen when you don't stop the service before attempting to uninstall it or/and some associated process or handle hangs around, preventing the service from being uninstalled.

One common culprit is services.msc - it's particularly bad because if you've been a good little monkey and stopped the service before running your uninstaller, you probably still have the services.msc window open.

Before you go restarting the machine etc, MAKE SURE YOU CLOSE SERVICES.MSC, in your session and any other active rdp session.

If you close and reopen the console, you'll probably find that your service has now been successfully deleted.

Sunday, May 29, 2011

Creating the ASP.NET Session State DB

So I know where to look this up the next time I re-forget it, the following cmd creates a session state db using integrated security.


C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_regsql.exe -ssadd -sstype c -d ASPState -S (local) -E 

Where:

S - db host/instance
E - use integrated security



Ensure that the login is also granted sysadmin privileges

To add the appropriate permissions:


use ASPState
grant EXECUTE on GetHashCode to "DOMAIN\Username"
grant EXECUTE on GetMajorVersion to "DOMAIN\Username"
grant EXECUTE on TempGetAppID to "DOMAIN\Username"
grant EXECUTE on TempGetStateItem to "DOMAIN\Username"
grant EXECUTE on TempGetStateItem2 to "DOMAIN\Username"
grant EXECUTE on TempGetStateItem3 to "DOMAIN\Username"
grant EXECUTE on TempGetStateItemExclusive to "DOMAIN\Username"
grant EXECUTE on TempGetStateItemExclusive2 to "DOMAIN\Username"
grant EXECUTE on TempGetStateItemExclusive3 to "DOMAIN\Username"
grant EXECUTE on TempGetVersion to "DOMAIN\Username"
grant EXECUTE on TempInsertStateItemLong to "DOMAIN\Username"
grant EXECUTE on TempInsertStateItemShort to "DOMAIN\Username"
grant EXECUTE on TempInsertUninitializedItem to "DOMAIN\Username"
grant EXECUTE on TempReleaseStateItemExclusive to "DOMAIN\Username"
grant EXECUTE on TempRemoveStateItem to "DOMAIN\Username"
grant EXECUTE on TempResetTimeout to "DOMAIN\Username"
grant EXECUTE on TempUpdateStateItemLong to "DOMAIN\Username"
grant EXECUTE on TempUpdateStateItemLongNullShort to "DOMAIN\Username"
grant EXECUTE on TempUpdateStateItemShort to "DOMAIN\Username"
grant EXECUTE on TempUpdateStateItemShortNullLong to "DOMAIN\Username"
go

Friday, May 27, 2011

I'm ACE...

By "ACE", I mean that as of 8:45am this morning, I'm an Adobe Certified Expert in Flex 3 with AIR.

The exam was interesting.

To be honest, I think it'd be relatively easy to fail even for an experienced dev. A lot of the questions are basic, but some are tricky purely because they're so specific. I don't know about the rest of you, but I don't tend to keep screeds of syntax and namespaces in my head. I generally know vaguely what I  need, and what it's probably called (or should be called)... Intellisense gets the me rest of the way there. And if there was anything I was unsure of, a google would remind me quickly enough.

The ACE exam is not at all like that. You WILL get questions about class/event/method names, and it doesn't matter how easy it is to look it up in the real world. Moral of the story, kids - don't make the mistake of thinking that just because you're a good Flex developer and work with Flex 8 hours a day, you'll be sweet.

At least scan EVERYTHING in the livedocs or you're going to get thrown by obscure questions about the AIR update process or the correct name of the event dispatched in blah situation. Or something else you've never used before, won't ever use, and don't much care about.

You don't find out at the end which questions you got right/wrong, just your overall percentages. The questions I assume I got right, I knew without a shadow of a doubt. The ones I didn't know, I really didn't know, no idea whatsoever - any I got right out of the ones I "flag[ged] for review" were dumb luck.


Anyway, onwards and upwards!

Now I'm quite looking forward to my Flex 4 exam next month. These days I'm far more current with the Gumbo/Hero nitty-gritty than with Flex 3 and I've been itching for a chance to do a Flex 4 skinning deep-dive. Muwahaha. Should be great...