Creating OpenVPN Server and Setting up OpenVPN Clients

I recently setup a remote office that houses my huge Virtual Host machine and wanted private/encrypted access to that network from where ever I am.  Thus I turned to OpenVPN as a solution after a little bit of research (see this BestVPN Article).  This article covers the basics of setting up an OpenVPN server on a Ubuntu server sitting behind a NAT firewall. 

Let’s start on the Ubuntu Server…
Enter root first…

$ sudo su

Setup OpenVPN Server

Starting with a Ubuntu computer you’d like to make the OpenVPN Server… Install OpenVPN and Easy-RSA

$ apt-get install openvpn easy-rsa -y

Certificates

The first thing to know about OpenVPN is we’ll be setting things up to use certificates.  It is the most secure method and requires you to manually distribute the client certificates and configuration files.  The method you choose determines the security.  Most secure is to hand deliver the certs on an encrypted thumb drive.

Certificate Authority

To setup your own Certificate Authority (CA) and generating certificates and keys for an OpenVPN server and multiple clients first copy the easy-rsa directory to /etc/openvpn.

$ mkdir /etc/openvpn/easy-rsa
$ cp -rf /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/
$ vi /etc/openvpn/easy-rsa/vars

And, change the values that matches with your country, state, city, mail id etc.

export KEY_COUNTRY=”CountryCode”
export KEY_PROVINCE=”MyStateOrProvince”
export KEY_CITY=”MyCity”
export KEY_ORG=”Organization Name”
export KEY_EMAIL=”vpn@example.com”
export KEY_CN=MyVPN
export KEY_NAME=MyVPN
export KEY_OU=MyVPN

Enter the following to generate the master Certificate Authority (CA) certificate and key:

$ cd /etc/openvpn/easy-rsa/
$ cp openssl-1.0.0.cnf openssl.cnf
$ source vars
$ ./clean-all

Run the following command to generate CA certificate and CA key:

$ ./build-ca

Server Certificates

Next, we will generate a certificate and private key for the server:

$ ./build-key-server server

Client Certificates

Each client will need a certificate to authenticate itself to the server. To create the certificate, enter the following in a terminal while being user root:

$ ./build-key client

Generate Diffie Hellman Parameter

This is a unique key used for our VPN Server, Enter the following command to generate DH parameter.

$ ./build-dh
Go to the directory /etc/openvpn/easy-rsa/keys/ and enter the following command to transfer the above files to /etc/openvpn/ directory.

$ cd /etc/openvpn/easy-rsa/keys/
$ cp dh1024.pem ca.crt server.crt server.key /etc/openvpn/

Client Configuration File

We need to copy and edit the client configuration file.
$ cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /etc/openvpn/client.ovpn

Edit file client.ovpn,
$ vi /home/client.ovpn

Set the VPN server host name/IP address:

remote [public ip or hostname of your vpn server] 1194

Distributing Client Certificates

You must copy all client certificates and keys to the remote VPN clients in order to authenticate to the VPN server. In our case, we have generated certificates and keys to only one client, so we have to copy the following files to the VPN client.

ca.crt
client.crt
client.key
client.ovpn

You have to copy the above files to your VPN clients securely. Copy the keys with caution. If anyone gets ahold of your keys, they can easily intrude and get full access to your virtual private network.

Configuring VPN Server

Copy the file server.conf.gz file to /etc/openvpn/ directory.
$ cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/

Extract the file using the following command:
$ gzip -d /etc/openvpn/server.conf.gz

Edit file server.conf,
$ vi /etc/openvpn/server.conf

Find and uncomment the following lines to route client systems traffic through OpenVPN server.

[…]
push “redirect-gateway def1 bypass-dhcp”
[…]

Also, Uncomment and change the DNS servers to reflect your own DNS values. Here I am using Google public DNS servers.

[…]
push “dhcp-option DNS 208.67.222.222”
push “dhcp-option DNS 208.67.220.220”
[…]

Uncomment the following lines:

[…]
user nobody
group nogroup
[…]

Save and close the file.

IP forwarding and routing Configuration

Edit sysctl.conf file,
$ vi /etc/sysctl.conf

Find the following line and set value “1” to enable IP forwarding.

# Controls IP packet forwarding
net.ipv4.ip_forward = 1

Run the following command to apply the sysctl changes.
$ sysctl -p

Enter the following command to enable IP forwarding:
$ echo 1 > /proc/sys/net/ipv4/ip_forward

Start OpenVPN Server

Finally, start openvpn service and make it to start automatically on every reboot using the following commands:
$ service openvpn start

Verify if VPN interface(tun0) is created using ifconfig command:
$ ifconfig

Network Router Configuration

We need to do two things on your router and how you do them greatly depends on your router.  I’m assuming you have a hardware router hooked up to your DSL, Cable or other type of internet connection and you’re setting up a Ubuntu VPN server on the internal network and want to access other computers on that internal network once your remote clients have authenticated into the VPN tunnel.

1. Your VPN server should have an internal static IP address… We need to tell your router to route all 10.8.0.0 traffic to your VPN server so when your VPN clients connect they can communicate with your internal network.

2. Open external port 1194 tcp and udp and point it at your VPN server’s internal static IP address.

Clients

Now we have the files needed to put on your clients, your server is all setup, and your router is configured correctly… it’s time to look at setting up clients.  I created a client certificate for each of my three workstations… each running a different OS:  Mac OS X, Ubuntu 14.04, and Windows 7.  I want to validate and connect into my VPN remote network from all three systems… but configuring their client is slightly different on each.  Below I go into details on setting each one up.

Ubuntu Client

I’ll assume you are using this system as a Ubuntu workstation/laptop and have a graphical interface… thus want to use Network Manager to connect in.  First we’ll need to install two items:
$ sudo apt-get install openvpn network-manager-openvpn

Navigate…
System Settings->Network->+ (hit pluse in bottom left)
Choose VPN interface and hit Create
Select OpenVPN from the type list and hit Create
Specify the Gateway (public ip or domain name of your vpn server)
Point the User Certificate at the client.crt file
Point the CA Certificate at the ca.crt file
Point the Private Key at the client.key file.

Save that and you’re done.  You should now connect into your VPN and run a few ping and other tests. 

Mac Client

My primary laptop is a Mac, so let’s go there next.  Here you’ll need to install a VPN client application called TunnelBlick.  https://www.tunnelblick.net/

Once you’ve installed the application, you need to dbl-click on your client.ovpn file.  The ovpn file type has been associated with Tunnelblick when it was installed and will open up the file allowing you to add that connection ot your available list.  Once done, simply connect into the VPN and run your tests.

Windows Client

Visit http://sourceforge.net/projects/securepoint and download the windows OpenVPN client.
Launch the Securepoint SSL VPN client, dbl click the tray icon when it appears, and select New. 
Next
Enter Name of your VPN Connection and hit Next
Enter the Public IP or Domain Name of your VPN server, the port you configured (default is 1194) and I prefer TCP connections due to reliability reasons… then hit Next
Point the User Certificate at the client.crt file
Point the CA Certificate at the ca.crt file
Point the Private Key at the client.key file.
Hit Next
Under Advanced Settings
– check the “Comp-LZO” checkbox
– uncheck the “Auth user/pass” checkbox
– leave all others at their Defaults
hit Next
Lastly hit Finish

 

All done… let me know if you have any questions below.

Installing Tanium v6.1

Installing Tanium is actually really easy and I’m going to make it even easier by walking you through the express installation of the product.

In the following article I’ll provide you with the various screen shots for the express installation of Tanium v6.1.314.2342 and I’ll call out screens that may need additional explainations. Let’s get started!
I assume you’ve already acquired the installation executable from your Technical Account Manager or Sales person…
tanium01
Double click it to launch the installer. If you’re installing onto a Windows 2008r2 server, like I am here, you may need to click yes to the UAC request dialog:
tanium02
tanium03
tanium04
This virtual computer I’m installing our server onto, does not have an MSSQL server installed, so we’ll choose to install the MSSQL Express Edition.
tanium05
tanium06
tanium08
We’ll have to agree to Microsoft’s EULA…
tanium09
I’ve chosen to download and install updates to MSSQL here.
tanium10
I’m also using the default options…
tanium13
Leave the named instance settings as is.
tanium14
As well as the service configuration settings…
tanium15
We only support Windows authentication so choosing between only Windows Auth or both is up to you.
tanium16
tanium19
Now… back to the Tanium installation… choose the Express Install.
tanium20
Provide your windows credentials for the initial user. If your server is linked to a domain, it can be a domain login (does not need to be an admin or anything). If your server is NOT on a domain, simply provide one of the local accounts username/passwords to continue.
tanium22
All done!
tanium23

The express installation of our product creates a self signed certificate for the console, so you’ll need to agree to continue.
tanium24
Log in with the username/password you specified earler…
tanium25
When you have successfully logged in, an initial content load will occur. This means your server is downloading a “starter” pack of content (sensors, packages, dashboards, etc) which will get you started with the product immediately. This process does take several minutes, so please be patient.
tanium26
Once the content load is complete, you’ll get to play around with the product!
tanium27

Currently you do not have any endpoints to work with. I’ll release another article very soon which explains a few ways of getting agent installed onto your computers.

Tanium How-to SigCheck

If you’ve read my blog over the past few days, you already know that I now work for Tanium. Tanium has a self-named product that is used at many of the top fortune 50 businesses to help them manage and get instant answers on the most common security and systems management questions they face in mere seconds!
I thought I’d start sharing some how-to articles related to the product. I’m still learning myself so I will share as I learn. For this first article, I thought I’d start slightly after the beginning. I’m sure anyone reading this has gotten the full intro and some basic training from their assigned Technical Account Managers. And if you have any questions, the TAMs are always listening and willing to help!
Now, for this first article I want to tackle a problem that comes up all too often when distributing software that might be used by the Tanium client itself. In the example below, I will teach you how to distribute the Sysinternals tool called SigCheck. To do this you will need to produce a few pieces of content:
1. “Has SigCheck” is a sensor that checks your endpoints and determines if you have the utility already installed or not. This sensor allows you to ask the following question: Get Has SigCheck from all machines. This question needs to return a Yes or No depending on the presence of the sigcheck.exe utility.
2. “Distribute SigCheck” is a package that pulls the SigCheck.zip from the Sysinternals website, it also pulls an unzip utility from our Tanium content site and since we’re building this on the Community website, pulls the distributesigcheck.vbs from the Tanium Community website.

The logical process once our content is built is as follows:
1. Ask the question “Get Has SigCheck from all machines”
2. Select the No answer and deploy an action, choose the “Distribute SigCheck” package and you’re execute.

“Has SigCheck” Sensor
Of course this all starts with the basic “has” sensor. To build this we’ll be writing an extremely simple sensor that will check the existence of our file within the Tools directory of our Tanium Client. This vbscript will look a little something like this:

‘========================================
’ Has SigCheck Utility
’========================================

’ This sensor will report on the existence of the sigcheck file.

Option Explicit
Dim objFSO
Dim strTaniumToolsDir, strFile
Set objFSO = CreateObject(“Scripting.FileSystemObject”)

strFile = “sigcheck.exe”
strTaniumToolsDir = GetTaniumDir(“Tools\Sigcheck”)

If objFSO.FileExists(strTaniumToolsDir&strFile) Then
WScript.Echo “Yes”
Else
WScript.Echo “No”
End If

Function GetTaniumDir(strSubDir)
‘GetTaniumDir with GeneratePath, works in x64 or x32
‘looks for a valid Path value

Dim objShell
Dim keyNativePath, keyWoWPath, strPath

Set objShell = CreateObject(“WScript.Shell”)

keyNativePath = “HKLM\Software\Tanium\Tanium Client”
keyWoWPath = “HKLM\Software\Wow6432Node\Tanium\Tanium Client”

’ first check the Software key (valid for 32-bit machines, or 64-bit machines in 32-bit mode)
On Error Resume Next
strPath = objShell.RegRead(keyNativePath&“\Path”)
On Error Goto 0

If strPath = "“ Then
’ Could not find 32-bit mode path, checking Wow6432Node
On Error Resume Next
strPath = objShell.RegRead(keyWoWPath&”\Path“)
On Error Goto 0
End If

If Not strPath = ”“ Then
If strSubDir <> ”“ Then
strSubDir = ”" & strSubDir
End If

Dim fso
Set fso = WScript.CreateObject(“Scripting.Filesystemobject”)
If fso.FolderExists(strPath) Then
If Not fso.FolderExists(strPath & strSubDir) Then
’’Need to loop through strSubDir and create all sub directories
GeneratePath strPath & strSubDir, fso
End If
GetTaniumDir = strPath & strSubDir & “"
Else
’ Specified Path doesn’t exist on the filesystem
WScript.Echo ”Error: “ & strPath & ” does not exist on the filesystem“
GetTaniumDir = False
End If
Else
WScript.Echo ”Error: Cannot find Tanium Client path in Registry"
GetTaniumDir = False
End If
End Function ’GetTaniumDir

Function GeneratePath(pFolderPath, fso)
GeneratePath = False
If Not fso.FolderExists(pFolderPath) Then
     If GeneratePath(fso.GetParentFolderName(pFolderPath), fso) Then
         GeneratePath = True
         Call fso.CreateFolder(pFolderPath)
     End If
 Else
     GeneratePath = True
 End If
End Function ’GeneratePath

Notice that I have copied code from existing sensors, namely the GetTaniumDir function (also requires GeneratePath and RegKeyExists) which reads the registry to determine where our client is installed. Providing an argument will append that to the end of the Tanium directory that was read. The new community will soon have the feature to add reusable code blocks like this with a simple checkbox. But until then, simply copy-paste the functions needed from other code.

“Distribute SigCheck” Package
The distribution package has multiple components that are a bit complicated when combined together. I will boil down each component and help you build this package. The Tanium Client will automatically download all files related to the package for us… they’ll all be sitting in the working directory of the command line we specify. Typically that is Tanium Client\Downloads\Action_XXXX. Knowing that, let’s look at the overall logic we’ll be using:
1. Unzip the SigCheck.zip file
2. Get the Tanium client directory using the same reusable code we added to the sensor.
3. Copy the SigCheck.exe into the Tools directory under the Tanium Client directory.
4. Agree to the Sysinternals EULA by indicating agreement within the Registry. (this is required or the SigCheck utility will hang every time waiting for user input which will never come since you’re running as SYSTEM on the endpoint).

Distributing SigCheck

Steps 1, 2, and 3: Unzip SigCheck.zip into Tools Directory
To unzip our utility we acquired from Microsoft, we’ll need to use a command line unzip utility. In the official content, we often use 7za.exe. It is an extremly small utility we will add to our package with the following details:

Filename: 7za.exe
URI: https://community.tanium.com/files/7za.exe
SHA–256: c136b1467d669a725478a6110ebaaab3cb88a3d389dfa688e06173c066b76fcf
Check for Updates: Never

The following reusable code block will be used to unzip our utility zip file:

Sub Unzip(strZipFilePath, strTargetDir)
’ Takes full file path to zip file, path to target directory
’ will extract to target directory as a subdirectory
’ overwriting anything in the subdirectory and showing no UI.
 Dim objShell, objFSO, strCurrentDir, strZipUtil
 Dim strTempDir, strZipFileName, strCommand, intResult

 Set objShell = WScript.CreateObject("WScript.Shell")
 Set objFSO = CreateObject("Scripting.FileSystemObject")

 strCurrentDir = Replace(WScript.ScriptFullName, WScript.ScriptName, "")

 If Not objFSO.FileExists(strZipFilePath) Then
     WScript.Echo "Cannot continue - " & strZipFilePath & " does not exist"
     Exit Sub
 End If

 strZipUtil = strCurrentDir & "7za.exe"

 If Not objFSO.FileExists(strZipUtil) Then 
     WScript.Echo "Cannot continue - " & strZipUtil & " does not exist"
     Exit Sub
 End If 

 If Not objFSO.FolderExists(strTargetDir) Then
     objFSO.CreateFolder(strTargetDir)
 End If

 strZipFileName = objFSO.GetFile(strZipFilePath).Name
 ' remove .zip from end"
 If InStr(LCase(strZipFileName),".zip") = Len(strZipFileName) - 3 Then ' ends in zip
     strZipFileName = Left(strZipFileName,Len(strZipFileName) - 4)
 End If
 strTempDir = strCurrentDir & strZipFileName
 WScript.Echo "Unzipping to " & strTempDir
 If Not objFSO.FolderExists(strTempDir) Then
     objFSO.CreateFolder strTempDir
 End If

 strCommand = Chr(34) & strZipUtil & Chr(34) & " x -y -o" & Chr(34) & strTempDir & Chr(34) & " " & Chr(34) & strZipFilePath & Chr(34)

 WScript.Echo "running unzip:"
 WScript.Echo "   command: " & strCommand

 objShell.Run strCommand, 0, True

 If objFSO.FolderExists(strTempDir) Then
     WScript.Echo "Copying " & strTempDir & " to " & strTargetDir
     On Error Resume Next
     intResult = objFSO.CopyFolder(strTempDir,strTargetDir,True) ' overwrite
     On Error Goto 0
     If intResult = 0 Then
         WScript.Echo "Success"
     Else
         WScript.Echo "Failure - result is " & intResult
     End If
 End If
End Sub ’Unzip

This function allows us to unzip with a single command: Unzip Source-Zip-File Destination-Folder
We’ll accomplish steps 1–3 in one fail swoop after setting up a few variables for use. We need the full path of our zip file as well as the destination folder to extract into. To get our current working directory where the zip file was downloaded for us, we can use the filesystem object as follows:

Set objShell = CreateObject(“WScript.shell”)
strCurrentDir = objShell.CurrentDirectory
To get the destination folder, we’ll reuse the technique we learned from the sensor above to get the tanium client directory:
strTaniumDir = GetTaniumDir(“Tools”)
Now accomplishing steps 1 through 3 is as easy as:
Unzip strCurrentDir&“\SigCheck.zip”, strTaniumDir

Step 4: Agree to Sysinternals EULA
Before we can execute the SigCheck utility, Sysinternals requires you to agree to their EULA. When you execute it for the first time a popup box appears with the EULA with an Agree or Cancel button. After some research I learned the EULA agreement flag is stored in the users profile inside of the registry. (HKEY_CURRENT_USER\Software\Sysinternals\SigCheck)
Before the Tanium Client can use this utility, the SYSTEM user must agree to the EULA. This presents a problem since SYSTEM doesn’t have a UI nor are we sitting at the thousands of machines we want to run the utility on. Thus we will need to indicate agreement by adding the “EulaAccepted” registry value. We’ll do that with the following code:

Dim WshShell
Set WshShell = WScript.CreateObject(“WScript.Shell”)
WshShell.RegWrite “HKEY_CURRENT_USER\Software\Sysinternals\SigCheck\EulaAccepted”, “1”, “REG_DWORD”
set WshShell = Nothing

Downloads
You can download the “Has SigCheck” sensor from the Tanium Community website at: https://community.tanium.com/repo/sensor/788
I’m still building the packages feature of our Community so I’ll follow up later with the package download link.

Bonus… Distribute SigCheck Automatically
All done! To review, we built a sensor to check the existance of our SigCheck utility and built a package to distribute it to our computers. The only problem now is we may want to have distribution occur anytime an endpoint comes online and doesn’t have the utliity. To accomplish this we’ll need to ask our new sensor question and deploy our new package with the reissue option specified. The following is a screen shot of what this looks like:

Reissue SigCheck

XML Deserialization

So, you have an XML document, your programming in Visual Studio 11 for your new Windows 8 Metro app, and you need to access the data within?  I’m here to help…

DE serializing your XML document is very simple.  First you’ll need to define a CLASS object the way your XML document is…

Here’s my example XML document:

<?xml version="1.0" encoding="UTF-8" ?>

<Congress>
  <Regions>
    <Region>
      <Title>Northeast</Title>

      <States>
        <State>
          <Title>Connecticut</Title>

          <Districts>
            <District>
              <Title>District 1</Title>
              <SubTitle>Larson, John B.</SubTitle>
            </District>
          </Districts>
        </State>
      </States>
    </Region>
  </Regions>
</Congress>

This is an example of an XML document I’m currently using in my contest application.  As you can see there can be multiple Regions, States or Districts.  Each organized in sub objects… I am showing you only one of each since it would get pretty long otherwise…

Now, we’ll need a few classes organized just like this XML document:

[XmlRoot("Congress")]
public class clsCongress
{
    [XmlArray("Regions")]
    [XmlArrayItem("Region", typeof(clsRegion))]
    public clsRegion[] Region { get; set; }
}

[XmlRoot("Regions")]
public class clsRegion
{
    [XmlElement("Title")]
    public string Title { get; set; }

    [XmlArray("States")]
    [XmlArrayItem("State", typeof(clsState))] 
    public clsState[] State { get; set; }
}

[XmlRoot("States")]
public class clsState
{
    [XmlElement("Title")]
    public string Title { get; set; }
        
    [XmlArray("Districts")]
    [XmlArrayItem("District", typeof(clsDistrict))]
    public clsDistrict[] District { get; set; }
}

[XmlRoot("Districts")]
public class clsDistrict
{        
    [XmlElement("Title")]
    public string Title { get; set; }
        
    [XmlElement("SubTitle")]
    public string SubTitle { get; set; }
}


As you can see form my class objects, you’ll need to specify the XmlRoot for each class as well as each XmlElement so everything maps correctly.  In my example, the elements match, but they don’t have to so long as they’re mapped with the XmlElement tag.

Now, I know you can find this code anywhere on the net… but what they don’t go into detail explaining is the array variables I have shown here. 

In my example, I have Congress which is made up of multiple Regions, which is made up of multiple States, and Districts.  In my example here, I demonstrate how to get multiple sub-objects pulled in easily and quickly.

Here is the code I use to load up the XML text, oh and I’m downloading this content using the new fancy async features from VS11 and Windows 8:

internal async Task PullRegionsAsync(Uri baseUri)
{
    string baseUrl = "https://danielheth.com/myexample.xml";

    //download the data xml
    //http://msdn.microsoft.com/en-us/library/windows/apps/system.net.http.httpclienthandler.maxrequestcontentbuffersize(v=VS.110).aspx
    //says there is a 65k limit on the size of what this function will download...
    var client = new HttpClient();
    var response = await client.GetAsync(baseUrl + "Data.xml");
            
    //------------------------------------------------
    //convert xml into an easily digestable object
    clsCongress congress = null;
    XmlSerializer des = new XmlSerializer(typeof(clsCongress));
    congress = (clsCongress)des.Deserialize(response.Content.ContentReadStream);
    //------------------------------------------------

    foreach (clsRegion r in congress.Region)
    {
        string RegionTitle = r.Title;

        foreach (clsState s in r.State)
        {
            string StateTitle = s.Title;

            foreach (clsDistrict d in s.District)
            {
                string DistrictTitle = d.Title;
            }
        }
    }
}

There you have it… deserializing your XML document into an easily digestible object within C#.

If you have any questions or comments please leave them below…

Windows 8 Metro Application–Bing Maps

I’ve entered myself into a new Windows 8 application contest.  I’ve come up with a wonderful idea which includes utilizing Bing Maps.  After an awful lot of research I’ve come up with something that works… Perfectly!!!

Since this is a Windows 8 application, I’m writing this in Visual Studio 11 express which utilizes an awesome multi-threading feature called async/await.  So I’ll be taking advantage of that here.

First thing I needed to do was acquire my Bing Map Developers key… Acquire yours free from:  https://www.bingmapsportal.com

Let’s start coding!!!

I followed the following MSDN article to setup my app for access to the Bing SOAP API’s.  http://msdn.microsoft.com/en-us/library/cc966738.aspx

Then added the following to the top of my code:

using HouseofRepresentatives.GeocodeService;
using HouseofRepresentatives.SearchService;
using HouseofRepresentatives.ImageryService;
using HouseofRepresentatives.RouteService;


private ImageSource _map = null;
public String Latitude = "";
public String Longitude = "";


public ImageSource Map
{
    get
    {
        if (this._map == null) UpdateMap();
        return this._map;
    }

    set
    {
        if (this._map != value)
        {
            this._map = value;
            this.OnPropertyChanged("Map");
        }
    }
}

I had two situations for my locations… in one case I knew the exact Lat/Lon, and in others I only knew an address… in my case a state name.  First I needed to turn that address into a Lat/Lon for passing onto the get map function.

private async Task<string> getLocationPoint(string address)
{
    if (address != null && address != "")
    {
        GeocodeRequest request = new GeocodeRequest();
        request.ExecutionOptions = new HouseofRepresentatives.GeocodeService.ExecutionOptions();
        request.ExecutionOptions.SuppressFaults = true;
        GeocodeServiceClient geocodeClient = 
            new GeocodeServiceClient(GeocodeServiceClient.EndpointConfiguration.BasicHttpBinding_IGeocodeService);
        HouseofRepresentatives.GeocodeService.Credentials t = 
            new HouseofRepresentatives.GeocodeService.Credentials();
        t.Token = "[[put your Bing Maps Key Here]]";

        request.Query = address;
        request.Credentials = t;

        GeocodeResponse response = await geocodeClient.GeocodeAsync(request);
        if (response.Results.Count() > 0)
        {
            return response.Results[0].Locations[0].Latitude.ToString() + 
                "," + response.Results[0].Locations[0].Longitude.ToString();
        }
    }
    return "";
}

Next I needed to actually get the Image from Bing.  Now let’s do that using the following function:

private async Task<string> GetImagery(string locationString)
{  //http://msdn.microsoft.com/en-us/library/dd221354.aspx
    string key = "[[insert your Bing Maps Key here]]";
    MapUriRequest mapUriRequest = new MapUriRequest();

    // Set credentials using a valid Bing Maps key
    mapUriRequest.Credentials = 
        new HouseofRepresentatives.ImageryService.Credentials();
    mapUriRequest.Credentials.ApplicationId = key;
                      

    // Set the location of the requested image
    mapUriRequest.Center = new HouseofRepresentatives.ImageryService.Location();
    string[] digits = locationString.Split(',');
            
    mapUriRequest.Center.Latitude = double.Parse(digits[0].Trim());
    mapUriRequest.Center.Longitude = double.Parse(digits[1].Trim());

    // Set the map style and zoom level
    MapUriOptions mapUriOptions = new MapUriOptions();
    mapUriOptions.Style = MapStyle.AerialWithLabels;
    mapUriOptions.ZoomLevel = 17;

    // Set the size of the requested image in pixels
    mapUriOptions.ImageSize = new HouseofRepresentatives.ImageryService.SizeOfint();
    mapUriOptions.ImageSize.Height = 240;
    mapUriOptions.ImageSize.Width = 480;

    mapUriRequest.Options = mapUriOptions;

    //Make the request and return the URI
    ImageryServiceClient imageryService = 
        new ImageryServiceClient(ImageryServiceClient.EndpointConfiguration.BasicHttpBinding_IImageryService);
            
    try
    {
        MapUriResponse mapUriResponse = await imageryService.GetMapUriAsync(mapUriRequest);

        if (mapUriResponse.Uri != null)
        {
            return mapUriResponse.Uri;
        }
        else { return ""; }
    }
    catch (Exception ex)
    {
        return "";
    }
}

Ok… now that I have my image Uri, it’s time to use it to load a picture:

public async Task<bool> UpdateMap(string address = "")
{
    if (address != "")
    {
        //then user is specifying an address instead of a specific long/lat.  
        //We need to get that info in order to proceed...
        string point = await getLocationPoint(address);
        if (point != "")
        {
            string[] p = point.Split(',');
            Latitude = p[0];
            Longitude = p[1];
        }
    }

    if (Longitude != "" && Latitude != "")
    {
        string uripath = await GetImagery(Longitude + "," + Latitude);
        if (uripath != "")
        {
            this.Map = new BitmapImage(new Uri(uripath));
            return true;
        }
        else
        {
            this.Map = new BitmapImage(new Uri(imageBaseUri, "Data/blank.png"));
            return false;
        }
    }
    else
    {
        this.Map = new BitmapImage(new Uri(imageBaseUri, "Data/blank.png"));
        return false;
    }
}

If you’ve stuck with me this far… you are a programmer… LOL.

In each of my functions I utilized the new async/await features.  This means when I call either of the two functions as below, it will load the image once the OS has downloaded and cached it.  The image will automatically appear when ready…

//calling the get-map function with an address
UpdateMap("Arkansas");

//or
UpdateMap("1 Microsoft Way, Redmond, Washington");

//or i can configure my lat/lon then update
Latitude = "39.450000762939453";
Longitude = "-98.907997131347656";
UpdateMap();

If you guys have any questions or comments, be sure to post them below!

How to Produce a Webcast… part 1

imageI’ve gotten back into the video game.  Years ago I had a web show called RootSync which I produced on a shoestring budget.  It worked well and had nearly 24 episodes (full season in TV terms).  Since then several things happened, I got a “real job”, divorced my Ex, closed my business, found a wonderful new wife, upgraded my job, upgraded my house, now I’m upgrading my broadcasting capabilities.Avatar

My latest venture into webcasting is a News Review called Week In Review.  I’ve worked hard on this show technically and have added so many new technically interesting features to make it happen.  Below is a short list of technical things that need to be learned and sorted out:

  1. Our Host and general theme of the show.
  2. Microsoft Cinema HD USB cameras for capturing high quality video.
  3. Wireless Label Microphones from RadioShack for capturing our hosts audio.
  4. Using a Xenyx1002B audio mixer to bring together both label microphones, Skype audio, and my computer’s audio then feeding them into VidBlaster for broadcasting.
  5. Utilizing VidBlaster for mixing multiple video sources together, broadcasting it over to uStream, and recording it for later post-production.
  6. uStream for the LIVE aspect of our show.  Broadcasting occurs every Friday at 7pm CST and uStream helps us broadcast LIVE.
  7. YouTube for the hosting of our episodes that have been post-produced.
  8. Using Windows Live Movie Maker for Post Production.
  9. iStockPhoto for royalty free videos, pictures and images.
  10. WordPress for hosting the main website which ties it all together.
  11. Publicizing our show by utilizing social networking like Twitter, Facebook, IMAutomator, etc…

I will be going into depth on each of the above technical aspects of the show and hopefully by the end of my Webcasting series you’ll have the knowledge needed to produce your own Webcast.

Our Host

A very important part of any new Webcast web show is your host.  The host must be interesting, insightful, and knowledgeable on the topics to be covered.  It helps if your host has the time to research and find the stories or topics that they would like to talk about in a way that would interest an audience.

David Smith3For my latest Webcast, my friend David will be hosting the show while I get to focus on the technical stuff.  David is a long time friend and has tons to talk about.  He has an actual PHD, he has lived and worked in L.A. during the riots, San Francisco, Las Vegas, Rome, and has ended up in Northwest Arkansas.  His extensive knowledge about a wide array of subjects makes him a very interesting listen and I believe the world would be better with his views shared.

David and I have been meeting every Friday for dinner ever since I can remember.  During our Friday dinners we’d talk about how our weeks have gone and what has happened in the world during the week as well as how those events would effect our lives here in Northwest Arkansas.  A few months ago we decided to record our discussions and share them with everyone and a new show was born.

Now that we have our host and the general theme of the show, it’s time to focus in on the technical aspects.  In part 2, I’ll discuss the video hardware used during our show.