Microsoft Store Intune Integration – Graph Commands

With the new Store Integration now speedily being added to tenants and my previous post on adding Company Portal proving so popular, I thought I’d have a look at what else is sitting in Graph

This post from Sander Rozemuller gave me an excellent starting point and the script dropped nicely into a function:

The full script can be found here on GitHub

Function Add-MSStoreApp(){
        
    <#
    .SYNOPSIS
    This function adds Microsoft Store Apps using Winget
    .DESCRIPTION
    The function connects to the Graph API Interface and creates a Microsoft Store App using the new experience
    .EXAMPLE
    Add-MSStoreApp -name "WhatsApp"
    .NOTES
    NAME: Add-MSStoreApp
    #>
    
    [cmdletbinding()]
    
    param
    (
        $name
    )
$appName = $name
$storeSearchUrl = "https://storeedgefd.dsx.mp.microsoft.com/v9.0/manifestSearch"
$body = @{
    Query = @{
        KeyWord   = $appName
        MatchType = "Substring"
    }
} | ConvertTo-Json
$appSearch = Invoke-RestMethod -Uri $storeSearchUrl -Method POST -ContentType 'application/json' -body $body
$exactApp = $appSearch.Data | Where-Object { $_.PackageName -eq $appName }

$appUrl = "https://storeedgefd.dsx.mp.microsoft.com/v9.0/packageManifests/{0}" -f $exactApp.PackageIdentifier
$app = Invoke-RestMethod -Uri $appUrl -Method GET 
$appId = $app.Data.PackageIdentifier
$appInfo = $app.Data.Versions[-1].DefaultLocale
$appInstaller = $app.Data.Versions[-1].Installers


    $appdescription = ($appInfo.Shortdescription).ToString()
    $appdescription2 = $appdescription.replace("`n"," ").replace("`r"," ").replace("\n"," ").replace("\\n"," ")
    $appdeveloper = $appInfo.Publisher
    $appdisplayName = $appInfo.packageName
    $appinformationUrl = $appInfo.PublisherSupportUrl
    $apprunAsAccount = ($appInstaller.scope | select-object -First 1)
    $appisFeatured = $false
    $apppackageIdentifier = $appId
    $appprivacyInformationUrl = $appInfo.PrivacyUrl
    $apppublisher = $appInfo.publisher


$deployUrl = "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps"
$json = @"
{
	"@odata.type": "#microsoft.graph.winGetApp",
	"categories": [],
	"description": "$appdescription2",
	"developer": "$appdeveloper",
	"displayName": "$appdisplayName",
	"informationUrl": "$appinformationUrl",
	"installExperience": {
		"runAsAccount": "$apprunAsAccount"
	},
	"isFeatured": false,
	"notes": "",
	"owner": "",
	"packageIdentifier": "$apppackageIdentifier",
	"privacyInformationUrl": "$appprivacyInformationUrl",
	"publisher": "$apppublisher",
	"repositoryType": "microsoftStore",
	"roleScopeTagIds": []
}
"@

$appDeploy = Invoke-mggraphrequest -uri $deployUrl -Method POST -Body $json -ContentType "application/JSON"



return $appDeploy
}

I also separated out the assignment and switched it to Group ID rather than everyone (NOTE: the group needs to be a user group):

Function Add-StoreAppAssignment(){

    <#
    .SYNOPSIS
    This function is used to add a store app assignment using the Graph API REST interface
    .DESCRIPTION
    The function connects to the Graph API Interface and adds a store app assignment
    .EXAMPLE
    Add-StoreAppAssignment -StoreAppID $StoreAppIdId -TargetGroupId $TargetGroupId
    Adds a Store app assignment in Intune
    .NOTES
    NAME: Add-SStoreAppAssignment
    #>
    
    [cmdletbinding()]
    
    param
    (
        $StoreAppID,
        $TargetGroupId
    )
    
    $graphApiVersion = "Beta"
    $Resource = "deviceManagement/deviceAppManagement/mobileApps/$storeAppID/assign"
        
        try {
    
            if(!$StoreAppID){
    
            write-host "No Compliance Policy Id specified, specify a valid Compliance Policy Id" -f Red
            break
    
            }
    
            if(!$TargetGroupId){
    
            write-host "No Target Group Id specified, specify a valid Target Group Id" -f Red
            break
    
            }
    
    $JSON = @"
    {
        "mobileAppAssignments":  [
                                     {
                                         "settings":  {
                                                          "installTimeSettings":  null,
                                                          "notifications":  "showAll",
                                                          "restartSettings":  null,
                                                          "@odata.type":  "#microsoft.graph.winGetAppAssignmentSettings"
                                                      },
                                         "intent":  "Required",
                                         "target":  {
                                            "groupId": "$TargetGroupId"
                                                    },
                                         "@odata.type":  "#microsoft.graph.mobileAppAssignment"
                                     }
                                 ]
    }
"@
    
        $uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)"
        Invoke-MgGraphRequest -Uri $uri -Method Post -Body $JSON -ContentType "application/json"
    
    
        }
        
        catch {
    
        $ex = $_.Exception
        $errorResponse = $ex.Response.GetResponseStream()
        $reader = New-Object System.IO.StreamReader($errorResponse)
        $reader.BaseStream.Position = 0
        $reader.DiscardBufferedData()
        $responseBody = $reader.ReadToEnd();
        Write-Host "Response content:`n$responseBody" -f Red
        Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
        write-host
        
    
        }
    
    }

Then a function to display all Store Apps:

    Function Get-MSStoreApps(){
        
        <#
        .SYNOPSIS
        This function is used to get MS Store Apps from the Graph API REST interface
        .DESCRIPTION
        The function connects to the Graph API Interface and gets any MS Store Apps
        .EXAMPLE
        Get-MSStoreApps
        Returns any MS Store Apps configured in Intune

        Get-MSStoreApps -id $id
        Returns specific app
        .NOTES
        NAME: Get-MSStoreApps
        #>
        
        [cmdletbinding()]
        
        param
        (
            $id
        )
        
        $graphApiVersion = "beta"
        $DCP_resource = "deviceAppManagement/MobileApps"
        
            try {
        
                if($Name){
        $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)/$id"
        ((Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).value)

                }
        
                else {
        
                $uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)?`$filter=(isof('microsoft.graph.winGetApp'))"
        (Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).value
        
                }
        
            }
        
            catch {
        
            $ex = $_.Exception
            $errorResponse = $ex.Response.GetResponseStream()
            $reader = New-Object System.IO.StreamReader($errorResponse)
            $reader.BaseStream.Position = 0
            $reader.DiscardBufferedData()
            $responseBody = $reader.ReadToEnd();
            Write-Host "Response content:`n$responseBody" -f Red
            Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
            write-host
            
        
            }
        
        }

Putting these together you could:

Assign all Store apps:

##Assign Store Apps
$sapps = Get-MSStoreApps

foreach ($sapp in $sapps) {
Add-StoreAppAssignment -Id $sapp.id -TargetGroupId "$intunegrp.id"GROUPIDHERE"
}

Or add multiple apps:

##List of apps to install
$storeapps = @("Company Portal", "Microsoft To Do: Lists, Tasks & Reminders", "Windows Terminal")

##Add each
foreach ($app in $storeapps) {
   Add-MSStoreApp -Name $app
}

The possibilities are endless!!

8 thoughts on “Microsoft Store Intune Integration – Graph Commands”

  1. trying this with MS teams and the runas account is blank. if i put SYSTEM, it will create the app and i can assign it, but it fails to install (gets stuck on “Installing”) and i am unsure how to troubleshoot.

    if i use your function to generate the JSON, i get this, where RunAsAccount is blank. i know win32 apps are in preview in Intune/Winget world. i just want to validate that i cannot use this method for teams and that its not supported as a SYSTEM install and i will need to use a winget script.

    {
    “@odata.type”: “#microsoft.graph.winGetApp”,
    “categories”: [],
    “description”: “Make amazing things happen together at home, work, and school by connecting and collaborating with anyone from anywhere.”,
    “developer”: “Microsoft Corporation”,
    “displayName”: “Microsoft Teams”,
    “informationUrl”: “https://go.microsoft.com/fwlink/p/?linkid=2126612”,
    “installExperience”: {
    “runAsAccount”: “”
    },
    “isFeatured”: false,
    “largeIcon”: {
    “@odata.type”: “#microsoft.graph.mimeContent”,
    “type”: “string”,
    “value”: “”
    },
    “notes”: “”,
    “owner”: “”,
    “packageIdentifier”: “XP8BT8DW290MPQ”,
    “privacyInformationUrl”: “https://privacy.microsoft.com/en-US/privacystatement#mainnoticetoendusersmodule”,
    “publisher”: “Microsoft Corporation”,
    “repositoryType”: “microsoftStore”,
    “roleScopeTagIds”: []
    }

    Reply
  2. I actually found that I could install Adobe Creative Cloud if I changed the scope to user from machine. I didn’t realize that the following was also in the error.
    {“error”:{“code”:”ModelValidationFailure”,”message”:”Requested value ‘machine’ was not found.”

    The icon generation fails for every app I tested with. The API also doesn’t seem to accept machine scope so unsure how to requested accepted values.

    Reply
  3. It’s also failing for me. Trying to get Adobe Create Cloud deployed. I also had to remove the icon capture piece as that was failing completely.

    Invoke-mggraphrequest : POST https://graph.microsoft.com/beta/deviceAppManagement/mobileApps
    HTTP/1.1 400 Bad Request

    {“error”:{“code”:”BadRequest”,”message”:”Unable to read JSON request payload. Please ensure Content-Type header is set and payload is of valid JSON
    format.”

    Reply

Leave a Comment