Sunday, January 29, 2012

PhoneGap + WP7–OpenSource MultiPlatform Mobile app development

PhoneGap is an open source mobile app development platform that allows you to create an app for Windows Phone 7 (WP7) and the same app can also be run on other app platforms. Windows Phone support was added as part of version 1.3.

Read the quick start to see how easy it to create a WP7 app.

And here are some videos on using PhoneGap with WP7: http://phonegap.com/2011/12/20/phonegap-for-windows-phone-getting-started/

And more information can be found at this blog-post: PhoneGap for WP7 dissected

Maslow’s pyramid applied to software engineering

Liked this post by Scott Hanselman, where he applied Maslow’s pyramid to software development:http://www.hanselman.com/blog/MaslowsHierarchyOfNeedsOfSoftwareDevelopment.aspx

A proposed heirarchy of needs of software - Bragging Rights, Refactorable, Maintainable, Buildable, Revisable

Read the post!

Free HDR software for Windows

I was looking for free software that would run on Windows that would aid in creating HDR images.

After about 5 minutes of searching I came across these 2:

1. Luminance HDR (qtpfsgui) and

2. Picturenaut

I am new to HDR photography, so I wasn’t very sure about all the different options in the software. But I found it a lot more easier to create a cool looking HDR image using Luminance than with Picturenaut.

Here are the input images that I used (found via a Bing search for HDR source images)

hdr01 hdr02 hdr03

-2

0

+2

This was the resulting image using Luminance:

hdr04

More to follow, once I learn a little more about the 2 softwares and get a few sample source images of my own.

10 things you should know about web.config

An excellent post that every Asp.net dev should read: http://weblogs.asp.net/jgalloway/archive/2012/01/17/10-things-asp-net-developers-should-know-about-web-config-inheritance-and-overrides.aspx

Monday, January 23, 2012

Windows authentication fails when using hosts file IIS

You can use the hosts file (C:\Windows\System32\drivers\etc\hosts) to setup a mock host-name for local development/testing. Here is an example: I want to use http://helloworld/ locally to point to a test website.

1. Add an entry for helloworld to the hosts file.
image

This means that the url helloworld will be looped back to your local machine

2. Next in IIS Manager, right click on your site and select “Edit Bindings”

3. In the dialog that opens setup your default binding like so:

image

4. Browse to http://helloworld/

Now if you have Windows Authentication turned on, on your site, you will find that IE will not auto log you into the site, nor will you be able to log in by providing the correct credentials. The reason for this is  that in Windows Server 2003 SP1 a new security functionality called “loopback check” was added, this blocks the authentication request and so for your site to work with the new-host name locally you need to disable the loopback check.

This is described in this post: http://support.microsoft.com/kb/926642, and is done via editing the registry (2 methods are provided). Here is the first method (which I like better than method 2 – which completely disables the loopback check).

Method 1: individually allow host-names

  1. Click Start, click Run, type regedit, and then click OK.
  2. Locate and then click the following registry subkey:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
  3. Right-click MSV1_0, point to New, and then click Multi-String Value.
  4. In the Name column, type BackConnectionHostNames, and then press ENTER.
  5. Right-click BackConnectionHostNames, and then click Modify.
  6. In the Value data box, type the CNAME or the DNS alias, that is used for the local shares on the computer, and then click OK.
    Note Type each host name on a separate line.
    Note If the BackConnectionHostNames registry entry exists as a REG_DWORD type, you have to delete the BackConnectionHostNames registry entry.
  7. Exit Registry Editor, and then restart the computer.
Method 2: disable loopback check
Copy the folllowing text into notepad, save the file with an extension of .reg and run it.

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
"DisableLoopbackCheck"=dword:00000001

Saturday, January 21, 2012

DPM–Restoring a protected SqlServer database to a different server

Reason: I needed to restore a SqlServer database from production to a dev server.

Unfortunately the help documentation for the DPM cmdlets are pretty much useless as they don’t tell you how a cmdlet should be used or what parameters (or combination of parameters are allowed). In addition, most online posts report that you cannot directly perform a restore of SqlServer database to a different server (and that you need to restore the files and then run scripts to reattach the database). I was lucky to happen upon Wilson Souza’s post and modified his source-code to do exactly what I needed it to do: restore a protected production database to a development server. Here is the script that I came up with.

Notes:

  • It has been tested against DPM 2010. (not sure if it will work against DPM 2007).
  • An example of how to call the function is provided at the bottom
  • As part of the restore process, the script will drop the database on the destination server if it already exists
  • The source database must be part of a protection group (duh! obvious)
  • The destination database server must have the protection agent installed on it and the agent should be running
  • the params required are pretty self explanatory – but look at the bottom of the script for an example
  • Need to install DPM management shell on the machine from where DPM scripts will be run (if its not the DPM server)

function RestoreDbFromDPM
#this script is based on Wilson Souza's work as described at
#
http://social.technet.microsoft.com/Forums/en-US/dpmsqlbackup/thread/e5e50339-5707-4e72-bb9a-56f6d60ba926

{
    Param([string] $dpmServerName, [string] $sqlProtectionGroupName,
    [string] $serverName, [string] $databaseName, [string] $restoreToServerName,
    [string] $restorePathMdf, [string] $restorePathLog, [bool] $doTheRestore = $false,
    [string] $dateOfRestoreToUse = $null,
    [string] $dpmServerUsedToProtectClient = $null)

    $startDate = $null;
    $endDate = $null;
    if ($dateOfRestoreToUse -ne $null -and $dateOfRestoreToUse.Length -gt 0) #if a date was provided then setup a date-range
    {
        $startDate = Get-Date $dateOfRestoreToUse;
        $endDate = $startDate.AddDays(1).AddSeconds(-1); #one day
    }

    if ( (Get-PSSnapin -Name 'Microsoft.DataProtectionManager.PowerShell' -ErrorAction SilentlyContinue) -eq $null )
    {
        Add-PSSnapin -Name 'Microsoft.DataProtectionManager.PowerShell'
        Write-Host "Completed loading DPM powershell snapin"
    }
    else
    {
        Write-Host "DPM powershell snapin is already loaded"
    }
   
    RepointDpmAgent $dpmServerName $restoreToServerName
       
    Connect-DPMServer $dpmServerName; #lets connect

    $sqlProtectionGroup=Get-ProtectionGroup $dpmServerName | where-object { $_.FriendlyName -eq $sqlProtectionGroupName}
    if($sqlProtectionGroup -eq $null)
    {
        Write-Host "The protection group $sqlProtectionGroupName was not found on the server $dpmServerName";
        return;
    }
   
    #find the data-source for the database-name on the server requested
    $sqlDataSource = Get-DataSource -ProtectionGroup $sqlProtectionGroup | where-object { $_.name -eq $databaseName -and $_.Instance -eq $serverName}
    if ($sqlDataSource -ne $null)
    {
        $sqlDs = [Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.SQL.SQLDataSource]$sqlDataSource;
        #find a recoverypoint that is not incremental - not sure why incremenatl restores bomb!
        $recoveryPoints = Get-Recoverypoint -DataSource $sqlDs | where-object { $_.HasFastRecoveryMarker -eq "Fast" -and $_.IsRecoverable}
        if ($recoveryPoints -eq $null)
        {
            Write-Host "A recovery point for the database: $databaseName on server: $serverName was not found in the protection group $sqlProtectionGroup" -ForegroundColor Red
            return
        }
        if ($startDate -ne $null) #range has been provided - lets find a recovery point within the date range
        {
            $recoveryPoints = $recoveryPoints | `
                        Where-Object {`
                            $_.RepresentedPointInTime -ge $startDate -and `
                            $_.RepresentedPointInTime -lt $endDate`
                        };
           
            if ($recoveryPoints -ne $null)
            {
                Write-Host "A recovery point for the specified date: $startDate was found. Recovery Point date: $($recoveryPoints.RepresentedPointInTime)"
            }
            else
            {
                Write-Host "A recovery point for the database: $databaseName on server: $serverName was not found "`
                                "in the protection group $sqlProtectionGroupName "`
                                "within the daterange: $startDate to $endDate. "`
                                "Restore cannot proceed!" `
                                -ForegroundColor Red
                return
            }
        }
       
        if ($recoveryPoints.Count) #check if we got back an array
        {
            $recoveryPointToUse = $recoveryPoints[-1]; #array - select the latest
        }
        else
        {
            $recoveryPointToUse = $recoveryPoints;
        }
       
        if ($recoveryPointToUse -eq $null)#what! fail!
        {
            Write-Host "A recovery point for the database: $databaseName on server: $serverName was not found in the protection group $sqlProtectionGroup" -ForegroundColor Red
            return
        }
               
        $length = $recoveryPointToUse.PhysicalPath.Length; #Length = num files (eg: mdf and log = 2)
       
        #lets setup the alt.database details.
        $alternateDatabaseDetails = New-Object -TypeName Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.SQL.AlternateDatabaseDetailsType;
        $LocationMapping = New-Object Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.SQL.FileLocationMapping[] $length;
         $alternateDatabaseDetails.LocationMapping = $LocationMapping
       
        $i = 0;
        $a = $null;
        while($i -lt $length)
        {       
            $alternateDatabaseDetails.LocationMapping[$i] = New-Object -TypeName Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.SQL.FileLocationMapping;
            $alternateDatabaseDetails.LocationMapping[$i].FileName = $recoveryPointToUse.FileSpecifications[$i].FileSpecification;
            $alternateDatabaseDetails.LocationMapping[$i].SourceLocation = [Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.OMCommon.PathHelper]::GetParentDirectory($recoveryPointToUse.PhysicalPath[$i]);
            if ($alternateDatabaseDetails.LocationMapping[$i].FileName.ToLower().EndsWith(".ldf"))
            {
                $alternateDatabaseDetails.LocationMapping[$i].DestinationLocation = $restorePathLog
                #= $alternateDatabaseDetails.LocationMapping[$i].SourceLocation;
            }
            else
            {
                $alternateDatabaseDetails.LocationMapping[$i].DestinationLocation = $restorePathMdf
            }       
            $i++;
        }
        $alternateDatabaseDetails.InstanceName = $restoreToServerName;
        $alternateDatabaseDetails.DatabaseName = $databaseName;
       
        $recoveryOption = New-RecoveryOption `
            -TargetServer $restoreToServerName `
            -RecoveryLocation OriginalServerWithDBRename `
            -SQL `
            -RecoveryType Recover `
            -AlternateDatabaseDetails $alternateDatabaseDetails;
           
        #drop the database if it already exists - else DPM fails on the restore
        DropDatabase $restoreToServerName $databaseName;
         $dbsize = ($recoveryPointToUse.Size / (1024*1024*1024)).ToString(".###");
        Write-Host "restoring database: $($alternateDatabaseDetails.DatabaseName)`n"`
                    " with backup from $($recoveryPointToUse.RepresentedPointInTime)`n"`
                    "  to Sql-Server: $($alternateDatabaseDetails.InstanceName)`n"`
                    "   DB size:  $dbsize GB .....`n"
                   
        if ($doTheRestore)
        {
            $restoreJob = Recover-RecoverableItem -RecoverableItem $recoveryPointToUse -RecoveryOption $recoveryOption;

            Write-Host "Restore Status: $($restoreJob.Status)`n HasCompleted: $($restoreJob.HasCompleted)`n  Start: $($restoreJob.StartTime)"
            $waitTime = 2; #initial wait time
            while ($restoreJob -ne $null -and $restoreJob.HasCompleted -eq $false)
            {
                Write-Host "." -NoNewline;
                Start-Sleep -Seconds $waitTime;
                $waitTime = 20;
            }
           
            Write-Host ""
            if($restoreJob.Status -ne "Succeeded")
            {
                Write-Host "Restore Status: $($restoreJob.Status)`n Start: $($restoreJob.StartTime)`n  End: $($restoreJob.EndTime)" -ForeGroundColor Red
            }
            else
            {
                Write-Host "Restore Status: $($restoreJob.Status)`n Start: $($restoreJob.StartTime)`n  End: $($restoreJob.EndTime)" -ForeGroundColor DarkGreen
            }
           
            $td = (New-Timespan -Start $restoreJob.StartTime -end $restoreJob.EndTime)
            Write-Host "Elapsed time: Hours: $($td.Hours) Minutes:$($td.Minutes) Seconds:$($td.Seconds) MSecs:$($td.Milliseconds)"
        }
        else
        {
            Write-Host "DoTheRestore is set to false - restore is not being performed" -BackgroundColor Red
        }
    }
    else
    {
        Write-Host "Database $databaseName on $serverName was not found" -ForeGroundColor Red
    }
   
    Disconnect-DPMServer $dpmServerName
   
    if ($dpmServerUsedToProtectClient.Length -gt 0)#we have been provided the dpmserver for protection - so repoint
    {
        RepointDpmAgent $dpmServerUsedToProtectClient $restoreToServerName   
    }   
}


function DropDatabase([string] $restoreToServerName, [string] $databaseName)
{
    Write-Host "Checking if database $databaseName needs to be dropped"
    [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null
    $sqlServerSmo = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server ($restoreToServerName)

   
    if ($sqlServerSmo.databases[$databaseName] -ne $null)
    {
        Write-Host "Dropping database $databaseName on server $restoreToServerName"
        $sqlServerSmo.KillAllProcesses($databaseName)
        $sqlServerSmo.databases[$databaseName].drop()
        Write-Host "Database $databaseName on server $restoreToServerName has been dropped"
    }
    else
    {
        Write-Host "Database $databaseName does not exist on server $restoreToServerName"
    }
   
    Write-Host ""
}

function RepointDpmAgent([string] $dpmServerName, [string] $dpmClient)
{
    Write-Host "Setting the DPMServer for $dpmClient to $dpmServerName"
    Invoke-Command -ComputerName $dpmClient `
                  -ArgumentList $dpmServerName `
                  -ScriptBlock {param($serverName) $cmd = "C:\Program Files\Microsoft Data Protection Manager\DPM\bin\SetDpmServer.exe"; & $cmd -dpmServerName $serverName;}
}

####example of how to call the above functions to perform a restore
cls;

#dateOfRestoreToUse is optional. If not provided – it will use the latest available restorepoint
#doTheRestore is optional. if not true – the script will be run in demo mode and will not perform the restore

RestoreDbFromDPM `
    -dpmServerName "dpmServerName" `
    -sqlProtectionGroupName "ProtectionGroupName" `
    -serverName "DatabaseServerOnWhichTheDatabaseResides" `
    -databaseName "NameOfTheDatabaseToBeRecovered" `
    -restoreToServerName "DatabaseServerToWhichTheRestoreShouldBePerformed" `
    -restorePathMdf "D:\MSSQLData\" `
    -restorePathLog "L:\MSSQLLog\" `
    -dateOfRestoreToUse "2012/01/19" ` 
    -dpmServerUsedToProtectClient "dpmServerThat ServerName should point to for day to day protection" ` #(not required)
    -doTheRestore $true;

More info:

Another restore sample: http://social.msdn.microsoft.com/Forums/en-SG/sqldisasterrecovery/thread/6c011fcd-765d-4f02-adb0-1975bd5c2f94
Yet another restore sample: http://the-network-guy.blogspot.com/2009/01/automating-dpm-recovery.html

Friday, January 20, 2012

Visual Studio Achievements–Gamification of software development

Check out the new VS add-on called “Visual Studio Achievements”. Its an add-on that tracks what you are coding and provides you awards as you perform certain actions (very much like the achievements that you earn when you play games like Call of Duty on the Xbox).

Learn more and download the add-on from: http://channel9.msdn.com/achievements/visualstudio

And here is a screen-shot of the 2 latest achievements that I earned!

Get your game on!

image

http://channel9.msdn.com/niners/theRajah/achievements/visualstudio

Wednesday, January 18, 2012

DPM PowerShell commands–create a help document

Here is a simple command to list all the commands in DPM with detailed help documentation:

Get-Command -PSSnapin Microsoft.DataProtectionManager.Powershell | Get-Help -detailed > c:\dpmhelp.txt

Monday, January 16, 2012

Fuslogvw not working for Asp.Net applications

I have found that if I change settings to use a custom path pointed at the root folder of the C drive, Fuslogvw begins to work for Asp.Net applications too. Without that, no logs are generated.

Windows Firewall–Determining why you arent able to connect to a machine

Recently I was having trouble connecting to a Data Protection Manager server from a remote machine using power-shell cmdlets. I knew I had everything properly configured with DPM, and so I knew it was probably Windows Firewall that was blocking access to the computer.

What I needed was a log of what was being blocked and here is how I was able to turn on logging on the machine (a Windows 2008 server).

Under “Administrative Tools” select “Windows Firewall with Advanced Security”

image

Click on the topmost node: “Windows Firewall with Advanced Security on Local Computer”

image

Select “Windows Firewall Properties”

image

In my case I needed logging turned on for my Domain profile, so on the Domain profile tab, I clicked on the Customize button in the logging section and turn on logging of dropped packets:

image image

The log file is by default created at: “%systemroot%\system32\LogFiles\Firewall\pfirewall.log”

If you look at the log file you will find out the protocol that the remote machine is using to connect and the port. Depending on your specific situation you will have to add an incoming rule (or outgoing rule) to allow the appropriate connections through.

Friday, January 13, 2012

IIS 7x: Listing site settings

Here is a simple command to list all your IIS sites and their different settings (bindings, authentication, etc)

appcmd list sites /text:*

The information that gets captured includes (sample):

SITE
  SITE.NAME:"xxxx"
  SITE.ID:"yy"
  bindings:"http/*:80:xxxxx"
  state:"Started"
  [site]
    name:"xxxx"
    id:"yy"
    serverAutoStart:"true"
   [bindings]
      [binding]
        protocol:"http"
        bindingInformation:"*:80:xxxxx"
    [limits]
      maxBandwidth:"4294967295"
      maxConnections:"4294967295"
      connectionTimeout:"00:02:00"
   [logFile]
      logExtFileFlags:"Date, Time, ClientIP, UserName, ServerIP, Method, UriStem, UriQuery, HttpStatus, Win32Status, TimeTaken, ServerPort, UserAgent, HttpSubStatus"
      customLogPluginClsid:""
      logFormat:"W3C"
      directory:"C:\inetpub\logs\LogFiles"
      period:"Daily"
      truncateSize:"20971520"
      localTimeRollover:"false"
      enabled:"true"
    [traceFailedRequestsLogging]
      enabled:"false"
      directory:"C:\inetpub\logs\FailedReqLogFiles"
      maxLogFiles:"50"
      maxLogFileSizeKB:"512"
      customActionsEnabled:"false"
   [applicationDefaults]
      path:""
      applicationPool:""
      enabledProtocols:"http"
      serviceAutoStartEnabled:"false"
      serviceAutoStartProvider:""
    [virtualDirectoryDefaults]
      path:""
      physicalPath:""
      userName:""
      password:""
      logonMethod:"ClearText"
      allowSubDirConfig:"true"
   [ftpServer]
      allowUTF8:"true"
      serverAutoStart:"true"
     [connections]
        unauthenticatedTimeout:"30"
        controlChannelTimeout:"120"
        dataChannelTimeout:"30"
        disableSocketPooling:"false"
        serverListenBacklog:"60"
        minBytesPerSecond:"240"
        maxConnections:"4294967295"
        resetOnMaxConnections:"false"
        maxBandwidth:"4294967295"
     [security]
        [dataChannelSecurity]
          matchClientAddressForPort:"true"
          matchClientAddressForPasv:"true"
        [commandFiltering]
          maxCommandLine:"4096"
          allowUnlisted:"true"
        [ssl]
          serverCertHash:""
          serverCertStoreName:"MY"
          ssl128:"false"
          controlChannelPolicy:"SslRequire"
          dataChannelPolicy:"SslRequire"
        [sslClientCertificates]
          clientCertificatePolicy:"CertIgnore"
          useActiveDirectoryMapping:"false"
          validationFlags:""
          revocationFreshnessTime:"00:00:00"
          revocationUrlRetrievalTimeout:"00:01:00"
       [authentication]
          [anonymousAuthentication]
            enabled:"false"
            userName:"IUSR"
            password:""
            defaultLogonDomain:"NT AUTHORITY"
            logonMethod:"ClearText"
          [basicAuthentication]
            enabled:"false"
            defaultLogonDomain:""
            logonMethod:"ClearText"
         [clientCertAuthentication]
            enabled:"false"
         [customAuthentication]
            [providers]
      [customFeatures]
        [providers]
      [messages]
        exitMessage:""
        greetingMessage:""
        bannerMessage:""
        maxClientsMessage:""
        suppressDefaultBanner:"false"
        allowLocalDetailedErrors:"true"
        expandVariables:"false"
      [fileHandling]
        keepPartialUploads:"false"
        allowReplaceOnRename:"false"
        allowReadUploadsInProgress:"false"
      [firewallSupport]
        externalIp4Address:""
      [userIsolation]
        mode:"None"
        [activeDirectory]
          adUserName:""
          adPassword:""
          adCacheRefresh:"00:01:00"
      [directoryBrowse]
        showFlags:""
        virtualDirectoryTimeout:"5"
      [logFile]
        logExtFileFlags:"Date, Time, ClientIP, UserName, ServerIP, Method, UriStem, FtpStatus, Win32Status, ServerPort, FtpSubStatus, Session, FullPath"
        directory:"C:\inetpub\logs\LogFiles"
        period:"Daily"
        truncateSize:"20971520"
        localTimeRollover:"false"
        enabled:"true"
        selectiveLogging:"LogSuccessful, LogError, LogInfrastructure"
   [application]
      path:"/"
      applicationPool:"xxxx"
      enabledProtocols:"http"
      serviceAutoStartEnabled:"false"
      serviceAutoStartProvider:""
     [virtualDirectoryDefaults]
        path:""
        physicalPath:""
        userName:""
        password:""
        logonMethod:"ClearText"
        allowSubDirConfig:"true"
     [virtualDirectory]
        path:"/"
        physicalPath:"e:\inetpub\wwwroot\xxxxx"
        userName:""
        password:""
        logonMethod:"ClearText"
        allowSubDirConfig:"true"

 

More info:

http://learn.iis.net/page.aspx/114/getting-started-with-appcmdexe

Wednesday, January 11, 2012

Running DPM Cmdlets from workstations

The DPM-Cmdlets can be run from computers other than the DPM server. But before you can do that you need to install the DPM Management Shell and for this you need the 2gb DPM installer.

image

 

Notes:

DPM and Windows Firewall: I needed to open TCP port 57736 and UDP port 1434 for remote access to work. (more info below)

http://blogs.technet.com/b/dpm/archive/2007/06/20/dpm-cli-hello-world.aspx

The TCP port that I had to open corresponded to the TCP/IP port used by SQL server. You can figure it out using the SqlServer configuration tool by looking at the properties for the protocols:

image

Thursday, January 05, 2012

MS-FTP: 530 User cannot log in, home directory inaccessible.

When using Microsoft’s FTP system, if you use the “User name directory” isolation mode:

image

you may get the “530 User cannot log in, home directory inaccessible” error.

Some things to check:

1. You should have a LocalUser folder under the FtpRoot folder.

2. You should have a folder with the name of the account that is being used to connect to the FTP server (eg: account name = testAccount, then folder structure should be Inetpub\Ftproot\LocalUser\testAccount).

3. The account being used to connect to the FTP server should have access to the folder created in step 2. (The account should be a local user account on that box).