Tag Archives: Powershell

Generating CM 2012 AppStore Deeplinks using Powershell

When working with the Application Catalog in CM 2012, there may be situations where you want to automate the approvals of install requests. While this task itself is worthy of discussion (will cover in a future post), this post will focus on a small part of that process, generating Deeplinks for applications.

Deeplinks are used for linking directly to an application detail page in the App Catalog. So, lets assume that you have your automated approvals solution in place, once you approve an application install, you want to send your end user a link to that application so they can install it. Great, so whats so hard about that?

The issue is that your deeplink looks something like this:

  • http://contoso.com/appstore/#/SoftwareCatalog/AppDetails/530063006F0070006500490064005F00380036004500370038003700310039002D0036003000330033002D0034004400390030002D0039003600330038002D003000410046003600410035003700420034004400420037002F004100700070006C00690063006100740069006F006E005F00640039003300610062003500620033002D0066003600650065002D0034003500610031002D0039003200650062002D00300064003300660032003100660033006100370031006100

Ahhhhh!!!…..Where do all these random numbers and letters at the end of the link come from?!? Well surely its stored somewhere in the CM database? Nope. Maybe there’s a CM Powershell cmdlet to get this value? Nope. Well how about the in the CM SDK? Nope, not there either.

It turns out that this long string is a Base 64 encoding of the ModelName of the application you want to link to. This means that all we need to do is find that charset that was used and we should be able to encode/decode deeplinks. Problem is, none of the default charsets were used. UTF-8, UTF-16, Unicode, ASCII…..None of these charsets returned desired results.

So what now? Well, we know the decoded and encoded value and we know that it is a Base 64 encoding. This means that every 4 characters in the encoded string correlates to 1 character on the decoded string. Using this knowledge we can generate the charset and throw it into hash tables that we can then use for encoding and decoding. The below script contains those hash tables and the functions that are used to encode and decode the strings.

#Dictionary values for encoding/decoding
$codes = @{}
$codes.Add('/', '2F00')
$codes.Add('_', '5F00')
$codes.Add('-', '2D00')
$codes.Add('0', '3000')
$codes.Add('1', '3100')
$codes.Add('2', '3200')
$codes.Add('3', '3300')
$codes.Add('4', '3400')
$codes.Add('5', '3500')
$codes.Add('6', '3600')
$codes.Add('7', '3700')
$codes.Add('8', '3800')
$codes.Add('9', '3900')
$codes.Add('a', '6100')
$codes.Add('b', '6200')
$codes.Add('c', '6300')
$codes.Add('d', '6400')
$codes.Add('e', '6500')
$codes.Add('f', '6600')
$codes.Add('o', '6F00')
$codes.Add('p', '7000')
$codes.Add('i', '6900')
$codes.Add('l', '6C00')
$codes.Add('n', '6E00')
$codes.Add('t', '7400')

$upperCodes = @{}
$upperCodes.Add('A', '4100')
$upperCodes.Add('B', '4200')
$upperCodes.Add('C', '4300')
$upperCodes.Add('D', '4400')
$upperCodes.Add('E', '4500')
$upperCodes.Add('F', '4600')
$upperCodes.Add('I', '4900')
$upperCodes.Add('S', '5300')


function encode([string]$AppID)
{
	$encoded = $null
    #foreach char in string, get encoded value from dictionary
	foreach ($char in [Char[]]$AppID)
	{
        #if char is uppercase look in uppercase dictionary
		if ([char]::IsUpper($char)) { $encoded = $encoded + $upperCodes.Get_Item($char.ToString()) } 
		else { $encoded = $encoded + $codes.Get_Item($char.ToString()) }
	}
	return $encoded
}

function lookUpKey($code)
{
    $returnVal = $null
    #look in lowercase dictionary for code
    if ($codes.ContainsValue($code)) 
    { 
        foreach ($key in ($codes.GetEnumerator() | Where-Object {$_.Value -eq $code}))
        {
            $returnVal = $key.Name
        }
    }
    #if not there look in uppercase dictionary
    elseif ($upperCodes.ContainsValue($code))
    {
        foreach ($key in ($upperCodes.GetEnumerator() | Where-Object {$_.Value -eq $code}))
        {
            $returnVal = $key.Name
        }
    }
    return $returnVal
}

function decode([string]$AppIDSig)
{
    $i = 0
    $Code = $null
    $decoded = $null

    foreach ($char in [Char[]]$AppIDSig)
    {
        #if less then 4 characters in code grab next character
        if ($i -le 3)
        {
            #build 4 char codes
            $code = $code + $char
            $i++
        }
        #if 4 characters are in code lookup the decoded value
        else
        {
            $decoded = $decoded + (lookUpKey $code)
            
            #reset code and start building 4 char code again
            $code = $char
            $i = 1
        }
    } 
    #foreach statement does not iterate the last time to get last code, look up value for last code here
    $decoded = $decoded + (lookUpKey $code)

    return $decoded
}