Tuesday, September 15, 2015

Disable F1 Windows Help and Support on Windows 8.1

One of the most useless things built into windows is the F1 help, unfortunately Microsoft doesn't make it easy to disable. I think I can say that I may have found the F1 help useful once, and that is probably pretty generous.

Below is a Powershell script which will disable the F1 help in windows. Basically, it takes control over helppane.exe and then renames it. Thankfully, if windows can't find the file, it will not through an error. If you want to restore the F1 help, just rename the executable back.
takeown /f c:\windows\helppane.exe
$acl = Get-Acl "C:\Windows\HelpPane.exe"
$rule = New-Object  System.Security.AccessControl.FileSystemAccessRule("$([Environment]::UserDomainName)\$([Environment]::UserName)","FullControl","Allow")
$acl.SetAccessRule($rule)
Set-Acl "C:\Windows\HelpPane.exe" $acl
Rename-Item "C:\Windows\HelpPane.exe" "C:\Windows\HelpPane1.exe"
This may work on other versions of windows, but I have only tested this on Windows 8.1.

Thursday, September 3, 2015

Powershell Open A Windows Explorer Window And Select A File

Just a quick useful function that I have used a couple times and always forget about. If you have a script that persists a file to disk, you can open a Windows Explorer window and select the file with this function. This can be useful in desktop applications as well. I'll leave it to the reader to translate it to C# (it leverages straight-up .Net functions already).
function Show-InExplorer($file) {
 $explorerArgs = "/select, $file";
 [System.Diagnostics.Process]::Start("explorer.exe", $explorerArgs) | Out-Null;
}
NOTE: Dispite what people have said on several StackOverflow posts, I found that I had to have the comma after the /select.

Thursday, August 27, 2015

GNU Screen Awesomeness

Introduction

I have been using GNU Screen for a LONG time; it usually comes by default with every *nix distribution that I have used. It is one of my favorite tools in my *nix toolbox. Basically it allows you to multiplex your SSH session allowing the ability to switch between full screen shell windows. I recently worked on a project which used Linux and utilized the tool pretty heavily. I thought everyone knew about Screen, except my fellow developer had never heard of it, so I figured this topic would be great to share.

Basically, I can have screens for GNU Midnight Commander, MySQL REPL (sometimes I create a tunnel and use Workbench, but I don't always have access to it), my source directory, and a configuration directory. This allows me to quickly switch between different tasks/locations without having to do a lot of heavy lifting or have multiple SSH connections or change directories a lot.

This is all well and great, but it comes with another great benefit. If you are disconnected for some reason, screen will keep everything waiting for your return. You can also suspend your screen session via a keyboard shortcut and resume it just the same.

Let's get started.

Getting Started With Screen

It is really easy to start screen:
$ screen
You are in!
NOTE: The keyboard shortcuts all require the Control key, it is usually abbreviated with Ctrl, but the below will use "C-" because that is how Screen's help specifies.
Now you have a LOT of shortcuts, but below are the most basic and useful:

Create new window
C-a, c
View Windows
C-a, w
Switch to Window
C-a, # (index of the window)
Disconnecting/Detatching
C-a, d

Now, A Bit More Advanced

Name Your Session
C-a :sessionname bars
Let's test this out, create a named session.
screen -S sessionname
Enter some commands at the new prompt. And then press
C-a, d
Now you should be back where you were before you started Screen. Even if you were you were running Midnight Commander (or anything else). Now let's jump back into the session.
screen -r sessionname
That is it. So easy. Use it!

Friday, August 21, 2015

Azure Resource Manager Templates, The Missing Parts

Azure Resource Manager (ARM) is a fantastic addition to the Azure ecosystem. The fact that you can create a template for your environment is all the better. Basically, it allows you to describe all of the resources you need in an environment and have an amazing amount of configuration.

ARM templates are merely JSON files that use JSONSchema. Visual Studio gives you validation and lets you know if you reference something that is not known. The support is nice, but there are several things that do not validate, but work against Azure regardless.

A good place to start looking for template examples is the Azure GitHub repo azure-quickstart-templates. There are many examples, but from a development standpoint, good examples putting them all together are difficult to come by.

All is not rainbows and butterflies, there are limitations. To list a few:
  • If you require a GUI, you will be greatly dismayed by the offering in Visual Studio. It is extremely simplistic and you will quickly out grow it. There is, however, a very nice JSON Outline pane which will help you navigate the JSON file.
  • Database servers cannot be shared across Resource Groups.
  • Does not handle Cloud Services (Web/Worker Roles)
  • Does not handle Service Bus namespaces
  • There are a number of other services that are not supported on the new portal and not in the Resource Manager.
I am sure that in the coming months the unhandled services will be supported. It is possible to get around the these limitations via Powershell, but you don't don't get the template deployment goodness.

Build your connection strings

Assuming you are describing an Azure Web App, you can configure the configuration connectionstrings. You can build them based on other resources described in the template.
Here are examples of the ones I have been able to find:
"DefaultConnection": {
    "value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', parameters('serverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', parameters('databaseName'), ';User Id=', parameters('administratorLogin'), '@', parameters('serverName'), ';Password=', parameters('administratorLoginPassword'), ';')]",
    "type": "SQLAzure"
},
"variables": {
    "storageAccountId": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name,'/providers/','Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]",
...
"AzureWebJobsDashboard": {
    "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountId'),'2015-05-01-preview').key1)]",
    "type": "custom"
},
So this next one is a bit cheating, but it is presently the only way to make it happen (for now). I will dive more into this later.
"AzureWebJobsServiceBus": {
    "value": "[parameters('serviceBusConnectionString')]",
    "type": "custom"
},
"WebDocDb": {
    "value": "[concat('AccountEndpoint=', reference(concat('Microsoft.DocumentDb/databaseAccounts/', parameters('databaseName'))).documentEndpoint, ';AccountKey=', listKeys(resourceId('Microsoft.DocumentDb/databaseAccounts', parameters('databaseName')), '2015-04-08').primaryMasterKey, ';')]",
    "type": "custom"
},
"RedisCache": {
    "value": "[listKeys(resourceId('Microsoft.Cache/Redis', parameters('redisName')), '2014-04-01').primaryKey]",
    "type": "custom"
}

Web App With Staging Slot

Here is a good example of how to create a web application with a staging slot both containing the correct connection strings.
"variables": {
    "siteNameStage": "[concat(parameters('siteName'),'stage')]",
    "databaseNameStage": "[concat(parameters('databaseName'),'stage')]",

    "storageAccountId": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name,'/providers/','Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]",
    "storageAccountIdStage": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name,'/providers/','Microsoft.Storage/storageAccounts/', variables('storageAccountNameStage'))]",

    "storageAccountNameStage": "[concat(parameters('storageAccountName'),'stage')]"
},
"resources": [

...

    /*** Web App ***/
    {
      "apiVersion": "2015-06-01",
      "name": "[parameters('siteName')]",
      "type": "Microsoft.Web/Sites",
      "location": "[parameters('siteLocation')]",
      "dependsOn": [ "[concat('Microsoft.Web/serverFarms/', parameters('hostingPlanName'))]" ],
      "tags": {
        "[concat('hidden-related:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "empty"
      },
      "properties": {
        "name": "[parameters('siteName')]",
        "serverFarmId": "[parameters('hostingPlanName')]"
      },
      "resources": [
        {
          "apiVersion": "2014-11-01",
          "type": "config",
          "name": "connectionstrings",
          "dependsOn": [
            "[concat('Microsoft.Web/Sites/', parameters('siteName'))]",
            "[resourceId('Microsoft.Sql/servers', parameters('serverName'))]",
            "[resourceId('Microsoft.Cache/Redis', parameters('redisName'))]"
          ],
          "properties": {
            "DefaultConnection": {
              "value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', parameters('serverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', parameters('databaseName'), ';User Id=', parameters('administratorLogin'), '@', parameters('serverName'), ';Password=', parameters('administratorLoginPassword'), ';')]",
              "type": "SQLAzure"
            },
            "AzureWebJobsDashboard": {
              "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountId'),'2015-05-01-preview').key1)]",
              "type": "custom"
            },
            "AzureWebJobsStorage": {
              "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountId'),'2015-05-01-preview').key1)]",
              "type": "custom"
            },
            "AzureWebJobsServiceBus": {
              "value": "[parameters('serviceBusConnectionString')]",
              "type": "custom"
            },
            "WebDocDb": {
              "value": "[concat('AccountEndpoint=', reference(concat('Microsoft.DocumentDb/databaseAccounts/', parameters('databaseName'))).documentEndpoint, ';AccountKey=', listKeys(resourceId('Microsoft.DocumentDb/databaseAccounts', parameters('databaseName')), '2015-04-08').primaryMasterKey, ';')]",
              "type": "custom"
            },
            "RedisCache": {
              "value": "[listKeys(resourceId('Microsoft.Cache/Redis', parameters('redisName')), '2014-04-01').primaryKey]",
              "type": "custom"
            }
          }
        },
        {
          "apiVersion": "2015-04-01",
          "name": "appsettings",
          "type": "config",
          "dependsOn": [
            "[concat('Microsoft.Web/Sites/', parameters('siteName'))]"
          ],
          "properties": {
            "Demo:Environment": "PROD",
            "Test:Environment": ""
          }
        },
        {
          "apiVersion": "2014-11-01",
          "name": "slotconfignames",
          "type": "config",
          "dependsOn": [
            "[resourceId('Microsoft.Web/Sites', parameters('siteName'))]"
          ],
          "properties": {
            "connectionStringNames": [ "DefaultConnection", "AzureWebJobsDashboard", "AzureWebJobsStorage", "AzureWebJobsServiceBus", "WebDocDb", "RedisCache" ],
            "appSettingNames": [ "Demo:Environment", "Test:Environment" ]
          }
        },
    
        /*** Web App STAGING SLOT ***/
        {
          "apiVersion": "2015-04-01",
          "name": "Staging",
          "type": "slots",
          "location": "[parameters('siteLocation')]",
          "dependsOn": [
            "[resourceId('Microsoft.Web/Sites', parameters('siteName'))]"
          ],
          "properties": {
          },
          "resources": [
            {
              "apiVersion": "2014-11-01",
              "type": "config",
              "name": "connectionstrings",
              "dependsOn": [
                "[resourceId('Microsoft.Web/Sites/slots', parameters('siteName'), 'Staging')]",
                "[resourceId('Microsoft.Sql/servers', parameters('serverName'))]",
                "[resourceId('Microsoft.Cache/Redis', parameters('redisName'))]"
              ],
              "properties": {
                "DefaultConnection": {
                  "value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', parameters('serverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', variables('databaseNameStage'), ';User Id=', parameters('administratorLogin'), '@', parameters('serverName'), ';Password=', parameters('administratorLoginPassword'), ';')]",
                  "type": "SQLAzure"
                },
                "AzureWebJobsDashboard": {
                  "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountNameStage'), ';AccountKey=', listKeys(variables('storageAccountIdStage'),'2015-05-01-preview').key1)]",
                  "type": "custom"
                },
                "AzureWebJobsStorage": {
                  "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountNameStage'), ';AccountKey=', listKeys(variables('storageAccountIdStage'),'2015-05-01-preview').key1)]",
                  "type": "custom"
                },
                "AzureWebJobsServiceBus": {
                  "value": "[parameters('serviceBusConnectionStringStage')]",
                  "type": "custom"
                },
                "WebDocDb": {
                  "value": "[concat('AccountEndpoint=', reference(concat('Microsoft.DocumentDb/databaseAccounts/', variables('databaseNameStage'))).documentEndpoint, ';AccountKey=', listKeys(resourceId('Microsoft.DocumentDb/databaseAccounts', variables('databaseNameStage')), '2015-04-08').primaryMasterKey, ';')]",
                  "type": "custom"
                },
                "RedisCache": {
                  "value": "[listKeys(resourceId('Microsoft.Cache/Redis', parameters('redisName')), '2014-04-01').primaryKey]",
                  "type": "custom"
                }
              }
            },
            {
              "apiVersion": "2015-04-01",
              "name": "appsettings",
              "type": "config",
              "dependsOn": [
                "[resourceId('Microsoft.Web/Sites/slots', parameters('siteName'), 'Staging')]"
              ],
              "properties": {
                "Demo:Environment": "TEST",
                "Test:Environment": "TEST"
              }
            }
          ]
        }
      ]
    },

...

That is a lot of JSON, but very useful.

Service Buses

Services buses don't seem to be receiving the love that other Azure resources have received, but it doesn't make them any less useful.

The trick to using/maintaining Service Buses is to not use the Resource Manager template. Basically, you can use a Powershell script to create the Service Bus(es), grab the connection string(s), and then pass the connection string into the ARM template deployment as a parameter.
function Create-AzureServiceBusQueue($Namespace, $Location) {
 # Query to see if the namespace currently exists
 $CurrentNamespace = Get-AzureSBNamespace -Name $Namespace;

 # Check if the namespace already exists or needs to be created
 if ($CurrentNamespace)
 {
  Write-Host "The namespace [$Namespace] already exists in the [$($CurrentNamespace.Region)] region.";
 }
 else
 {
  Write-Host "The [$Namespace] namespace does not exist.";
  Write-Host "Creating the [$Namespace] namespace in the [$Location] region...";
  New-AzureSBNamespace -Name $Namespace -Location $Location -CreateACSNamespace $false -NamespaceType Messaging;
  $CurrentNamespace = Get-AzureSBNamespace -Name $Namespace;
  Write-Host "The [$Namespace] namespace in the [$Location] region has been successfully created.";
 }
 return $CurrentNamespace.ConnectionString;
}
You may want to dig a little deeper and this page MSDN page, Use PowerShell to manage Service Bus and Event Hubs resources, is pretty useful.

Putting It Together

With the web application resource section in a template and the Service Bus(es) created via Powershell, how do we deploy the template to put it together?
# Create the Services Buses
$serviceBusConnectionStrings = @{"Prod"=$(Create-AzureServiceBusQueue $ServiceBusName $ResourceGroupLocation);
     "Stage"=$(Create-AzureServiceBusQueue "$($ServiceBusName)stage" $ResourceGroupLocation);
     "Dev"=$(Create-AzureServiceBusQueue "$($ServiceBusName)dev" $ResourceGroupLocation);}

...

$rg = Get-AzureResourceGroup | ? { $_.ResourceGroupName -eq $ResourceGroupName };
if ($rg -eq $null) {
 # Create the Resource Group
 New-AzureResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation;
}
# Start a Resource Group deployment
$results = New-AzureResourceGroupDeployment `
  -Name WebAppDeployment `
  -ResourceGroupName $ResourceGroupName `
  -TemplateFile $TemplateFile `
  -TemplateParameterFile $TemplateParameterFile `
  -storageAccountNameFromTemplate $DefaultStorage `
  -serviceBusConnectionString $($serviceBusConnectionStrings.Prod) `
  -serviceBusConnectionStringStage $($serviceBusConnectionStrings.Stage);
Write-Output $results;
Write-Output "ServiceBus Prod: $($serviceBusConnectionStrings.Prod)";
Write-Output "ServiceBus Stage: $($serviceBusConnectionStrings.Stage)";
Write-Output "ServiceBus Dev: $($serviceBusConnectionStrings.Dev)";
This will configure the web app and populate the correct connection strings on the correct slot. Hopefully, Microsoft will add the capability to maintain Cloud Services and Service Buses soon, but until then, this will be helpful.

Monday, August 17, 2015

A Couple AutoHotKey Windows 10 Helpers

With Windows 10 comes a bunch of new features and shortcuts. I have long been a fan of VirtuaWin, it's context menu driven virtual desktop paradigm is a bit of a hurdle, but it is easy to get used to. Windows 10 brings the concept of virtual desktops to the masses. It is pretty simplistic and has much room for improvement, but probably a good starting point.

Here are a couple tweaks that make navigating multiple desktop with your mouse.
; Show Task View, Wheel/Middle click on desktop
#IfWinActive ahk_class Progman
MButton::sendevent {LWin down}{Tab down}{Tab up}{Lwin up}
Return
#IfWinActive

; Move to the desktop left of the current desktop
$WheelLeft::send ^#{Left}

; Move to the desktop right of the current desktop
$WheelRight::send ^#{Right}

Friday, August 7, 2015

R Create Data.Frame Like Read.Csv

In exploring using R.NET and RserveLink inside of C#, I ran into a couple performance issues with my scenario. In load balanced environments which will need to pull the random forests and the cached CSV data saving the files to a network share makes sense, but there is a cost. My initial process was:
  1. In C#, load and prep the data.
  2. Serialize the data into CSV format and save to a network share.
  3. Use R.NET or RServeLink, send the below commands to pull the Random Forest and the CSV data and run the data through the Random Forest.
Below is the proof of concept R code.
library("randomForest")
library("caret")

mydata = read.csv(file="IntPonAllTheData.csv",head=TRUE,row.names="IntPonID")

test.predict <- predict(readRDS('//intponsrv/Data/RandomForest/CLASS123.rf'), mydata)
write.table(test.predict)
I was able to combine several of the lines, but it didn't improve the performance very much. However, if I could remove 2 of the network and file I/O trips, that would greatly improve the performance. The only question was, how do I create a data.frame in R that would produce the same object as read.csv. I inquired to the #R freenode channel (they are awesome, check them out and stay a while) and they suggested that I look into the save function or dputs function. I was able to use dputs and serialize the data.frame. The format of the serialization wasn't an exact match, but it was close enough that I could figure out how the data.frame is structured relative to the CSV data. The following is my converted code which generates a data.frame directly.
library("randomForest")
library("caret")

df <- data.frame(Q1 = c(0.301775147928994,0.301775147928994,0.301775147928994,0.301775147928994),Q2 = c(0.301775147928994,0.301775147928994,0.301775147928994,0.301775147928994),Q2 = c(0.094674556213018,0.094674556213018,0.094674556213018,0.094674556213018),Q3 = c(0.301775147928994,0.301775147928994,0.301775147928994,0.301775147928994),Q4 = c(0.082840236686391,0.082840236686391,0.082840236686391,0.082840236686391),row.names = c("baseline","TEST1","TEST2","TEST3"))
write.table(df)

test.predict <- predict(readRDS('//intponsrv/Data/RandomForest/CLASS123.rf'), df)
write.table(test.predict)
Instead of generating the CSV, I can generate the data.frame statement with the same result. After integrating it with my C# code, this produced a 60-80% improvement in processing time per prediction, when repeatedly processing large data sets.