Search the Windows Store from Powershell

Let’s look at the Windows Store. Lots of apps (and growing) and with all of us being the Powershell-hungry people we are, Let’s search the store with Powershell!

I used Fiddler to grab the search string. Looking at the URL call, I image that this may be changed/updates as time goes by, however, since we don’t have an official Windows Store API to work with, this will have to do. The main web request I found and used was:
https://next-services.apps.microsoft.com/search/6.3.9600-0/776/en-US_en-US/m/US/c/US/il/en-US/cp/10005001/query/cid/0/pf/1/pc/0/pt/x64/af/0/lf/1/s/0/2/pn/0/pgc/-1?phrase=Netflix

Obviously replacing “Netflix” at the end will allow us to put in our own string to search with. For example, if I wanted to search for Zillow we could simply modify the string:
https://next-services.apps.microsoft.com/search/6.3.9600-0/776/en-US_en-US/m/US/c/US/il/en-US/cp/10005001/query/cid/0/pf/1/pc/0/pt/x64/af/0/lf/1/s/0/2/pn/0/pgc/-1?phrase=Zillow

The search results come back in XML. Within Powershell we can use the Invoke-WebRequest to get the response and then convert over to an XML object.

$appResult = Invoke-WebRequest -Uri "https://next-services.apps.microsoft.com/search/6.3.9600-0/776/en-US_en-US/m/US/c/US/il/en-US/cp/10005001/query/cid/0/pf/1/pc/0/pt/x64/af/0/lf/1/s/0/2/pn/0/pgc/-1?phrase=Netflix"

[xml]$appResultXml = $appResult.Content

Note: When using your own search string, spaces need to be formatted in a “URL” friendly way (For example, a space ends up being %20). With Powershell we can use the static method EscapeDataString to give us a good string:

$newFormattedString = [System.Uri]::EscapeDataString("Hello I Have Spaces")
Write-Host $newFormattedString
> Hello%20I%20Have%20Spaces

If you want, you can pipe $appResultXml to the Out-File cmdlet and look at the XML for a better visual understanding. Dig down to the “Pt” elements (there should be more than one). Each Pt element is a result in our search. The more results, the more Pt’s. Digging into each Pt elemet we get some additional information on each app in the result. If we go back to powershell, we can easily loop through these items and give us some additional data:

# Loop through the Results
foreach ($appResObj in $appResultXml.rslt.ptl.pts.pt)
{
        write-host "ProductFamily Name:`t" $($appResObj).pfn
        write-host "Language:`t" $($appResObj).L
        write-host "Title:`t" $($appResObj).T
        write-host "Age Rating:`t" $($appResObj).Wr
        write-host "Average Rating:`t" $($appResObj).Sr
        write-host "Total Reviews:`t" $($appResObj).src
        write-host "Currency Code:`t" $($appResObj).Cc
        write-host "Cost:`t" $($appResObj).p
        write-host "Category Name:`t" $($($appResObj).n).i
        write-host "Category ID:`t" $($($appResObj).c).n
        write-host "Developer Name:`t" $($appResObj).Dev
        write-host "Developer ID:`t" $($appResObj).DevI
        write-host "`n`n"
}

In our Zillow response from above, the output will look like this:

ProductFamily Name:	 Zillow.Zillow_nxemgnmz6chhm
Language:	 en
Title:	 Zillow
Age Rating:	 7
Average Rating:	 4
Total Reviews:	 332
Currency Code:	 USD
Cost:	 0.00
Category Name:	 Lifestyle
Category ID:	 14
Developer Name:	 Zillow
Developer ID:	 844427398339648

ProductFamily Name:	 60695TheRobot.Housevalue_8m7qmqa133yjj
Language:	 en-us
Title:	 House value
Age Rating:	 12
Average Rating:	 3.4
Total Reviews:	 28
Currency Code:	 USD
Cost:	 0.00
Category Name:	 Finance
Category ID:	 17
Developer Name:	 The Robot
Developer ID:	 306107898116081

ProductFamily Name:	 51189ApoorvUpadhyay.Neighbourhood_2z112j43hyvdw
Language:	 en-us
Title:	 Neighbourhood
Age Rating:	 7
Average Rating:	 1
Total Reviews:	 1
Currency Code:	 USD
Cost:	 1.49
Category Name:	 Tools
Category ID:	 19
Developer Name:	 ApoorvUpadhyay
Developer ID:	 985156469124598

and two more....(Shortened for brevity)

For me the benefit of this is being able to grab the “Category” for an app programmatically. If we have SCCM 2012 R2, we can easily use that inventoried information and locate the additional information. I use the query down below. Note the where clause to exclude built in apps that are not in the Windows Store. I’m also doing a “distinct” because I don’t care about the version of each (The ApplicationName and FamilyName are consistent even when the version changes).

select distinct
	ApplicationName0,
	FamilyName0,
	PublisherId0
from v_GS_WINDOWS8_APPLICATION
where IsFramework0 = 0

If we use these results you’ll need to take “ApplicationName” and split the string. This string is in a format <Developer>.<Application>. Searching using the URL above, using the Publisher name may not return what we want (at least in my findings).

$appName = "4DF9E0F8.Netflix"                   # ApplicationName0
$appSearchableName = $appName.Split('.')[1]     # Since ApplicationName0 is <Developer>.<Application> we only want <Application> for searching

After the simple Split, we’ll have the 2nd half of the ApplicationName string (“Netflix” in the example above.) Add in the new $appSearchableName to the WebRequest above, and check it out! Today, I’m grabbing the Category data (as well as the rest of the information) into a database and keying off of the FamilyName column in the SCCM SQL View v_GS_Windows8_Applications. If you do want to match this data up with what is in SCCM, I’d recommend nesting an if statement to check the returned “pfn” (product family name) with the “FamilyName” column in SCCM.

Things to Consider:

  • The search URL I’m using appears to have some version and architecture information in it. My guess is this will change but only time will tell.
  • I did find some applications that may be thrown off by my split command. For example, if the application or publisher name has “.NET” in the name the additional “.” will throw this off.
  • I have had instances where the application is not found by the search string i’m generating. I’m experimenting with some RegEx and other string manipulators to try to add spaces or search until the desired result is found.

Using this process, I was able to pull in about 75% of the inventoried apps within SCCM that we have (out of ~300 distinct apps). It’s not perfect but I am still working on this, so hopefully I can provide some meaningful updates soon!

Enjoy!

Advertisements