Skip to content

Admin Guide

This guide walks administrators through setting up and managing the App Store for Intune using the web-based admin interface.

Getting Started

After initial deployment and Entra ID configuration (see SETUP.md), most portal configuration can be done directly through the Admin Dashboard.

Accessing the Admin Dashboard

  1. Sign in to the portal with an account that is a member of the Admin Group
  2. Click Admin in the navigation menu
  3. The admin portal uses an Intune-style left-rail navigation (v1.28.0+) grouped into four sections that mirror the Microsoft Intune admin center layout. If you've used Intune, the structure should already feel familiar:

Apps - App Management — Manage apps synced from Intune (visibility, approval workflows, deployment options, version rollback) - App Catalog — Browse the public WinGet repository and publish apps to Intune - App Upload (v1.29.0+) — Upload custom .msi installers for apps that aren't in WinGet - App Updates — Track and deploy update versions for published apps with ring-based rollouts

Approvals - Pending Approvals — Review and approve/reject requests

Reports - Analytics — Request volume, approval throughput, install outcomes, ROI calculator - Store Health — Operational metrics for the portal itself (request volume, deploy pipeline, error rates, latency) - Activity Log — Full timeline of packaging jobs and update deployments

Store Administration - Settings — Authorization, deployment defaults, automation policies, WinGet integration - Branding — Logo, favicon, brand colors, footer - Communications — Company info, notification recipients, Terms of Service, per-event toggles - License — PowerStacks license activation and entitlement status

Setup Wizard

For first-time setup or to reconfigure the portal, use the Setup Wizard:

  1. Go to Admin > Settings tab
  2. Click the 🚀 Setup Wizard button
  3. Follow the guided steps:
  4. Welcome - Overview of setup steps
  5. License - Enter and validate your PowerStacks license key
  6. Access Groups - Configure Admin and Approver Entra ID groups
  7. Email Notifications - Set up email settings for notifications
  8. Sync Apps - Import apps from your Intune tenant

The wizard saves your settings as you progress through each step. You can skip the wizard at any time and configure settings manually.

Note: The License step is required for the portal to be fully operational. Without a valid license, users will see warning banners and some features may be restricted.

Quick Reference Commands (shown in wizard completion): | Component | Command | |-----------|---------| | API (includes packaging service) | cd src/AppRequestPortal.API && dotnet run | | Web | cd src/AppRequestPortal.Web && npm start |

Portal Settings

The Settings tab allows you to configure portal-wide options including authorization, display settings, deployment configuration, and version management. Notification and messaging settings are on the Communications tab (see below).

Group-Based Authorization

Control who has admin and approver access to the portal.

Setting Description
Admin Group (Required) Entra ID group Object ID. Members have full admin access to sync apps, manage settings, and view all requests. If not configured, all admin endpoints return 403 Forbidden.
Approver Group Entra ID group Object ID. Members can approve/reject requests (in addition to workflow-specific approvers)

Important (v1.10.6+): The Admin Group is required. If no Admin Group ID is configured (in either portal settings or appsettings.json), all users are denied admin access. See SETUP.md for initial configuration instructions.

Lost admin access? If the Admin Group ID is accidentally cleared from portal settings, the appsettings.json / environment variable value is used as a fallback. If neither is set, you must set AppSettings__AdminGroupId as an environment variable (or in appsettings.json) and restart the application to regain access.

Since the App Store for Intune is used to request apps for Intune-managed devices, we recommend protecting access to the portal with a Conditional Access policy that requires: - Managed device - The device accessing the portal must be enrolled in Intune - Compliant device - The device must meet your organization's compliance policies

This ensures users can only request apps from trusted, compliant devices.

Prerequisites

Before creating the policy: 1. You must have Entra ID Premium P1 or P2 license (or Microsoft 365 E3/E5, etc.) 2. You need the Conditional Access Administrator or Global Administrator role 3. Have at least one compliance policy configured in Intune

Creating the Conditional Access Policy

  1. Navigate to Conditional Access
  2. Go to Azure Portal
  3. Navigate to Microsoft Entra ID > Security > Conditional Access
  4. Click + New policy

  5. Name the Policy

  6. Enter a descriptive name: App Store for Intune - Require Compliant Device

  7. Configure Assignments - Users

  8. Under Users, click 0 users and groups selected
  9. Select Include > All users
  10. (Optional) Under Exclude, add a break-glass admin account for emergency access

  11. Configure Assignments - Target Resources

  12. Under Target resources, click No target resources selected
  13. Select Cloud apps
  14. Click Include > Select apps
  15. Search for and select your App Store for Intune app registrations:
    • App Store for Intune API (or your API app registration name)
    • App Store for Intune Frontend (or your frontend app registration name)
  16. Click Select

  17. Configure Conditions (Optional)

  18. Under Conditions > Device platforms
  19. Click Not configured
  20. Set Configure to Yes
  21. Select Include > Select device platforms
  22. Check: Windows, iOS, Android (the platforms you manage)
  23. Click Done

  24. Configure Access Controls - Grant

  25. Under Grant, click 0 controls selected
  26. Select Grant access
  27. Check Require device to be marked as compliant
  28. Check Require Microsoft Entra hybrid joined device (optional, for hybrid environments)
  29. Select Require one of the selected controls (OR) or Require all the selected controls (AND) based on your requirements
  30. Click Select

  31. Configure Session Controls (Optional)

  32. Under Session, you can configure:

    • Sign-in frequency: Require re-authentication periodically
    • Persistent browser session: Disable persistent sessions for extra security
  33. Enable the Policy

  34. Set Enable policy to Report-only first to test
  35. Click Create

  36. Test and Enable

  37. Monitor the Sign-in logs for a few days in Report-only mode
  38. Verify legitimate users can access the portal from compliant devices
  39. Verify access is blocked from non-compliant/unmanaged devices
  40. Once verified, edit the policy and change to On

Policy Summary

Setting Value
Name App Store for Intune - Require Compliant Device
Users All users (exclude break-glass account)
Cloud apps App Store for Intune API, App Store for Intune Frontend
Conditions Device platforms: Windows, iOS, Android
Grant Require device to be marked as compliant
Enable policy Report-only (then On after testing)

Troubleshooting Access Issues

If users report they cannot access the portal:

  1. Check Sign-in Logs
  2. Go to Microsoft Entra ID > Sign-in logs
  3. Filter by the user and application
  4. Look for Failure entries and check the Conditional Access tab
  5. The tab shows which policies applied and why access was denied

  6. Common Issues | Issue | Solution | |-------|----------| | Device not enrolled | User needs to enroll their device in Intune | | Device not compliant | User needs to resolve compliance issues (updates, encryption, etc.) | | Using personal device | User needs to use their work-managed device | | Policy excluding wrong users | Review the Exclude settings in the CA policy |

  7. Verify Device Status

  8. Go to Microsoft Intune admin center > Devices
  9. Search for the user's device
  10. Check Compliance status and any failed compliance policies

Alternative: Allow Browser Access with App Protection

If you need to allow browser access from unmanaged devices (less secure), you can create an alternative policy:

  1. Create a second CA policy for browser access
  2. Target the same apps
  3. Under Conditions > Client apps, select Browser only
  4. Under Grant, require Approved client app or App protection policy
  5. This allows access from unmanaged devices but with some protection

Recommendation: For maximum security, require compliant managed devices. The App Store for Intune is designed for employees requesting apps on their managed devices, so this policy aligns with the intended use case.

General Settings

Setting Description
Require manager approval by default When enabled, new approval workflows include manager approval as the first stage
Auto-create Entra ID groups Automatically create a security group when an app doesn't have a target group configured

Version & Updates

The Settings tab displays version information and update settings:

Setting Description
Current Version Displays the installed portal version, build date, and environment
Automatically check for updates When enabled, the portal periodically checks for new versions
Show update notifications When enabled, displays a notification banner when updates are available
Check for Updates Manual button to check for available updates
Install Update One-click button to download and install updates (requires configuration)

When an update is available, you'll see: - Update badge with the new version number - Link to release notes - Install Update button (if auto-update is configured)

Enabling In-App Updates

The portal supports one-click updates directly from the Admin Dashboard. This feature downloads the latest release and deploys it via Azure's Kudu ZIP deploy API.

Prerequisites: - Portal must be running in Azure App Service - Deployment credentials must be configured

Configuration Steps:

  1. Get Deployment Credentials from Azure Portal:
  2. Go to your App Service → Deployment CenterFTPS credentials
  3. Copy the Username (starts with $, e.g., $app-apprequest-prod-abc123)
  4. Copy the Password

  5. Add App Settings in Azure Portal:

  6. Go to your App Service → ConfigurationApplication settings
  7. Add these settings:
Name Value
Deployment__PublishUser Your FTPS username (e.g., $app-apprequest-prod-abc123)
Deployment__PublishPassword Your FTPS password
  1. Using the Update Feature:
  2. Go to Admin > Settings > Version & Updates
  3. Click Check for Updates to see if a new version is available
  4. If configured correctly, an Install Update button appears
  5. Click to download and deploy the update automatically
  6. The application will restart during the update process

Note: The Install Update button only appears when: - The portal is running in Azure App Service (not locally) - Deployment credentials are properly configured - An update is available

Manual Updates

If auto-update is not configured, you can manually update using either method below:

Method 1: Kudu ZIP Deploy (Recommended for existing installations)

For existing deployments, use the Kudu ZIP deployment feature:

  1. Go to the releases repository
  2. Download the latest AppRequestPortal-X.X.X.zip file (not the source code)
  3. In Azure Portal, navigate to your App Service
  4. Click Advanced ToolsGo (opens Kudu)
  5. Click ToolsZip Push Deploy
  6. Drag and drop the downloaded ZIP file into the deployment area
  7. Wait for deployment to complete (watch the logs)
  8. Restart your App Service if needed
  9. Database migrations will run automatically on next startup

Note: This method preserves your existing configuration and database. The ZIP contains only application files.

Method 2: Deploy to Azure Button (New installations only)

For fresh installations on an empty resource group:

  1. Go to the releases repository
  2. Click the Deploy to Azure button
  3. Select an empty resource group or create a new one
  4. Configure deployment parameters

Important: The Deploy to Azure button will fail on resource groups containing existing resources. Use Method 1 for existing deployments.

License Management

The portal requires a valid PowerStacks license to operate. License status is displayed in the Admin Dashboard and affects portal functionality.

Viewing License Status

  1. Go to Admin > Settings tab
  2. The License section shows:
  3. Current license status (Valid, Expired, Over Device Limit, etc.)
  4. License type and expiration date
  5. Device count vs. licensed limit
  6. Last validation timestamp

License Validation

The portal automatically validates your license: - On application startup - Every 24 hours - When you manually click Validate License

To force a validation check, click the Validate License button in the License section.

Updating License Key

  1. Go to Admin > Settings tab
  2. In the License section, enter your new license key
  3. Click Save License Key
  4. The portal validates the new key and displays the result

Alternatively, use the Setup Wizard to enter or update your license key.

License Warnings

Users see warning banners in the following situations:

Condition Banner Message
License expiring soon (≤30 days) "License expires in X days. Please contact your IT administrator to renew."
Device count in grace period (up to 3% over limit) "Device count exceeds license limit by X devices. Please contact your IT administrator to upgrade."
License invalid/expired Warning message explaining the issue

Note: When device count exceeds the license limit by more than 3%, new app requests are blocked until the license is upgraded or device count is reduced.

Device Count

The portal tracks managed devices from Intune that have checked in within the last 30 days. Device count is updated: - During each app sync from Intune - When you click Update Device Count in the License section

Display Settings

Configure the portal's visual appearance for all users.

Setting Description
Enable dark mode Toggle dark mode on/off for all portal users (default setting)
Max featured apps on home page Maximum number of featured apps to display in the home page carousel (default: 8)
Hero App Select one app to feature prominently at the top of the home page

Dark Mode Behavior:

The portal supports multiple dark mode sources with the following priority: 1. User preference - Users can click the sun/moon icon (☀️/🌙) in the header to toggle dark mode for themselves 2. System preference - If the user hasn't set a preference, the portal auto-detects the operating system's dark mode setting 3. Admin default - Falls back to the admin-configured dark mode setting

User preferences are stored in localStorage and persist across sessions. Users can always override the admin setting for their own viewing preference.

Dark Mode Styling: When dark mode is enabled, the portal uses a vignette-style design inspired by Microsoft Learn and Intune admin center: - Main content area: Darkest (#1a1a1a) with subtle inset shadow for depth - Header/Footer: Medium dark (#252525) with subtle borders - Outer edges: Lighter dark gray (#2d2d2d)

This creates a professional look where the center content draws focus while the periphery provides visual framing.

Note: Dark mode settings persist across page refreshes and login/logout cycles. The admin setting is loaded via a public API endpoint so it applies even before the user authenticates.

App Deployment Settings

Setting Description
Group Name Prefix Prefix used when auto-creating Entra ID groups (default: AppStore-). Groups are named {prefix}{AppName}-Required. Use this to identify portal-managed groups in your tenant.

Custom Domain Configuration

The Settings tab includes a Custom Domain section for configuring a custom domain (e.g., apps.yourdomain.com) for your portal.

Prerequisites

Before configuring a custom domain: 1. Your DNS must be configured with the appropriate CNAME or A record pointing to your Azure App Service 2. Your Azure App Service must be on the Basic tier or higher (required for custom domains with SSL)

Configuring via Admin Dashboard

  1. Go to Admin > Settings tab
  2. Scroll to the Custom Domain section
  3. Read the prerequisites and ensure DNS is configured
  4. Click Configure Custom Domain in Azure
  5. This opens the Azure Portal with a pre-configured ARM template that:
  6. Adds your custom domain to the App Service
  7. Creates a free Azure-managed SSL certificate
  8. Binds the certificate to your domain

After Configuration

Once your custom domain is configured:

  1. Update Entra ID Redirect URIs - Add your custom domain URLs to your App Registration
  2. Update Portal URL - In Communications > Email Notifications, update the Portal URL to use your custom domain
  3. Test Authentication - Sign out and sign back in to verify authentication works

Note: For detailed DNS configuration, certificate options, and troubleshooting, see CUSTOM-DOMAINS.md.

Communications

The Communications tab (formerly "Terms of Service") consolidates all notification, messaging, and company branding settings in one place.

Company Information

Configure your organization's branding details. These fields are used in notification messages and will support further message customization in future releases.

Setting Description
Company Name Your organization's name, displayed in notifications
Company Logo Upload a logo image (PNG/JPEG). Displayed in branded communications
Support Email Contact email for support inquiries
Support Phone Contact phone number for support

Email Notifications

Configure how the portal sends email notifications for request submissions and approvals.

Setting Description
Enable email notifications Toggle to turn email notifications on or off
Send As User ID The Entra ID Object ID of the user or shared mailbox that will send emails. Find this in Azure Portal > Entra ID > Users > [select user] > Object ID
From Address The email address displayed in the From field (should match the mailbox)
Portal URL The URL of your portal, used in email links to direct users back to the portal

Email Events — When email notifications are enabled, you can toggle individual events:

Event Description
Request Submitted Notify requestor when their request is submitted
Approval Required Notify approvers when their approval is needed
Request Approved Notify requestor when their request is approved
Request Rejected Notify requestor when their request is rejected
App Installed Notify requestor when their app is installed on their device
App Published Notify admin when a WinGet app is published to Intune

Note: The app registration must have the Mail.Send Microsoft Graph application permission with admin consent granted.

Creating a Service Account for Email Notifications

For production deployments, we recommend creating a dedicated shared mailbox or service account with minimal permissions rather than using a personal user mailbox. This ensures email delivery is not tied to any individual's account.

Option A: Shared Mailbox (Recommended — No License Required)

  1. In the Microsoft 365 Admin Center, go to Teams & Groups > Shared mailboxes
  2. Click Add a shared mailbox:
  3. Name: App Store for Intune (or your preferred name)
  4. Email: apprequests@yourdomain.com
  5. Click Create
  6. Get the Object ID: Go to Azure Portal > Entra ID > Users > search for the shared mailbox > copy the Object ID
  7. In the portal admin settings, set:
  8. Send As User ID: The Object ID from step 4
  9. From Address: apprequests@yourdomain.com

Shared mailboxes do not require a Microsoft 365 license and cannot be used for interactive sign-in, making them ideal for automated email sending.

Option B: Dedicated Service Account (License Required)

  1. In Azure Portal > Entra ID > Users > New user:
  2. Display name: App Store for Intune Service
  3. User principal name: svc-apprequest@yourdomain.com
  4. Assign a Microsoft 365 license with Exchange Online
  5. Disable interactive sign-in: Entra ID > Users > [service account] > Properties > Account enabled = No (or use Conditional Access to block interactive sign-in)
  6. Copy the Object ID and configure as with Option A

Permissions Required:

The portal sends emails using the Microsoft Graph Mail.Send application permission via the backend app registration. This permission allows the app to send mail as any user in the organization. To limit which mailbox the portal actually uses:

  • Configure the Send As User ID in the portal settings to the specific shared mailbox or service account Object ID
  • Optionally, use an Exchange Online Application Access Policy to restrict the Mail.Send permission to only the designated mailbox:
# Connect to Exchange Online
Connect-ExchangeOnline

# Create a mail-enabled security group for allowed senders
New-DistributionGroup -Name "App Store Email Senders" -Type Security

# Add the shared mailbox to the group
Add-DistributionGroupMember -Identity "App Store Email Senders" -Member "apprequests@yourdomain.com"

# Restrict the app registration to only send from mailboxes in this group
New-ApplicationAccessPolicy `
    -AppId "<your-api-client-id>" `
    -PolicyScopeGroupId "App Store Email Senders" `
    -AccessRight RestrictAccess `
    -Description "Restrict App Store for Intune to send emails only from the designated mailbox"

# Test the policy (may take up to 30 minutes to propagate)
Test-ApplicationAccessPolicy -AppId "<your-api-client-id>" -Identity "apprequests@yourdomain.com"

Actionable Email Messages (Approve/Reject Buttons)

When enabled, approval notification emails include Approve and Reject buttons directly in the email body (Outlook Actionable Messages). Approvers can approve or reject requests without leaving their inbox.

Important: Actionable email buttons require a one-time provider registration with Microsoft and configuring the Originator / Provider ID in the portal settings. Without registration, emails will still be sent — they will contain the standard HTML body with a "Review Request" link to the portal. The Approve/Reject buttons will only appear once registration is complete and the Originator ID is configured.

Setting Description
Enable actionable email messages Toggle to enable Approve/Reject buttons in approval emails
API Base URL for Email Actions The base URL of your API (e.g., https://apprequest-prod-xxx.azurewebsites.net). Used for the button callback endpoints.
Originator / Provider ID The Provider ID from your Microsoft Actionable Email registration. Required for Outlook to render action buttons.

How it works: 1. When a request requires approval, the email includes an embedded MessageCard with Approve/Reject buttons 2. The MessageCard is embedded in the email <head> as application/ld+json — Outlook reads this to render action buttons 3. When an approver clicks Approve or Reject, Outlook sends an HTTP POST directly to your API 4. The API validates the request using a secure action token and processes the approval 5. Fallback behavior: If Outlook doesn't support Actionable Messages, or if the provider is not registered, or if the Originator ID is not configured, the email falls back to the standard HTML body with a "Review Request" link to the portal. Emails are always sent regardless of registration status — only the action buttons are affected.

Registering with Microsoft (Required for Action Buttons):

Outlook Actionable Messages require a one-time provider registration with Microsoft. Without this registration, Outlook will silently ignore the action buttons and only show the HTML fallback with a "Review Request" link.

  1. Go to the Actionable Email Developer Dashboard
  2. Sign in with your Microsoft 365 admin account
  3. Click New Provider and fill in:
  4. Friendly Name: App Store for Intune (or your preferred name)
  5. Sender email address: The From Address configured in your email settings (e.g., apprequests@company.com)
  6. Target URL: Your API Base URL (e.g., https://apprequest-prod-xxx.azurewebsites.net)
  7. Scope: Select Organization (your tenant only — auto-approved by tenant admin)
  8. Public Key: Leave blank (not required for organization-scoped registrations)
  9. Submit the registration — organization-scoped registrations are auto-approved by the tenant admin
  10. Copy the Provider ID (GUID) from your registration
  11. In the portal admin settings, paste the Provider ID into the Originator / Provider ID field
  12. Allow up to 24 hours for the registration to take effect

Verifying Exchange Online Settings:

If action buttons still don't appear after registration, verify that Actionable Messages are enabled in Exchange Online:

# Check organization-level settings (both should be True)
Get-OrganizationConfig | FL ConnectorsActionableMessagesEnabled, SmtpActionableMessagesEnabled

# If disabled, enable them
Set-OrganizationConfig -ConnectorsActionableMessagesEnabled $true -SmtpActionableMessagesEnabled $true

# Check per-mailbox setting (should be True)
Get-Mailbox -Identity apprequests@company.com | FL ConnectorsEnabled

Important: Microsoft is transitioning Actionable Messages from External Access Tokens (EAT) to Entra ID token authentication. If Microsoft requires Entra ID tokens for new registrations, the portal's action endpoints may need to be updated in a future release. See the Entra ID Token documentation for details.

Microsoft Teams Bot Notifications

Send personal Teams notifications to approvers and requestors via a Teams Bot. Each user receives individual Adaptive Card messages in their Teams chat. This uses Microsoft Bot Framework proactive messaging.

Setting Description
Enable Teams bot notifications Toggle to turn Teams bot notifications on or off
Bot App ID Your API Client ID (the bot reuses the API app registration)
Test Send a test notification to yourself to verify the bot is working
Approval Required Notify approvers when their approval is needed
Request Approved Notify requestor when their request is approved
Request Rejected Notify requestor when their request is rejected
App Installed Notify requestor when their app is installed on their device
App Published Notify admin when a WinGet app is published to Intune

Prerequisites

  1. An Azure Bot resource registered in Azure Portal using your API app registration's Client ID (see SETUP.md)
  2. The Microsoft Teams channel enabled on the Azure Bot resource
  3. The bot pre-installed for users via Teams Admin Center setup policies

No separate Bot__ environment variables are needed — the bot uses AzureAd__ClientId, AzureAd__ClientSecret, and AzureAd__TenantId directly.

Configuring the Portal

  1. Go to Admin > Communications tab
  2. Scroll to Microsoft Teams Bot Notifications
  3. Enable Enable Teams bot notifications
  4. Enter the Bot App ID (your API Client ID — the bot reuses the same app registration)
  5. Click Test to send a test notification to yourself
  6. Select which events should trigger notifications
  7. Click Save Settings

How It Works

  • The bot is pre-installed for users via Teams Admin Center setup policies
  • When the bot is installed for a user, Teams sends a conversationUpdate event — the portal stores a conversation reference for that user
  • To send a notification, the portal retrieves the stored conversation reference and uses Bot Framework proactive messaging
  • For pooled approvals (group-based), the portal expands the group membership and sends individual messages to each group member
  • For sequential approvals, only the current stage approvers are notified
  • Notifications are sent as Adaptive Cards with request details and action buttons

Troubleshooting

  • Bot not sending messages: Verify the bot is installed for the user by checking the BotConversationReferences table
  • Test notification fails: Ensure the bot is installed for your user account first
  • 401 errors: Verify the Azure Bot resource's Microsoft App ID matches your AzureAd__ClientId and the client secret is valid
  • Some users don't receive notifications: The Teams Admin Center setup policy may take up to 24 hours to propagate

Note: No additional Microsoft Graph API permissions are required for Teams bot notifications. Bot Framework handles its own authentication.

Approval Reminders

Automatically send reminder emails for pending approvals.

Setting Description
Enable approval reminders Toggle to enable/disable automatic reminders
Reminder interval (days) Days before the first reminder is sent (default: 2)
Max reminders Maximum number of reminders per request (default: 3)

Stale Request Escalation

Automatically escalate requests that have been pending too long.

Setting Description
Enable escalation Toggle to enable/disable automatic escalation
Escalation threshold (hours) Hours before a request is escalated (default: 48)
Recipient email(s) Comma-separated email addresses for escalation notifications
Recipient group Entra ID group whose members receive escalation notifications

Terms of Service

The Terms of Service section remains within the Communications tab, allowing admins to create and manage TOS versions that users must accept.

App Management

The App Management tab is your central hub for managing which Intune apps are available in the portal and how they behave.

Syncing Apps from Intune

  1. Click the Sync Apps from Intune button
  2. The portal fetches all mobile apps from your Intune tenant
  3. Apps are imported with their name, publisher, description, icon, and category
  4. New apps are hidden by default - you must make them visible for users to see them

Incremental Sync: After the first full sync, subsequent syncs are incremental — only new and modified apps are fetched from Intune. The portal tracks the last sync date and uses lastModifiedDateTime filtering to minimize Graph API calls. Icons are fetched in parallel (5 concurrent requests) for faster sync times.

Scheduled Background Sync: A background service automatically syncs apps on a schedule: - Nightly full sync at 2:00 AM UTC — catches deletions and ensures consistency - Hourly incremental sync — picks up new and changed apps quickly - The manual Sync Apps from Intune button is still available for on-demand syncs

Pagination: The portal follows @odata.nextLink pagination from the Graph API, so tenants with more than 999 apps are fully supported.

Filtering the App List

The filter bar above the app table has six axes (v1.26.0+). All filters compose with the search box and persist while you navigate the tab:

Filter Values Default
Platform All / Windows / iOS / Android / macOS / Web (only platforms present in your tenant) All
Visibility All / Visible / Hidden All
Category All / (per-tenant categories) All
Source All / Store / Intune All
Purpose Install / Update / All Install
Search Free-text match against app name and publisher empty

Source distinguishes apps published through the App Store catalog flow (where the portal owns the lifecycle) from apps that already existed in Intune and were synced into the portal. Source = Store shows only apps with sourceWingetPackageId set — these are the apps where Version & Rollback, ring-based update deployments, and the Publish wizard apply.

Purpose distinguishes the user-facing Install Win32 app from the paired Update Win32 app that drives the two-app update model. The default is Install so the table shows the user-facing apps you'd expect; flip to Update when you need to inspect Update apps directly (for example to verify an Update app's group assignments or ring activation state). The flag is set automatically during Intune sync by joining against UpdateDeployment.UpdateIntuneAppId — there is no manual classification step.

App Table Columns

The app list table is read-only and informational. Click any row to open the app's detail view where you can edit settings.

Column Description
App App name, icon, and publisher
Platform App platform badge (Windows, iOS, Android, macOS, Web)
Type App type from Intune (e.g., Win32, Microsoft Store, iOS Store)
Assigned Status badge showing whether a target group is configured (Yes/No/N-A)
Visible Status badge showing whether users can see this app in the portal (Yes/No/N-A)
Approval Status badge showing whether approval is required (Yes/No/N-A)
Date Added When the app was first synced or published

Supported App Types

The portal supports self-service deployment for specific app types. When syncing apps from Intune, each app is classified by platform and support status:

Platform Supported Types Unsupported Types
Windows Win32, Microsoft Store (New) Windows Universal (LoB), MSI (LoB), AppX (LoB)
iOS iOS Store, iOS VPP iOS (LoB)
Android Android Store, Managed Google Play, Android for Work Android (LoB)
Web Web Apps -
macOS - All macOS app types

Why some types are unsupported: - Line of Business (LoB) apps require special handling during deployment that the portal cannot automate - macOS apps have different deployment mechanisms that are not yet implemented

Unsupported apps appear in the admin UI with their type displayed and an "N/A" status badge. Admins can see these apps exist but cannot make them available for self-service.

Configuring Individual Apps

Click any app row in the table to open its detail view. The detail view has two sections accessible from the left navigation:

  • Overview — Quick summary cards showing platform, visibility, approval status, assignment type, date added, and version
  • Properties — Grouped property sections (described below), each with an Edit link

Editing App Settings

There are three ways to edit app settings from the detail view:

  1. Side panel (quick edit) — Click "Edit" on the Visibility or Approval section to open a slide-out panel for fast single-field changes
  2. Settings wizard — Click "Edit" on the Assignment or Deployment Options section to open the full 5-step wizard, starting at the relevant step
  3. Edit All Settings — Click the "Edit All Settings" button to open the wizard from step 1

The App Settings Wizard has 5 steps:

Step Title Fields
1 Visibility & Store Visible, Featured, Category, Cost
2 Approval Requires Approval, Acknowledgment
3 Assignment Assignment type, Target group, Assignment filter
4 Deployment Options Install behavior, Restart behavior, Notifications, Grace period (Win32 only)
5 Review + Save Summary of all changes with diff highlighting

Visibility Settings

  • Yes: App appears in the user-facing app catalog
  • No: App is hidden from users but still tracked in the system
  • N/A: App type is not supported for self-service deployment

Use this to control which Intune apps are available for self-service requests. Apps that shouldn't be requested (system apps, dependencies, etc.) should remain hidden.

Hiding Apps with Active Deployments:

When you set an app's visibility to No and it has an active Intune deployment and Azure AD group, a confirmation dialog appears asking whether you also want to delete the deployment group and assignment:

  • OK: Hides the app AND removes the Intune assignment and deletes the Azure AD deployment group
  • Cancel: Only hides the app but preserves the deployment infrastructure (useful if you plan to make it visible again later)

Note: Deleting the deployment and group is permanent. Users who currently have the app will lose access when group membership is removed.

Automatic Deployment Setup:

When you set an app's visibility to Yes for the first time, the portal automatically:

  1. Creates an Entra ID Security Group named {GroupNamePrefix}{AppName}-{arch}-{locale}-v{version}-Required
  2. Example: AppStore-Microsoft Teams-x64-en-US-v1-0-0-Required
  3. The prefix is configurable in Settings (default: AppStore-)
  4. Dots in version numbers are replaced with dashes (e.g., 1.0.0 becomes v1-0-0)

  5. Creates an Intune App Assignment

  6. The app is assigned as Required to the new security group
  7. Assignment type (User or Device) is based on the app's Assignment setting

This automation ensures that when a user's request is approved, they simply need to be added to the group and Intune handles the deployment.

Note: If group or assignment creation fails, the error is logged but the visibility change still succeeds. You can manually create the assignment in Intune if needed.

Approval Settings

  • Yes: Requests go through the configured approval workflow before completion
  • No: Requests are auto-approved and the user/device is immediately added to the target group
  • N/A: App type is not supported

Approval can only be enabled for visible apps. If you try to enable approval for a hidden app, you'll see a warning: "App must be visible in the store to enable approval."

Delete from Intune

From the app detail view, apps with a real Intune deployment (not synced apps with a winget- prefix) can be deleted. This removes the app from both Intune and the portal entirely.

Confirmation flow:

  1. Step 1 — "Are you sure you want to delete [app name] from Intune?"
  2. Click Delete to proceed, or Cancel to abort
  3. Step 2 (only for portal-published apps with a deployment group) — "This app has a deployment group (group name). Do you also want to delete the deployment group?"
  4. Click Yes to delete the group, or No to keep it for reuse when republishing

What gets deleted:

Action Always Only if "Yes" to group deletion
Win32 app removed from Intune Yes
Intune assignment removed Yes
All associated requests removed Yes
App record removed from portal Yes
Entra ID security group deleted Yes

After deletion, the app is completely removed from the portal. To restore it, republish from the WinGet catalog.

When to use Delete from Intune: - You need to republish an app with updated settings (e.g., different silent switches, updated installer) - An app deployment is in a bad state and needs to be recreated - You want to permanently remove an app from both Intune and the portal

Edit App Modal

Click Edit on any app row to open the Edit App Modal, which provides access to all configurable app properties:

App Details Section

Field Description
Cost Optional cost to display on app cards (informational only, no billing). Enter a decimal value or leave empty for "Free".
Category App category displayed on app cards. Start typing to see suggestions from existing categories in your catalog. You can enter any category name.

Assignment Settings Section

Field Description
Assignment Type User (add requester to group) or Device (add requester's device to group)
Target Group Entra ID security group for app assignment. Click "Search Groups" to browse, or use "Clear" to remove.
Assignment Filter Optional Intune assignment filter. Select filter type (Include/Exclude) and choose a filter.

Win32 Deployment Options Section

These options appear only for Win32 apps and control Intune deployment behavior:

Field Description
Install Context System (machine-wide) or User (per-user) installation
Device Restart How to handle restart after install: Based on Return Code, Allow, Suppress, or Force
End User Notification What users see: Show All, Show Reboot Only, or Hide All
Allow Available Uninstall Whether users can uninstall from Company Portal
Restart Grace Period Enable/configure grace period before forced restart

Click Save to apply changes or Cancel to discard.

App Icon

Each app displays an icon in the catalog. Icons are typically synced from Intune, but some apps may be missing icons. The Edit App modal provides two ways to set an icon:

  • Upload Icon — Upload a PNG or JPEG image file from your computer
  • Browse Library — Opens the Icon Library picker, which shows all unique icons already used by other apps in the portal. Search by app name or publisher, then click an icon to apply it instantly. This is useful when multiple apps share the same publisher icon or when you want to reuse an existing icon without re-uploading.

Assignment Type

Determines what gets added to the Entra ID group when a request is approved:

  • User: The requesting user is added to the group (most common)
  • Device: The user's device is added to the group (useful for device-targeted deployments)

For Device assignment: - The portal auto-detects the user's current device based on browser/OS information - Devices matching the detected OS are pre-selected in the dropdown - The user can override the selection if they want to install on a different device - If a primary device is set in Intune and matches the current OS, it takes priority - The selected device is added to the target AAD group - Intune deploys the app to that specific device

Device Detection Logic: 1. Browser detects the operating system (Windows, macOS, iOS, Android) 2. Portal matches against the user's registered Intune devices 3. Matching devices are marked as "(Detected)" in the dropdown 4. A helpful message confirms the auto-detection: "This device was automatically detected based on your current browser."

Configuring Approval Workflows

Click the Workflow button on any app to open the Approval Workflow Editor.

No Approval Required

For apps with "Approval" set to "No", requests are auto-approved immediately. No workflow configuration is needed.

Simple Approval

For apps that just need someone from the Approver Group to sign off: 1. Set "Approval" to "Yes" 2. Leave the workflow with no stages 3. Any member of the configured Approver Group can approve

Manager + Additional Approvers

  1. Enable Require Manager Approval
  2. Choose workflow type:
  3. Linear: Specific users approve in sequence
  4. Pooled: Any member of specified groups can approve
  5. Add approval stages as needed

Conditional Stages (v1.8.2)

Each approval stage can be made conditional, so it only applies when specific criteria are met:

  1. Open the Approval Workflow Editor for an app
  2. Add a stage and assign an approver or group
  3. Toggle "Make this stage conditional"
  4. Add conditions using the condition builder:
  5. Select a condition type (Department, Cost Center, Job Title, Location, Platform, Request Count)
  6. Choose an operator (Equals, Not Equals, Contains, etc.)
  7. Enter the comparison value
  8. Add multiple conditions with AND/OR logic
  9. A human-readable summary of the conditions is shown on the stage card

See APPROVAL-WORKFLOWS.md for detailed condition types and operators.

See APPROVAL-WORKFLOWS.md for detailed workflow configuration options.

Version History and Rollback

The portal tracks version history for apps published from the App Catalog, enabling you to rollback to previous versions if a new version introduces issues.

Viewing Version History

  1. Go to Admin > App Management tab
  2. Find the app in the app table
  3. Open the app's detail view by clicking the row
  4. The Version History modal displays all recorded versions

Understanding Version Status

Each version in the history shows a status badge:

Status Description
Current (blue) The version currently deployed in Intune
Archived (gray) Previous version that was deployed, available for rollback
Failed (red) Deployment or publish attempt that failed

Version Information Displayed

For each version, you'll see:

  • Version number - The semantic version (e.g., "1.2.3")
  • Recorded date - When this version was detected/published
  • Updated by - User who published this version (if available)
  • Installer size - Size of the installer package
  • Release notes - Change summary for this version
  • Package ID - WinGet package identifier (e.g., "7zip.7zip")

Rolling Back to a Previous Version

If a new app version causes issues, you can rollback to a previous version:

  1. Open the Version History modal for the app
  2. Find the version you want to rollback to (must have "Archived" status)
  3. Click the Rollback button on that version
  4. Click Confirm Rollback to proceed
  5. The portal will:
  6. Re-publish the selected version to Intune
  7. Update the app assignment with the older version
  8. Mark the rolled-back version as "Current"
  9. Archive the previously current version

Important: Rollback is only available for versions marked as "Archived". Failed deployments and the current version cannot be rolled back to.

Version History Limitations

  • Winget apps only: Version history is only tracked for apps published from the App Catalog
  • Manual Intune apps: Apps added directly to Intune (not via portal) do not have version history
  • Retention policy: By default, the portal keeps all versions indefinitely. Admins can configure retention limits in Settings

Troubleshooting Rollback Issues

Rollback button is grayed out: - Only "Archived" versions can be rolled back to - Ensure the version's installer is still available

Rollback fails: - Check Graph API permissions (DeviceManagementApps.ReadWrite.All) - Verify the installer URL is still accessible - Review API logs for detailed error messages

Version history is empty: - Version history only tracks apps published through the portal - If you synced an existing Intune app, its pre-sync versions are not tracked - Only new publishes/updates will appear in history

Pending Approvals

The Pending Approvals tab shows all requests waiting for your approval.

Viewing Requests

Each request shows: - Requestor: Name and email of the person requesting the app - App: The app being requested - Requested: When the request was submitted - Stage: Current approval stage number - Justification: Reason provided by the requestor (if any)

Approving Requests

  1. Review the request details
  2. Click Approve to advance the request
  3. The request moves to the next approval stage (or completes if this was the final stage)

Rejecting Requests

  1. Click Reject
  2. Enter a reason for rejection (required)
  3. The requestor is notified of the rejection with your reason

User Experience

Browsing Apps

The portal provides a Microsoft Store-style browsing experience:

Home Page: - Hero section featuring a prominently displayed app - Featured apps carousel with navigation controls - Category sections showing apps grouped by category - Quick links to Browse Apps and My Requests - Platform badges (Windows, iOS, Android, macOS, Web) on app cards - "New" badges on apps added within the last 14 days

Browse Apps Page: - Search apps by name, publisher, or description - Filter apps by category using the dropdown - Filter apps by platform (Windows, iOS, Android, etc.) - Featured apps section at the top - Apps organized by category with platform badges

Visual Indicators: - Platform badges - Show the app's target platform with icons (🪟 Windows, 🍎 iOS, 🤖 Android, 🍏 macOS, 🌐 Web) - "New" badge - Green badge on apps added within the last 14 days - "Featured" badge - Gold badge on featured apps - Price indicator - Shows cost or "Free" label

App Detail Page: When users click on any app card, they see a detailed view including: - Large hero banner with app icon and blurred background - App name, publisher, and category badges - "Featured" badge if applicable - Get button to request the app - Price or "Free" indicator - Full description - App information (Publisher, Version, Category, Platform, Approval status)

How Users Request Apps

Users can request apps in two ways:

Quick Request (Get button): 1. Click the Get button on any app card (Home, Browse Apps, or App Detail page) 2. The request modal opens directly 3. If Device assignment, select the target device 4. Enter optional justification 5. Click Submit Request

From App Detail Page: 1. Click on an app card to open the App Detail page 2. Review the app description and information 3. Click the Get button 4. Complete the request form and submit

Request Status Flow

Status Description
Pending Request is awaiting approval
Approved All approvals complete, processing assignment
Rejected Request was rejected by an approver
Processing System is adding user/device to AAD group
Completed User/device successfully added to group
Failed Error occurred during processing

My Requests

Users can view their request history by clicking My Requests in the navigation. This shows all requests they've submitted with current status.

Request New App

Users can request apps that aren't in the catalog by clicking the + Request New App button on the Browse Apps page.

How It Works

  1. User fills out the form with app name, publisher, description, and optional download URL
  2. The portal sends an email notification to all members of the Admin Group
  3. The email includes:
  4. Requestor name and email
  5. App name and publisher
  6. Business justification provided by the user
  7. Download URL (if provided)
  8. Suggestions for how to add the app (Winget catalog or manual upload)
  9. The request is logged in the audit trail

Admin Actions

When you receive a new app request email:

  1. Evaluate the request: Is this app appropriate for your organization?
  2. Find the app:
  3. Check the App Catalog in Admin Dashboard for easy publishing
  4. Search for the app in Intune if it's already available
  5. Download from the vendor if needed
  6. Add to portal:
  7. Use App Catalog to publish directly to Intune, or
  8. Manually add the app to Intune and sync
  9. Configure visibility: Make the app visible in the portal
  10. Notify the user: Reply to the email or notify the user directly

Configuration

The Request New App feature uses your existing email notification settings:

  • Admin Group: Members receive the notification emails
  • Email Settings: Uses the same Mail.Send configuration as other notifications

No additional configuration is required. If email notifications are disabled, the feature will return an error to the user.

Reports & Analytics

The Admin Dashboard includes comprehensive reporting capabilities to help you understand app request patterns and deployment status.

Accessing Reports

  1. Navigate to Admin in the navigation menu
  2. The dashboard displays summary tiles at the top
  3. Use the tabs to navigate between report views:
  4. Summary - Overview statistics with install status
  5. Trends - Visual charts showing request patterns over time
  6. By Person - Detailed request history by user
  7. Install Status - Deployment status for approved requests

Summary Dashboard

The Summary view shows key metrics as clickable tiles:

Tile Description
Total Requests Total number of app requests in the system
Pending Requests awaiting approval
Approved Requests that have been approved
Rejected Requests that were rejected
Pending Install Approved requests waiting for Intune deployment
Installing Apps currently being installed on devices
Installed Successfully deployed apps
Install Failed Apps that failed to install

The install status tiles (Pending Install, Installing, Installed, Install Failed) are color-coded for quick identification: - Pending Install (blue) - Deployment pending - Installing (orange) - Installation in progress - Installed (green) - Successfully deployed - Install Failed (red) - Deployment failed

The Trends tab provides visual analytics to help identify patterns and popular applications.

The main trends chart shows: - Requested (blue line) - Number of new requests per day - Completed (green line) - Number of completed requests per day - Visual area fills under each line for easy comparison

Use the time range dropdown to view: - Last 7 days - Last 14 days - Last 30 days - Last 90 days

Top Requested Apps

A horizontal bar chart showing the most frequently requested applications, helping you identify: - Popular apps that might benefit from auto-approval - Apps that may need better visibility or promotion - Patterns in user requests

Status Distribution

A breakdown showing the distribution of request statuses: - Total count and percentage for each status - Visual progress bars for comparison - Separate sections for request status and install status

Install Status Tracking

The portal automatically tracks the deployment status of approved requests for Intune apps.

How It Works

  1. Initial Status: When a request is approved for an Intune-managed app, the install status is set to "Pending Install"
  2. Background Polling: A background service checks Intune for deployment status every 15 minutes
  3. Status Updates: The portal updates the install status based on Intune's reported deployment state
  4. Final Status: Once installed (or failed), the status stops being polled

Install Status Values

Status Description
Not Applicable App is not tracked for install status (e.g., Winget apps)
Pending Install Request approved, waiting for Intune to begin deployment
Installing Intune is actively installing the app on the device
Installed App successfully installed and detected on the device
Install Failed Installation failed - check the error message for details
Uninstalled App was installed but has since been removed

Viewing Install Status

Admin Dashboard: 1. Go to Admin > Reports section 2. View install status counts in the summary tiles 3. Click on any status tile to filter by that status 4. Use the Install Status tab for detailed view

Install Status Tab: The dedicated Install Status tab shows: - Summary counts for each install state - List of all requests with their current install status - Last checked timestamp for each request - Error messages for failed installations

Troubleshooting Install Status

Status stuck on "Pending Install": - Verify the device is online and connected to Intune - Check that the user/device is correctly added to the target AAD group - Review Intune device sync status in the Intune admin center

Status shows "Install Failed": - Check the error message in the Install Status column - Common issues: - Disk space insufficient - App dependencies not met - User cancelled the installation - Device compliance issues blocking deployment

Status not updating: - The polling service runs every 15 minutes - Check API logs for any errors in the InstallStatusPollingService - Verify the app registration has DeviceManagementApps.Read.All permission

By Person Report

The By Person tab allows you to search for a specific user and view all their app requests:

  1. Enter a user's name or email in the search box
  2. View their complete request history
  3. See status, install status, and timestamps for each request
  4. Use the Retry button on failed requests to re-attempt group membership

Audit Trail

The Audit Trail tab provides a comprehensive log of all portal activity for compliance and security monitoring.

Accessing the Audit Trail

  1. Go to Admin > Reports section
  2. Click the Audit Trail button in the report navigation
  3. Use filters to narrow down results

Available Filters

Filter Description
Search Free-text search across user email, action, entity, and details
Action Type Filter by specific action (e.g., Request.Submitted, App.Suggested)
Entity Type Filter by entity type (e.g., Request, App, Settings)
Start Date Show events from this date onwards
End Date Show events up to this date

Audit Log Information

Each audit entry includes:

Field Description
Timestamp When the action occurred
User Email address of the user who performed the action
Action The type of action performed
Entity Type The type of object affected
Entity ID Identifier of the affected object
Details Additional context (varies by action type)
IP Address The IP address of the user

Common Actions Logged

Action Description
Request.Submitted User submitted an app request
Request.Approved Approver approved a request
Request.Rejected Approver rejected a request
Request.Completed Request was fulfilled (user added to group)
App.Suggested User submitted a new app request via Request New App form
Settings.Updated Admin changed portal settings
Apps.Synced Admin synced apps from Intune

Exporting Audit Logs

  1. Apply any desired filters
  2. Click the Export CSV button
  3. A CSV file downloads with all matching audit entries
  4. Use this for compliance reporting or external analysis

Audit Log Retention

Audit logs are stored indefinitely in the SQL database. There is no automatic purge. For organizations with high volume, consider:

  • Periodic export to long-term storage
  • Database scaling if performance is affected
  • Custom retention policies via direct database management

Best Practices

App Visibility Strategy

  1. Sync all apps to get your full Intune catalog
  2. Keep system apps hidden (dependencies, frameworks, required apps)
  3. Make user-requestable apps visible (productivity tools, optional software)
  4. Use categories from Intune to help users find apps

Approval Configuration Strategy

App Type Recommended Setting
Free productivity tools No approval required
Licensed software Manager approval
Admin/privileged tools Multi-stage with IT Security
Developer tools Manager + IT approval

Group Management

With automatic group and assignment creation, the portal handles most group management for you:

  1. Automatic Setup: When you make an app visible, the portal creates a security group and Intune assignment automatically
  2. Consistent Naming: Groups follow the pattern {GroupNamePrefix}{AppName}-{arch}-{locale}-v{version}-Required (e.g., AppStore-Microsoft Teams-x64-en-US-v1-0-0-Required). Dots in version numbers are replaced with dashes.
  3. Custom Prefix: Configure the Group Name Prefix in Settings to match your organization's naming conventions
  4. Manual Override: You can still manually set a Target Group on an app if you prefer to use an existing group

Tip: To use existing groups instead of auto-created ones, set the Target Group before making the app visible.

Email Notifications

  1. Create a dedicated shared mailbox for notifications
  2. Grant the app Mail.Send permission on that mailbox
  3. Use a recognizable From address like apprequest@company.com
  4. Include your portal URL so users can click through to view status

App Catalog & Cloud Packaging

The App Catalog tab in the Admin Dashboard allows you to browse over 9,000 apps from Microsoft's official WinGet repository (microsoft/winget-pkgs) and publish them directly to Intune as Win32 apps. Package manifests are fetched directly from GitHub (no third-party services), ensuring zero supply chain attack risk.

Browsing the App Catalog

  1. Navigate to Admin > App Catalog tab
  2. Popular packages are displayed 24 per page with pagination controls
  3. Use the search box to find specific apps (search uses "Load More" infinite scroll)
  4. Each package shows: name, publisher, version, and description
  5. Icons are loaded automatically where available

Publishing to Intune

  1. Find the app you want to publish
  2. Select architecture and locale (if available):
  3. Each package card displays available architectures (e.g., x64, x86, arm64) and locales (e.g., en-US, de-DE, fr-FR)
  4. If multiple options are available, they appear as dropdown selectors
  5. If only one option is available, it appears as a label showing what will be published
  6. Default selections: x64 for architecture, en-US for locale
  7. Click Publish to Intune button on the package card
  8. A packaging job is created with your selected architecture and locale
  9. Monitor job status in the Packaging Jobs section below the catalog

Architecture, Locale, and Version Tracking:

When apps are published from the WinGet catalog: - The selected architecture, locale, and version are stored in the packaging job - When the app is synced from Intune, it automatically inherits these values - Deployment groups are named to include all three: AppStore-AppName-x64-en-US-v25-10-186-0-Required - Dots in version numbers are replaced with dashes (e.g., 25.10.186.0 becomes v25-10-186-0) - This helps identify which variant and version of multi-architecture apps is deployed, and prevents duplicate deployments of the same version

Packaging Jobs

The Packaging Jobs section shows all queued and completed packaging operations:

Status Description
Pending Job is queued, waiting for processing
Downloading Downloading the installer from WinGet manifest URL
Packaging Wrapping in PSADT v4 and creating .intunewin package
Uploading Uploading package to Intune via Graph API
Creating Creating Win32LobApp in Intune
Completed App successfully created in Intune
Failed Error occurred - click Retry to requeue

Packaging Architecture

The packaging process runs in-process on the App Service — no separate containers, agents, or functions needed:

  1. Queue Message: When you click "Publish to Intune", a job is added to Azure Storage Queue
  2. Background Service: The in-process PackagingQueueService picks up the job
  3. Download: Installer is downloaded from the URL in the WinGet manifest
  4. Wrapping (PSADT mode only): Installer is wrapped in PSAppDeployToolkit v4 for standardized deployment
  5. Package Creation: .intunewin package is created using the cross-platform SvRooij.ContentPrep library
  6. Intune Upload: The package is uploaded and a Win32LobApp is created via Graph API

Packaging Methods: Raw vs PSADT

When publishing an app from the App Catalog, you can choose between two packaging methods using the dropdown on each package card:

Method Description
Raw (default) Packages the installer directly. The installer executable is the entry point — Intune runs it with silent switches. Simpler, smaller package size.
PSADT Wraps the installer in PSAppDeployToolkit v4. Provides standardized logging, pre/post-install hooks, and consistent exit codes across all installer types. Larger package size due to framework files.

When to use PSADT: - You need standardized deployment logging across all apps - You want consistent install/uninstall behavior regardless of installer type - You need the pre-installation and post-installation hooks (e.g., closing running applications before install)

When to use Raw: - You want the simplest, most direct installation - Package size matters (PSADT adds ~5 MB of framework files) - The app's native installer already handles silent installation well

Raw Packaging Details

In Raw mode, the installer is packaged directly into the .intunewin file. The install and uninstall commands sent to Intune depend on the installer type:

Install commands by file type:

File Type Install Command Uninstall Command
.msi msiexec /i "installer.msi" {silent switch} msiexec /x "installer.msi" {silent switch}
.exe "installer.exe" {silent switch} Registry lookup (see below)
.msix / .appx powershell.exe Add-AppxPackage -Path 'installer.msix' Registry lookup (see below)

Registry-based uninstall (for non-MSI): For EXE and other non-MSI installers, the uninstall command searches the Windows registry (HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall and the Wow6432Node equivalent) for an entry matching the app's display name. It uses the QuietUninstallString if available, otherwise appends /S /silent /quiet to the UninstallString.

PSADT Packaging Details

In PSADT mode, the installer is placed inside a PSAppDeployToolkit v4 folder structure. The PSADT framework provides a standardized wrapper around the installer with logging, error handling, and consistent exit codes.

Package structure created:

Package/
+-- Invoke-AppDeployToolkit.exe       <-- Entry point (what Intune runs)
+-- Deploy-Application.ps1            <-- Generated install/uninstall logic
+-- AppDeployToolkit/                 <-- Framework files (from PSADT v4 template)
|   +-- AppDeployToolkitMain.ps1
|   +-- AppDeployToolkitHelpers.ps1
|   +-- ...
+-- Files/
    +-- installer.exe (or .msi)       <-- Your actual installer

Intune commands (all PSADT packages use the same commands): - Install: Invoke-AppDeployToolkit.exe -DeploymentType Install -DeployMode Silent - Uninstall: Invoke-AppDeployToolkit.exe -DeploymentType Uninstall -DeployMode Silent

Generated Deploy-Application.ps1 script variables:

Variable Value
$appVendor Publisher name from the Winget manifest
$appName Package name from the Winget manifest
$appVersion (empty — version tracked via Intune metadata)
$appLang EN
$appRevision 01
$appScriptVersion 1.0.0
$appScriptAuthor AppRequestPortal

Install section — what runs during installation:

For MSI installers:

Execute-MSI -Action Install -Path "$dirFiles\installer.msi"

PSADT automatically adds /qn /norestart when running in Silent deploy mode. If a custom silent switch was provided that includes MSI properties (e.g., TRANSFORMS=..., PROPERTY=VALUE), those are passed via -AddParameters.

For EXE installers:

Execute-Process -Path "$dirFiles\installer.exe" -Parameters '{silent switch}' -WaitForMsiExec

The -WaitForMsiExec parameter ensures PSADT waits if another MSI installation is already in progress. EXE installers always get explicit silent switches since PSADT doesn't know the correct flags for each installer.

Uninstall section — what runs during uninstallation:

For MSI installers:

Execute-MSI -Action Uninstall -Path "$dirFiles\installer.msi"

For non-MSI installers, the script searches the registry for the app's uninstall string:

$regPaths = @(
    'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*',
    'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
$app = Get-ItemProperty $regPaths |
    Where-Object { $_.DisplayName -like '*AppName*' } |
    Select-Object -First 1

if ($app.QuietUninstallString) {
    Execute-Process -Path 'cmd.exe' -Parameters "/c $($app.QuietUninstallString)"
} elseif ($app.UninstallString) {
    Execute-Process -Path 'cmd.exe' -Parameters "/c $($app.UninstallString) /S /silent /quiet"
}

Repair section: Runs the same commands as the install section. PSADT supports Invoke-AppDeployToolkit.exe -DeploymentType Repair -DeployMode Silent for reinstallation.

Error handling: If the PSADT script encounters a fatal error, it exits with an error code in the 60000 range and logs the error details. PSADT's built-in logging writes to C:\Windows\Logs\Software\ on the target device.

The following PSADT error codes are mapped as "Failed" return codes in Intune:

Exit Code Description
60001 General PSADT error (catch block in Deploy-Application.ps1)
60002 Error during pre-installation phase
60003 Error during installation phase
60008 Generic non-zero exit from the wrapped installer

These are registered in the Intune Win32 app return code mappings so that PSADT failures are properly reported in Intune and reflected in the portal's install status tracking.

PSADT fallback: If PSADT wrapping fails for any reason (e.g., template download failure, extraction error), the system automatically falls back to Raw packaging. The job will still complete successfully — just without the PSADT wrapper.

PSADT template caching: The PSADT v4 template is downloaded once from the official GitHub releases and cached in Azure Blob Storage (psadt-template/PSAppDeployToolkit_Template_v4.zip). Subsequent packaging jobs reuse the cached template.

Silent Switches

Silent switches tell the installer to run without displaying any UI. The portal resolves the silent switch in this order:

  1. Winget manifest value — if the manifest specifies InstallerSwitches.Silent, that value is used
  2. Installer type default — based on the InstallerType field in the Winget manifest
  3. File extension fallback — based on the installer's file extension
  4. Last resort/S /silent

Default silent switches by installer type:

Installer Type Silent Switch Used By
MSI / WiX /qn /norestart Windows Installer packages
InnoSetup /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- Inno Setup installers
Nullsoft / NSIS /S NSIS installers
Burn /quiet /norestart WiX Burn bootstrapper bundles
EXE (generic) /S /silent Generic executables

These defaults are applied in both Raw and PSADT modes.

Detection Scripts

Every app published to Intune includes an auto-generated PowerShell detection script. Intune runs this script on target devices to determine whether the app is already installed.

Detection strategy (in order of preference):

  1. ProductCode detection (most reliable) — If the Winget manifest includes AppsAndFeaturesEntries with a ProductCode (MSI GUID), the script checks for that exact GUID in the registry uninstall paths. This is the most precise detection method.

  2. DisplayName detection (fallback) — If no ProductCode is available, the script searches the registry for an entry where DisplayName matches the app name (using wildcard matching). Publisher name is also checked if available in the manifest.

Version checking: When a version number is available from the Winget manifest (via AppsAndFeaturesEntries.DisplayVersion or the package version), the detection script compares the installed version against the required minimum version. Apps with older versions are reported as "Not Installed" so Intune will upgrade them.

Registry paths checked: - HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* - HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*

Script execution context: Detection scripts run as 64-bit PowerShell (runAs32Bit: false) without signature enforcement (enforceSignatureCheck: false). The script exits with code 0 if the app is detected, or 1 if not installed.

Intune Win32 App Configuration

When the app is created in Intune via the Graph API, the following settings are applied:

Setting Value
Applicable architectures x64, x86
Minimum OS Windows 10 1903
Install context System (runs as SYSTEM account)
Device restart behavior Based on return code

Return codes configured:

Code Type Meaning
0 Success Installation completed successfully
1707 Success Installation completed successfully (MSI)
3010 Soft reboot Installation succeeded, reboot recommended
1641 Hard reboot Installation succeeded, reboot initiated
1618 Retry Another installation is in progress, retry later

App icon: If available, the app icon is fetched automatically (via Google S2 Favicon API or GitHub publisher avatar) and included as a PNG or JPEG in the Intune app metadata.

Setting Up Packaging

Packaging works out of the box with the default deployment. No additional setup is required beyond:

  1. Azure Storage Account (deployed by default via Bicep template)
  2. Graph API permissions for Intune app management (see Prerequisites)
  3. Verify connectivity:
  4. Go to Admin > App Catalog
  5. Try publishing a test app (e.g., "7-Zip")
  6. Check Packaging Jobs for status

The PSADT v4 template is automatically downloaded from the official GitHub repository on first use and cached in Azure Blob Storage.

Manifest Integrity Verification

By default, the packaging pipeline trusts WinGet manifests fetched from raw.githubusercontent.com. Each manifest declares a SHA256 for its installer, and the pipeline verifies the downloaded installer matches before publishing to Intune. That defends against a tampered installer at the publisher's download server, but it does not defend against a tampered manifest on the GitHub fetch path.

To close that gap, enable Settings → "Verify manifest integrity against Microsoft's signed index".

When the setting is enabled:

  1. Before packaging any WinGet-sourced app, the portal downloads Microsoft's signed community index (source2.msix, ~10 MB) from https://cdn.winget.microsoft.com/cache/source2.msix.
  2. The portal extracts the SQLite database embedded in that MSIX and looks up the package by its identifier.
  3. If the package is not present in the index, the packaging job fails immediately with an explicit "Manifest integrity check failed" error. There is no silent fallback.
  4. The downloaded MSIX and extracted SQLite are cached for 12 hours to avoid re-downloading the index on every packaging job.

When to enable this: Any environment that wants the same manifest-trust posture as the WinGet client itself. The cost is a one-time ~10 MB download every 12 hours and a brief extra step on the first packaging job after a cache refresh.

When to leave it off: If you've already implemented your own integrity controls (e.g. a hardened internal mirror of the WinGet repo with its own signing pipeline) and prefer to rely on those.

Failure mode: If verification fails for a specific package, only that packaging job fails — other jobs continue normally. To temporarily bypass verification (for example, to package a package that is genuinely missing from the index due to an upstream removal), an admin can disable the setting from the Settings page and retry. Re-enable it afterward.

For the full security chain and v2 roadmap (per-version manifest hash comparison, MSIX signature validation), see SECURITY.md → Package Verification.

App Updates

The App Updates tab in the Admin Dashboard shows all apps that have been published from WinGet and are being tracked for version updates.

Tracked Apps Table:

Column Description
App App name and publisher
WinGet Package ID The WinGet identifier (e.g., Microsoft.VisualStudioCode)
Published Version Version currently in your portal/Intune
Latest Version Latest version available in the WinGet repository
Status Steady state for this app — Update Available, Up to Date, Unknown (sticky, when the last deploy attempt failed), or Check failed (sticky, when the most recent WinGet update lookup couldn't resolve a version). Unknown is intentionally non-alarming — when packaging or assignment fails, we genuinely don't know what state Intune is in until you investigate via the activity bell or the Packaging Jobs tab. Transient deploy progress (Queued, Packaging, Assigning, etc.) is surfaced in the activity bell at top-right of the admin pages, not in this column.
Ring Template Name of the ring template configured for this app, or "—" when the app uses custom rings or ringless mode (per-app settings live in the Update Ring Configuration side panel)
Last Checked When the version was last compared. A small red dot is shown when the most recent check failed (e.g., the WinGet package ID could not be resolved)
Actions Deploy Update or Dismiss (only shown when update is available). Deploy Update opens a confirmation wizard showing exactly what will be deployed (app, version, ring mode, target, ring breakdown, auto-deploy setting) before you commit.

Select any row in the table to open a per-app detail view where you can configure ring deployment, set the auto-deploy override, and run an immediate update check (Check Now) just for that app — useful when you want to confirm a single app's status without waiting for the next scheduled run.

Automatic Tracking: - Apps published from the WinGet catalog are automatically tracked for updates - The SourceWingetPackageId is backfilled automatically by the background service (no manual Intune sync required) - Update checks run on a configurable schedule (default: every hour when enabled) - The "Last Checked" date now stamps on every attempt — success or failure — so a stale date in the UI tells you "this app's lookup has been failing", not "the service is broken". The failure reason is shown on the per-app detail view under Last Check Result.

Actions: - Check for Updates: Manually trigger an update check for all tracked apps - Check Now (per-app, on the detail view): Run an update check for a single app without waiting for the schedule - Deploy Update: Opens a confirmation wizard (v1.24.0+) showing the deployment summary — app, version transition, ring mode (template/custom rings/ringless), ring breakdown or ringless target+filter, and the per-app auto-deploy override. Once you select Deploy in the wizard, a packaging job is queued that downloads the new version from WinGet, wraps it in PSADT, archives the .intunewin to blob storage for rollback, creates a new Install Win32 app in Intune (advancing the portal's version pointer) and a paired Update Win32 app with a requirement script that targets only devices already running the app. Watch the activity bell at top-right for in-flight progress. - Dismiss: Hides the update notification for that app

Activity Bell (v1.24.0+):

The bell icon at the top-right of every admin page is an Intune-style task tracker. The badge shows the count of in-flight deploys plus any sticky-failed entries; click the bell to open a drawer listing recent activity with each entry's current state, age, and any error or pause message. Adaptive polling: 15 seconds while at least one task is in-flight, 60 seconds otherwise to keep the badge accurate; stops entirely when nothing's happening and the drawer is closed (so you're not burning API calls just to show a zero badge). Use this when you need to know what's happening right now across all your deploys; use the App Updates Status column when you need to know what state each app is in; use the Activity tab (below) when you need the full historical timeline.

Dismissing sticky failures (v1.27.0+):

Each terminal entry in the bell drawer (Up-to-Date, Packaging Failed, Assignment Failed) has a × dismiss button. Dismissing removes the entry from the drawer's default view and from the Activity Log tab's default view. Active entries — Queued, Packaging, Assigning, Paused — can't be dismissed; they're still moving and would just reappear on the next poll. A new failure for the same app is a distinct row, so a re-failure shows up regardless of whether you dismissed the prior one. Dismissals persist per-browser via localStorage. To restore everything you've dismissed, open the Activity tab and click Restore dismissed.

Activity tab (v1.27.0+):

Full unified timeline of packaging jobs and update deployments — the same data the bell drawer surfaces, but with no terminal-entry cap. Use this when you need to answer "what happened last week" or "did this app's last three deploys all fail?" — questions the 8-entry drawer can't span.

The filter bar above the activity table:

  • State — All / Active (in flight) / Failed / Up-to-Date / Paused
  • Time — Last 24 hours / 7 days / 30 days / 90 days / All time (default 30 days)
  • Search — free-text match against app name and version
  • Show dismissed — toggle to include entries you've dismissed in the bell drawer

Filters compose. The table paginates at 25 rows per page so a long history doesn't bog the page down. Each row has its own Dismiss button mirroring the bell drawer's behaviour, plus the standard state badge, started/finished timestamps, and the deploy's error or pause message.

The Run cleanup button on this tab runs both retention sweeps in one click:

  • Packaging jobs older than 30 days (keeping the 100 most-recent)
  • Update deployments older than 90 days (keeping the 100 most-recent)

In-flight and Paused work is never deleted regardless of age, and the most-recent N rows are always preserved regardless of age. Cleanup is manual — there is no scheduled background sweep, so retention happens on whatever cadence admins choose.

The bell drawer's footer link View all activity → deep-links straight here (/admin?tab=activity).

Recovery for stuck or orphaned deploys (v1.24.0+):

If a deploy gets stuck (e.g., App Service restart killed the worker mid-packaging) or completes packaging but the Update app handler doesn't advance the deployment, the recovery action is reachable from either side of the same orphaned state:

  • Packaging Jobs table surfaces Cancel and Cleanup for in-flight stuck jobs and Cleanup orphaned deploy for completed jobs whose linked deployment is still on Packaging.
  • Update Deployments table (v1.26.0+) surfaces a parallel Cancel and Cleanup for deployments stuck on Packaging.

Both routes call the same cancel-and-cleanup endpoint: one click marks the packaging job Failed for audit, marks the linked deployment Failed, and deletes the per-job blob folder to free storage. The Cleanup actions are time-gated to deployments that have been stuck for more than 10 minutes — brand-new deployments legitimately sit at Packaging for a few minutes while the Update-app handler runs, so the button is hidden until the threshold is exceeded. Re-trigger the deploy from App Updates → Deploy Update when ready — the new attempt starts clean.

Update Ring Templates

Ring templates define a staged deployment strategy for app updates. Instead of deploying an update to all devices at once, rings let you roll out to a pilot group first, wait a configurable number of days, then expand to broader groups.

Managing Templates:

In Admin > Settings, scroll to the Update Ring Templates section:

  • Click Create Template to define a new ring template
  • Each template has a name and one or more rings (up to 10)
  • Each ring has a name (e.g., "IT Pilot"), a delay in days, and one or more Entra ID security groups
  • Each ring has its own deployment settings: available/deadline timing, install behavior, restart settings, notifications, and delivery optimization
  • Click Show Deployment Settings on any ring to configure available time (days + time of day), deadline time, restart grace period, snooze settings, and more
  • Ring 1 typically has a 0-day delay (deploys immediately); subsequent rings deploy after their configured delay
  • Set one template as the default to auto-assign it to new apps
  • Click Import from Autopatch to discover Windows Autopatch ring groups from your Entra ID and pre-populate rings with those groups

Example Configuration:

Ring Name Delay Groups
1 IT Pilot 0 days IT-Pilot-Devices
2 Early Adopters 3 days Early-Adopters
3 Production 7 days All-Managed-Devices

This means Ring 1 deploys immediately, Ring 2 deploys 3 days later, and Ring 3 deploys 7 days after Ring 2 — a total rollout of 10 days.

Per-App Configuration:

For apps published from the Winget catalog, select the app's row on the App Updates tab to open its detail view. The detail view includes an Update Rings section with three deployment styles:

  • Ringless — updates deploy immediately to a single Intune assignment with no staged rollout. Pick All Devices or All Users as the target (default: All Devices), and optionally apply an Intune assignment filter to narrow the audience (e.g. limit by OS version or department). Ringless still creates the same two-app Install/Update pair as ringed mode (so rollback, install/update telemetry, and the lifecycle Status column work identically) — it just collapses the rollout to a single ring targeting the chosen built-in audience.
  • Use a template — apply a reusable ring template defined under Update Ring Templates. If a default template is set, it is preselected.
  • Custom rings — define rings specific to this one app. Same per-ring controls as a template (groups, availability/deadline timing, install behavior, restart settings, end-user notifications, delivery optimization, assignment filter), scoped to a single app. Use this when no global template fits — for example when this app needs a different pilot group, a different rollout pace, or a specific assignment filter.

When you select Custom rings, choose Edit custom rings to open the ring editor. Edits in the editor are held in the side panel until you select Save — switching between deployment styles before saving doesn't lose your in-progress custom rings. Ringless target/filter choices are likewise preserved when you flip to a ringed mode and back, so admins can experiment without losing prior settings.

The detail view also has an Auto-Deploy Updates section to set the per-app override (use the global default, always auto-deploy, or never auto-deploy). As of v1.23.0 auto-deploy works for ringless apps too — the only safety check is that the Update Ring Configuration side panel has been opened at least once for the app (so the admin has explicitly picked ringed or ringless mode rather than leaving it unconfigured).

Note (v1.20.0): The Update Rings and Auto-Deploy controls used to live on the App Management tab's app detail view. They have moved to the App Updates tab because not every app under App Management is tracked for updates — only apps published from the WinGet catalog are.

Ring-Based Deployments

When you click Deploy Update for an app with ring-based updates enabled, the system:

  1. Creates a packaging job for the new version (same as non-ringed updates)
  2. When packaging completes, creates a new "Update" Win32 app in Intune
  3. Activates Ring 1 immediately — creates Required assignments for Ring 1's groups
  4. Schedules subsequent rings based on their configured delays
  5. A background service checks every 15 minutes for rings that are ready to activate
  6. When each ring's delay expires, its groups receive the Required assignment

Deployment Dashboard:

The App Updates tab shows active and recent deployments below the updates table:

  • Ring progress indicator — colored circles show which ring is active
  • Click a deployment row to expand and see detailed ring status, schedule dates, and group assignments
  • Pause — stops ring progression (active ring stays deployed, next ring is held)
  • Resume — restarts ring progression after a pause
  • Advance — manually skip the delay for the next ring (useful for accelerating after pilot validation)
  • Halt rollout — removes active ring assignments and marks the deployment rolled back. Devices that already updated keep the new version; future rings are stopped. (Renamed from Rollback in v1.26.0 to disambiguate from the App-level rollback that swaps the Install app back to the prior version on all devices.)
  • Cancel — removes all assignments and marks the deployment as cancelled
  • Cancel and Cleanup — for deployments stuck on Packaging for more than 10 minutes. Marks the deployment Failed, marks the linked packaging job Failed, and deletes the blob folder for that job in one atomic action. Mirrors the Cancel and Cleanup button on the Packaging Jobs table.

Two-App Model:

When you deploy an update — ringed or ringless (v1.23.0+) — the system creates two separate Win32 apps in Intune:

  1. Install app (user-targeted) -- immediately updated to the new version so new installs always get the latest. Existing assignments are preserved.
  2. Update app -- a separate Win32 app with a requirement script that only installs on devices that already have the app. Devices without the app see it as "Not Applicable." Assignments are created on this app:
  3. In ringed mode, one Required assignment per group per ring, activated as the rollout progresses.
  4. In ringless mode, a single Required assignment to All Devices or All Users (the admin's choice in the Update Ring Configuration side panel), with an optional Intune assignment filter. Created and activated immediately at deploy time — there's only one ring to roll out.

This separation ensures: - New device enrollments always get the latest version (no vulnerability window) - Updates to existing devices are controlled separately from new installs (and, in ringed mode, gated through rings with health checks) - User-targeted and device-targeted assignments don't conflict

Per-Ring Assignment Settings:

When a ring activates, the per-ring deployment settings configured on the template are applied to the Intune assignment. Each ring's assignment includes:

  • Available time -- computed from the ring activation time plus the ring's "Available after days" + "Available at time" (or "as soon as possible" if not configured)
  • Deadline time -- computed the same way for the install deadline (or none if not configured)
  • Time zone -- assignment uses device local time when "Use device time zone" is enabled, otherwise UTC
  • End user notifications -- Show all, Show reboot only, or Hide all
  • Delivery optimization priority -- Foreground or Not configured
  • Restart settings -- grace period, countdown, and snooze duration (omitted when restart behavior is "Suppress")
  • Assignment filter -- optional Intune filter (Include or Exclude) scoping the ring to a subset of devices

Settings are read from the deployment-time snapshot on the ring, so changes to the template after a deployment starts do not affect rings already in flight.

Per-Ring Assignment Filters:

Each ring in a template can target an Intune assignment filter. Open the ring's "Show Deployment Settings" panel and pick a filter from the list (Windows-platform filters from your tenant). Choose Include matching devices or Exclude matching devices, or clear the filter to assign without one. The filter is snapshotted onto the deployment ring at deploy time alongside the other ring settings.

Install App Rollback:

If a new version has installation issues, you can roll back the Install app to the previous version with one click. In the app detail view, the Version & Rollback section card (top of the Properties view, v1.26.0+) has a primary Roll back to previous version button. This swaps the Install app back to the previous version's Intune app (which still exists in Intune), so new installs receive the older working version. No re-packaging is needed.

To pick a specific historical version (rather than the immediate predecessor), select View full history… in the same section card. The version history modal lists every published version with archive status and a per-version Rollback button.

Update App Rollback:

Rolling back a ring-based deployment removes the Intune assignments from active rings so no additional devices receive the update. Devices that already installed the update retain the new version -- Intune does not uninstall it.

Signal-Based Ring Progression

Ring advancement is not just delay-based -- the system checks device install health from Intune before advancing to the next ring. This prevents a failed update from rolling out broadly.

How it works:

After a ring's delay expires, the progression service queries Intune for device install status before advancing:

Condition Action
Success rate >= threshold (default 95%) Advance to next ring
Failure rate > failure threshold (default 10%) Auto-pause deployment, notify admin
Not enough data yet (evaluation period not met) Wait, even if delay expired

Configuration (on ring templates):

Setting Default Description
Minimum success rate 95% Required success rate before advancing
Maximum failure rate 10% Failure rate that triggers auto-pause
Minimum evaluation period 24 hours Wait time after ring activation before checking status

Set the minimum success rate to 0% to advance based on delay only (disables health checks).

Auto-Deploy Updates

Updates can be deployed automatically when detected, eliminating the need to click "Deploy Update" for each app.

Global setting (Admin > Settings): - Auto-deploy updates -- when enabled, all apps with ring-based updates configured will automatically package and deploy through their rings when a new version is detected

Per-app override (App detail view): - Always auto-deploy -- this app always auto-deploys, regardless of the global setting - Never auto-deploy -- this app never auto-deploys, regardless of the global setting - Use global default -- follows the global setting

Safety requirements: - Auto-deploy only works for apps with ring-based updates enabled. Apps without rings configured will still require manual "Deploy Update" clicks, even if auto-deploy is on. This ensures all auto-deployed updates go through staged rings. - The "Deploy Update" button on the Updates tab always works for manual one-off deployments regardless of auto-deploy settings.

Winget Integration Settings

In Admin > Settings > Winget Integration:

Setting Description
WinGet Repository URL GitHub repository URL for WinGet packages. Default: https://github.com/microsoft/winget-pkgs (Microsoft's official repository). Format: https://github.com/owner/repo or owner/repo. Organizations with custom/private WinGet repositories can point to their internal GitLab/GitHub mirror. Warning: Changing this will clear the entire package cache.
GitHub Personal Access Token Recommended. Required for the "Show More Results" live search feature (GitHub's Code Search API requires authentication). Also increases API rate limits from 60/hour to 5,000/hour for faster cache syncs. Create a classic token at https://github.com/settings/tokens with public_repo scope.

Why Use a GitHub Token?

Without token (unauthenticated): - 60 API requests per hour - Initial cache sync takes 2-3 hours - May hit rate limits during heavy use - "Show More Results" live search will not work — GitHub's Code Search API requires authentication. Only cached results and exact package ID lookups (e.g., Google.Chrome) will return results.

With token (authenticated): - 5,000 API requests per hour - Initial cache sync takes 30-60 minutes - Reliable operation even with many users - Full live search — "Show More Results" queries the entire WinGet repository in real time via GitHub Code Search, finding packages that may not yet be in the local cache

Creating a GitHub Personal Access Token:

  1. Go to GitHub Settings → Personal Access Tokens → Tokens (classic)
  2. Click "Generate new token" → "Generate new token (classic)"
  3. Give it a descriptive name: "App Store for Intune WinGet Integration"
  4. Select scope: public_repo (Access public repositories)
  5. Click "Generate token"
  6. Copy the token (starts with ghp_...)
  7. Paste into Admin Settings → WinGet Integration → GitHub Personal Access Token
  8. Click Save Settings

Note: Tokens are stored securely in Azure Key Vault and never exposed in logs or UI.

Local Development Testing

For developers testing the packaging feature locally:

  1. Prerequisites:
  2. Azure Storage account configured (uses the same storage queue and blob container as production)
  3. Graph API credentials configured for Intune access

  4. Configure the API (src/AppRequestPortal.API/appsettings.json):

  5. Ensure AzureStorage:ConnectionString points to your Azure Storage account

  6. Run the services:

    # API with background packaging service (port 5000)
    cd src/AppRequestPortal.API && dotnet run
    
    # Frontend (port 3000)
    cd src/AppRequestPortal.Web && npm start
    

  7. Test: Go to Admin > App Catalog, search for an app, click "Publish to Intune". The in-process background service will pick up the job and process it.

Troubleshooting Packaging

Jobs stuck in Pending: - Verify the App Service is running and the background service started (check Application Insights logs for PackagingQueueService) - Ensure the AzureStorage:ConnectionString is configured correctly - Check that the storage queue packaging-jobs exists

Jobs failing during download: - The service downloads directly from the installer URL in the WinGet manifest - Check if the package exists in the Microsoft winget-pkgs repository - Review logs for HTTP errors or GitHub API rate limits

Jobs failing during PSADT wrapping: - PSADT wrapping has graceful fallback — if it fails, the raw installer is packaged instead - Check logs for PsadtService entries - First-time use requires downloading the PSADT template from GitHub; ensure outbound HTTPS is allowed

Jobs failing during upload: - Verify the API has Graph API permissions for Intune (DeviceManagementApps.ReadWrite.All) - Review API logs for Graph API errors (detailed error messages are logged)

Database Maintenance

The App Store for Intune uses Azure SQL Database Basic tier, which includes comprehensive automatic maintenance features. No manual database maintenance is required.

Why No Manual Maintenance is Needed

Azure SQL Database handles all maintenance tasks automatically, including:

Feature Description
Automatic Index Tuning Azure monitors query patterns and automatically creates, drops, or rebuilds indexes to optimize performance
Automatic Plan Correction Detects and fixes query plan regression issues automatically
Automatic Backups Point-in-Time Restore (PITR) with 7-day retention (Basic tier), up to 35 days on higher tiers
Geo-Redundant Storage Backups are stored redundantly across Azure regions for disaster recovery
Automatic Updates Database engine patches and security updates applied automatically with no downtime
Automatic Statistics Query statistics are automatically updated to ensure optimal query plans

What About Maintenance Scripts?

You may be familiar with on-premises SQL Server maintenance solutions like Ola Hallengren's Maintenance Solution that schedule index rebuilds, integrity checks, and backup jobs. These are not needed for Azure SQL Database because:

  1. Index Maintenance: Azure's automatic tuning handles index optimization. For a Basic tier database under 2GB, index fragmentation has minimal impact on performance.

  2. Integrity Checks (DBCC CHECKDB): Azure runs these automatically. You cannot schedule them yourself on Azure SQL Database.

  3. Backup Jobs: Azure manages all backups automatically. You cannot create your own backup jobs—instead, you use Azure's built-in Point-in-Time Restore feature.

  4. Statistics Updates: Azure automatically updates statistics as needed. Manual UPDATE STATISTICS commands are rarely necessary.

Backup and Recovery

Azure SQL Database provides built-in backup and recovery capabilities:

Tier PITR Retention Backup Storage
Basic 7 days Geo-redundant (GRS)
Standard 35 days Geo-redundant (GRS)
Premium 35 days Geo-redundant (GRS)

To restore your database:

  1. Go to Azure Portal > SQL databases > your database
  2. Click Restore in the toolbar
  3. Select a restore point (any time within retention period)
  4. Azure creates a new database with data as of that point in time

Note: Restoring creates a new database—it does not overwrite the existing one. You would rename databases after verifying the restore if needed.

When to Consider Scaling Up

The Basic tier (2GB, 5 DTUs) is suitable for the App Store for Intune's typical workload. Consider scaling up if you observe:

  • Consistent high DTU usage (>80%) in Azure metrics
  • Slow query response times
  • Timeouts during peak usage

To scale up: 1. Go to Azure Portal > SQL databases > your database 2. Click Compute + storage 3. Select a higher tier (Standard, Premium) or increase DTUs 4. Changes take effect within minutes with minimal downtime

Manual Maintenance (If Ever Needed)

In rare cases where you need to manually optimize, you can:

-- View index fragmentation (informational only)
SELECT
    OBJECT_NAME(ips.object_id) AS TableName,
    i.name AS IndexName,
    ips.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE ips.avg_fragmentation_in_percent > 30
ORDER BY ips.avg_fragmentation_in_percent DESC;

-- Rebuild a specific index if needed (usually not necessary)
ALTER INDEX [IX_AppRequests_UserId] ON [AppRequests] REBUILD;

However, for the App Store for Intune's typical data volumes (hundreds to thousands of app requests), this manual intervention is almost never necessary.

Disaster Recovery & Backups

The App Store for Intune includes built-in disaster recovery features to protect your data.

What's Automatically Protected

Component Protection Recovery
SQL Database Automated backups (7-day PITR) + geo-redundant storage Restore to any point in time
Storage Account Geo-redundant (GRS) with 6 copies across 2 regions Automatic failover available
Key Vault Secrets Soft delete (7-day recovery) Recover deleted secrets
Application Code GitHub repository + immutable release packages Redeploy from ARM template

Quick Recovery Actions

Restore deleted data (SQL):

az sql db restore --resource-group <rg> --server <server> \
  --name AppRequestPortal --dest-name AppRequestPortal-Restored \
  --time "2026-02-14T10:00:00Z"

Recover deleted Key Vault secret:

az keyvault secret recover --vault-name <vault> --name AzureAdClientSecret

Rollback to previous app version:

az webapp config appsettings set --resource-group <rg> --name <app> \
  --settings WEBSITE_RUN_FROM_PACKAGE="https://github.com/powerstacks-corp/app-store-for-intune/releases/download/v1.5.5/AppRequestPortal.zip"

High Availability (Optional)

For organizations requiring higher uptime, see the Disaster Recovery Guide for: - SQL Active Geo-Replication setup - Traffic Manager / Azure Front Door configuration - Multi-region deployment patterns

Monthly Backup Verification

We recommend testing your recovery capability monthly: 1. Restore SQL database to a point 24 hours ago (test environment) 2. Verify data integrity 3. Delete test database 4. Document actual recovery time

Troubleshooting

Apps Not Syncing

  • Verify the app registration has DeviceManagementApps.Read.All permission
  • Check that admin consent is granted
  • Look at API logs for Graph API errors

Users Not Seeing Apps

  • Verify the app's Visible status is set to Yes (open the app detail view to check)
  • Check that the user is authenticated
  • Confirm the app has synced (check Last Sync Date)

Approvals Not Working

  • Verify the approver is in the correct AAD group
  • For Linear workflows, ensure the correct person is approving
  • Check that the workflow is properly configured on the app

User Not Added to Group

  • Verify the app's Target Group is configured
  • Check the app registration has Group.ReadWrite.All permission
  • Look at API logs for Graph API errors

Email Notifications Not Sending

  • Verify Mail.Send permission has admin consent
  • Check the Send As User ID is a valid Object ID
  • Confirm Enable email notifications is toggled on in the Communications tab
  • Look at API logs for email sending errors

Assignment Filter Dropdown Is Empty

When configuring per-ring filters in Update Ring Templates or per-app Custom rings, the filter dropdown should list every assignment filter that exists in your Intune tenant. If the dropdown is empty (or only shows "No filters available") even though filters do exist in Intune:

  • Verify the API app registration has DeviceManagementConfiguration.Read.All (Application) permission. This permission was missing from setup docs prior to v1.22.1 — older deployments often lack it.
  • Confirm admin consent has been granted for that permission.
  • After adding the permission, refresh the page; results are not cached.
  • If filters still don't appear, confirm filters actually exist in Intune (Intune admin center → Tenant administrationFilters).

Request Shows "Failed" Status

When a request shows as "Failed" after approval, it means the system couldn't add the user to the target group. Common causes:

  1. User already in group - Fixed in v1.2.0; now treated as success
  2. Group doesn't exist - The target group may have been deleted
  3. Permission issue - The app lacks GroupMember.ReadWrite.All permission
  4. Invalid group ID - The group ID configured for the app is incorrect

To retry a failed request: 1. Go to Admin > Reports > By Person 2. Search for the user 3. Find the failed request and click Retry

Viewing Azure App Service Logs

When troubleshooting issues, you can view detailed logs in Azure. There are three main options:

Option 1: Log Stream (Easiest - Real-time)

View logs as they happen. This is the quickest way to see what's happening:

  1. Go to the Azure Portal
  2. Navigate to your App Service (e.g., apprequest-prod-xxxxx)
  3. In the left menu, under Monitoring, click Log stream
  4. Logs will appear in real-time as requests are made

Tip: Keep Log Stream open in one tab while reproducing the issue in another tab. Reproduce the error and watch the logs appear.

Option 2: Application Insights (Historical Queries)

View historical logs and run queries. This is useful for investigating past issues.

Setup Required: Application Insights requires a connection string and (optionally) API credentials to be configured in your Azure App Service. If you haven't set this up yet, see Step 12: Configure Application Insights in the Setup Guide. The key settings are: - APPLICATIONINSIGHTS_CONNECTION_STRING — enables telemetry collection (logs, traces, exceptions) - ApplicationInsights__AppId and ApplicationInsights__ApiKey — enables the metrics dashboard in the Admin panel

Important: You must navigate to the Application Insights resource directly (e.g., ai-apprequest-prod), NOT the "Logs" blade inside App Service. The App Service > Logs blade queries Log Analytics tables (AppServiceConsoleLogs), not Application Insights tables (traces).

Steps: 1. Go to the Azure Portal 2. Go to your Resource Group 3. Click on the Application Insights resource (e.g., ai-apprequest-prod) 4. In the left menu, click Logs 5. Close the "Queries" popup if it appears 6. Use these queries:

View recent errors (severity 3+):

traces
| where severityLevel >= 3
| order by timestamp desc
| take 100

View all logs from the last hour:

traces
| where timestamp > ago(1h)
| order by timestamp desc

Search for group operations:

traces
| where message contains "AddUserToGroup" or message contains "group"
| order by timestamp desc
| take 50

View exceptions:

exceptions
| order by timestamp desc
| take 50

If you see "No tables" or "Failed to resolve table 'traces'": - You may be in the wrong location. Make sure you're in Application Insights > Logs, not App Service > Logs - If Application Insights was just deployed, wait 5-10 minutes for data to appear - Ensure the portal is running version 1.2.0+ (which includes Application Insights integration)

Option 3: App Service Logs (Log Analytics)

If you're in the App Service > Logs blade, it uses different tables. Use these queries instead:

View console output:

AppServiceConsoleLogs
| order by TimeGenerated desc
| take 100

View HTTP logs:

AppServiceHTTPLogs
| order by TimeGenerated desc
| take 100

Check what tables are available:

search *
| summarize count() by $table

Option 4: Enable Detailed Filesystem Logging

For even more detail, enable filesystem logging:

  1. Go to your App Service in Azure Portal
  2. Under Monitoring, click App Service logs
  3. Enable Application Logging (Filesystem) and set level to Information or Verbose
  4. Enable Detailed error messages
  5. Click Save

Logs are then available in Log Stream and can be downloaded from Advanced Tools (Kudu) > Debug Console > LogFiles