WinGet: creare app Win32 evergreen con Microsoft Intune

Eccoci ad un nuovo capitolo della serie dedicata a WinGet. Dopo aver visto come distribuire e governare WinGet con Microsoft Intune e, successivamente, come utilizzare uno script PowerShell come installer type per una Win32 app, il passo successivo è quasi naturale: che cosa succede quando questi due tasselli vengono combinati in modo ragionato? Questo articolo nasce proprio da qui. Non vuole presentare una soluzione chiusa o un pacchetto valido per un solo caso, ma mettere a fuoco un pattern operativo che oggi può semplificare in modo concreto il lavoro di chi gestisce il ciclo di vita delle applicazioni in Microsoft Intune.

La combinazione tra WinGet e PowerShell come installer type per le Win32 app, infatti, consente di costruire oggetti applicativi molto più dinamici del solito, in cui la logica di installazione, aggiornamento e rimozione può essere modellata in funzione dello stato reale del software sul dispositivo. Il punto centrale, però, non è la tecnologia in sé: la tecnologia è la risposta a un’esigenza ben precisa. La domanda interessante, allora, è un’altra: come si può ridurre il lavoro ripetitivo e continuo che oggi accompagna l’application lifecycle management, soprattutto quando si parla di applicazioni che cambiano spesso, si aggiornano di frequente e non possono restare indietro troppo a lungo?

È da questa esigenza che nasce il concetto di app autoconsistente, o app evergreen, che approfondirò nel corso dell’articolo. Più avanti, infatti, mostrerò un’implementazione pratica di questo approccio, ma il valore del ragionamento non sta nell’esempio specifico; questo serve soltanto a rendere il modello più tangibile. Una volta compreso il pattern, lo stesso approccio può essere adattato a molte altre applicazioni evergreen. Per chi volesse recuperare le premesse tecniche che stanno alla base di questo articolo, vi rimando alle guide precedenti della serie che sono disponibili alle pagine ICT Power
WinGet: distribuzione e governance con Microsoft Intune e Come utilizzare uno script PowerShell come installer type per le app Win32 in Microsoft Intune.

In particolare, in questo articolo vedremo:

  • Perché tenere le applicazioni aggiornate è soprattutto un tema di sicurezza
  • Come nasce l’idea delle app evergreen e che cosa significa davvero in un tenant Intune
  • I due tasselli che rendono possibile questo approccio: WinGet e PowerShell script installer
  • Come questi elementi si combinano in un modello operativo concreto
  • Quando questo approccio ha senso, quando no, e quali prerequisiti richiede
  • Demo: un esempio pratico di implementazione
  • Il posizionamento di questo approccio rispetto a Enterprise App Catalog
  • Conclusioni

Aggiornare le applicazioni è un lavoro che non finisce mai

Chi gestisce applicazioni Windows in Microsoft Intune conosce bene questo scenario: si pacchettizza una Win32 app, si definiscono i parametri di installazione, si costruisce la detection, si testa il comportamento e si pubblica il pacchetto. Dopo poco tempo, però, arriva una nuova versione e il ciclo ricomincia: recupero del nuovo installer, validazione, creazione di un nuovo file .intunewin, eventuale supersedence, nuovi test e nuovo monitoraggio.

Questo modello è corretto e, in molti casi, resta pienamente sensato. Non c’è nulla di sbagliato nel packaging tradizionale; anzi, per software complessi, applicazioni aziendali fortemente personalizzate o scenari in cui serve un controllo molto puntuale del deployment, rimane spesso la strada più solida. Il punto è che non tutte le applicazioni hanno lo stesso profilo operativo. Esiste infatti una categoria di software per cui il costo del lifecycle tende a diventare sproporzionato rispetto al valore del packaging manuale. Basti pensare a browser, utility molto diffuse, strumenti di produttività o applicazioni che hanno release frequenti e un footprint relativamente standardizzato. In questi casi, i team IT si ritrovano spesso intrappolati in una sequenza di attività ripetitive tra rincorrere nuove versioni, riallineare la detection, aggiornare i pacchetti e mantenere in linea il catalogo applicativo. Non è un problema di competenza, ma di economia del tempo. Più il software cambia rapidamente, più aumenta la quantità di energia spesa per attività che, pur necessarie, rischiano di avere un valore operativo sempre più basso.

È proprio in questo contesto che inizia a farsi spazio una domanda che trovo, a mio avviso, molto sensata: siamo davvero obbligati a rappresentare ogni applicazione come una fotografia statica di uno specifico installer? Oppure possiamo iniziare a trattarla come un oggetto che interpreta il proprio stato e sa riallinearsi quando il software non è installato, non è aggiornato oppure deve essere rimosso? Il pattern che presento in questo articolo nasce esattamente da questa esigenza. Non prova a sostituire ogni forma di packaging, ma punta ad alleggerire quella parte del catalogo applicativo in cui la manutenzione continua produce poco valore aggiunto e molto costo operativo.

Perché mantenere le applicazioni aggiornate è soprattutto un tema di sicurezza

La fatica
operativa, da sola, sarebbe già un motivo sufficiente per cercare un approccio più efficiente. Ma qui c’è anche un secondo livello, ancora più importante… quello della sicurezza! Molte delle applicazioni che si aggiornano di frequente sono anche quelle più esposte, perché dialogano costantemente con contenuti esterni, elaborano file provenienti da terzi oppure rappresentano un vettore comune di attacco.

Negli ultimi anni questo tema si è visto molto bene soprattutto sul fronte dei browser e dei componenti correlati. Un caso ormai noto è CVE-2023-4863, che ha interessato libwebp ed è stata segnalata da Google come sfruttata attivamente. Nel 2024, Google ha comunicato che CVE-2024-7971 e CVE-2024-7965 erano già sfruttate in the wild, mentre Microsoft ha collegato CVE-2024-7971 a una campagna attribuita a Citrine Sleet. Il quadro non si è certo fermato lì, infatti anche nel 2025 Google ha indicato come sfruttata in the wild CVE-2025-2783, seguita poi da altri casi come CVE-2025-5419; anche nel 2026 la stessa dinamica è proseguita, con CVE-2026-2441 segnalata come già oggetto di exploit. In parallelo, CISA continua a mantenere il Known Exploited Vulnerabilities Catalog, che rappresenta un indicatore molto chiaro del fatto che il ritardo nell’aggiornamento, per software molto diffusi, non è mai neutro.

Ecco qualche altro esempio degli ultimi anni:

Applicazione CVE Anno Tipologia
Google Chrome CVE-2025-2783 2025 Vulnerabilità sfruttata in the wild
Mozilla Firefox CVE-2024-9680 2024 Use-after-free – code execution
WinRAR CVE-2025-8088 2025 Path traversal con possibilità di esecuzione di codice
7-Zip CVE-2025-0411 2025 Mark-of-the-Web bypass
Adobe Acrobat Reader CVE-2022-44514 2022 Use-after-free – code execution all’apertura di un file malevolo
Notepad++ CVE-2025-15556 2025 Vulnerabilità nell’updater (assenza di verifica di integrità)

Tabella 1: Esempi di vulnerabilità recenti in applicazioni molto diffuse

Chiaramente la tabella non vuole essere esaustiva né creare allarmismi di alcun tipo, ma anzi vuole evidenziare un punto molto semplice: browser, archiviatori, reader e utility di uso quotidiano continuano a essere interessati da vulnerabilità rilevanti, talvolta già sfruttate attivamente. In questo contesto, ridurre il tempo tra disponibilità dell’aggiornamento e riallineamento effettivo dei client non è solo un vantaggio operativo, ma soprattutto un obiettivo di sicurezza.

Questo non significa che un modello evergreen debba sostituire il change management o il testing. In ambienti regolati o particolarmente sensibili continueranno a esistere approvazioni, anelli di rilascio, gruppi pilota e finestre di validazione. Significa però riconoscere che, per una classe specifica di applicazioni, la capacità di ridurre il tempo che intercorre tra la disponibilità dell’aggiornamento e il riallineamento effettivo del parco dispositivi ha un valore molto solido. In altre parole, la questione non è quella di evitare il lavoro ripetitivo, ma è soprattutto accorciare la finestra di esposizione. Ed è proprio questa doppia motivazione, operativa e di sicurezza, che rende interessante un approccio basato su app evergreen.

Da questa esigenza nasce l’idea delle app evergreen

Arrivati a questo punto, il concetto chiave può essere introdotto in modo più preciso. Quando parlo di app autoconsistenti o app evergreen non intendo un nuovo tipo di app disponibile in Microsoft Intune, né una funzionalità formale del prodotto. Uso questa espressione per descrivere un modo diverso di progettare una Win32 app. Nel modello più tradizionale, la Win32 app rappresenta soprattutto un installer, un comando di esecuzione e una detection costruita attorno a quello specifico pacchetto. Nel modello che propongo qui, invece, la Win32 app viene progettata per rappresentare uno stato desiderato. L’oggetto non è più soltanto il contenitore di una versione, ma diventa il punto in cui si concentra una logica capace di verificare se il software è assente, presente ma non aggiornato, già conforme oppure da rimuovere.

Questa distinzione è più importante di quanto sembri. Significa spostare il ragionamento da un artefatto statico a una logica di governo del software. Ed è proprio questo spostamento che consente di immaginare Win32 app più aderenti al comportamento che vogliamo amministrare e meno dipendenti dalla necessità di ricostruire il pacchetto a ogni iterazione. Da qui in avanti, quindi, l’esempio pratico va letto nel modo giusto e non come la soluzione definitiva, ma come una possibile incarnazione di questo modello. Se oggi lo applichiamo a Chrome, domani possiamo declinarlo per Firefox, 7-Zip, Notepad++, PowerToys, Adobe Reader o altre applicazioni con caratteristiche simili.

Figura 1: Schema concettuale delle app evergreen – WinGet come motore applicativo, PowerShell come orchestrazione, Intune come piattaforma di governo del ciclo

I due tasselli che rendono possibile questo approccio

A questo punto, chiarita l’esigenza e definito il concetto di app evergreen, resta da capire quali siano i due elementi che rendono praticabile questo modello. Da soli, presi singolarmente, sono già molto interessanti. Ma è quando vengono combinati che acquistano un valore diverso. Da una parte c’è WinGet, che può diventare un motore applicativo capace di lavorare sullo stato corrente del software. Dall’altra c’è la possibilità di usare uno script PowerShell come installer type per una Win32 app, cioè il livello in cui quella logica può essere espressa in modo controllato, riutilizzabile e soprattutto ci consente di non dover ripacchettizzare continuamente certe applicazioni. È dall’incontro tra questi due tasselli che nasce il pattern che stiamo costruendo.

WinGet come motore di delivery applicativo

Nel primo articolo della serie avevamo già chiarito un punto fondamentale, ovvero che WinGet non va considerato come una piccola utility da prompt utile solo in laboratorio o nelle mani dell’amministratore che ama automatizzare. Se distribuito correttamente, governato e standardizzato tramite Microsoft Intune, può diventare un vero motore applicativo anche in un contesto enterprise. Questa distinzione conta molto. Se volete recuperare l’articolo, vi rimando alla pagina ICT Power
WinGet: distribuzione e governance con Microsoft Intune.

Nel modello Win32 tradizionale, ogni aggiornamento importante tende a riportare il team IT allo stesso ciclo operativo, quindi recupero dell’installer, validazione, preparazione del nuovo pacchetto, upload, aggiornamento della detection, eventuale supersedence e nuovo deploy. È un modello corretto, e in molti casi resta pienamente sensato. Ma, come detto in precedenza, non è sempre il più efficiente per software molto diffusi, relativamente standardizzati e soggetti a rilasci frequenti.

Con WinGet il punto di partenza cambia. Invece di inseguire ogni volta un installer specifico, ci si può appoggiare a un catalogo dinamico e a un motore che sa già gestire installazione, aggiornamento e rimozione di moltissime applicazioni. Questo non elimina la governance. Al contrario, la sposta su un livello più interessante: la governance non è più soltanto la capacità di caricare un pacchetto, ma la capacità di decidere come utilizzare in modo controllato un motore che lavora già sullo stato effettivo del software sul dispositivo. Ed è proprio questa capacità di interrogare lo stato applicativo che rende WinGet così utile nel modello che stiamo costruendo. Se il motore è in grado di dirci se un’app è presente, quale versione è installata e se esiste un aggiornamento disponibile, allora la logica non è più costretta a ruotare attorno a una versione hardcoded definita a monte, ma può iniziare a ragionare sullo stato effettivo del dispositivo.

PowerShell script installer type per le Win32 app

Il secondo tassello è la possibilità di usare direttamente uno script PowerShell come installer type per una Win32 app. A prima vista potrebbe sembrare solo una comodità in più, in realtà introduce un cambiamento molto più sostanziale perché la logica non è più costretta dentro una semplice command line, ma può essere descritta in modo esplicito, leggibile e riutilizzabile. Per anni, quando serviva una gestione più evoluta, si è spesso ricorsi a wrapper, batch file, script richiamati da command line e pacchetti ricostruiti anche per modifiche minime. Tutto questo funzionava, ma creava anche una certa distanza tra l’oggetto visibile in Intune e la logica realmente eseguita sul client.

Con questa feature, invece, lo script diventa il punto in cui si concentra il comportamento applicativo. Questo significa poter eseguire pre-check, verificare prerequisiti, applicare branching, interrogare WinGet, decidere se installare o aggiornare, evitare lavoro inutile, gestire il logging e restituire a Intune un esito coerente con ciò che il dispositivo ha effettivamente rilevato. Vi rimando anche qui alla pagine ICT Power dell’articolo Come utilizzare uno script PowerShell come installer type per le app Win32 in Microsoft Intune.

Ed è esattamente questo il livello di orchestrazione che mancava per trasformare una semplice Win32 app in un oggetto più vicino a una policy applicativa.

Dai due tasselli al modello operativo

Quando questi due elementi vengono combinati, il salto di qualità diventa evidente. WinGet mette a disposizione il motore che può interrogare e modificare lo stato del software; PowerShell fornisce il livello in cui esprimere la logica; Intune offre il framework gestionale fatto di assegnazioni, detection, reporting e ciclo di valutazione. La combinazione di questi tre componenti consente di progettare una Win32 app che non rappresenta più soltanto un installer statico, ma uno stato desiderato governato in modo molto più dinamico.

È qui che il concetto di app evergreen acquista significato. Nel caso di un’assegnazione Required, se la detection non rileva lo stato atteso, Intune può avviare il flusso di installazione; se il software è presente ma la logica implementata tramite PowerShell e WinGet lo considera non allineato, quello stesso flusso può essere usato per il riallineamento o l’upgrade. Se invece l’applicazione è già conforme, non viene eseguita alcuna azione. Il percorso di rimozione resta in linea con lo stesso modello, ma segue un canale distinto: un assegnamento Uninstall oppure, nei casi previsti, l’esperienza di disinstallazione resa disponibile all’utente.

Il valore del pattern sta proprio in questa continuità. Non si disegna un oggetto differente per ogni singolo evento del lifecycle, ma si costruisce un oggetto che concentra in sé la logica necessaria per interpretare il proprio stato e riallinearlo quando serve. In questo senso, la Win32 app smette di essere soltanto il contenitore di un pacchetto e diventa un punto di governo del comportamento applicativo.

Componente

Ruolo nel pattern

Valore operativo

WinGet Motore applicativo Interroga lo stato del software e gestisce installazione, aggiornamento e rimozione tramite un catalogo dinamico
PowerShell Livello di orchestrazione Implementa pre-check, branching, logging, validazioni e decisioni operative
Intune Piattaforma di governo Gestisce assegnazioni, detection, reporting e cicli di rivalutazione del deployment

Tabella 2: Logica del modello operativo

Sostanzialmente, questo modello può essere letto attraverso quattro stati molto semplici:

  • software assente: nel caso di assegnazione Required, la detection segnala che lo stato atteso non è raggiunto e Intune può avviare l’installazione
  • software presente ma non aggiornato: la logica applicativa rileva che il software non è allineato e lo stesso oggetto può eseguire il riallineamento o l’upgrade
  • software presente e conforme: non viene eseguita alcuna azione
  • software da rimuovere: la rimozione avviene tramite lo stesso modello logico, ma attraverso un percorso di uninstall esplicito (es. per assegnazione Abailable)

Quando questo approccio ha senso, e quando invece no

Come tutti i pattern architetturali, anche questo non va trattato come una risposta universale a tutti i problemi. Funziona molto bene quando l’applicazione ha un ciclo di vita frequente, un comportamento abbastanza standardizzato, una presenza consolidata nel catalogo WinGet e un rapporto costo-beneficio che rende poco attraente il packaging ripetuto. Al contrario, esistono scenari in cui continuare con una Win32 app più tradizionale resta preferibile, ad esempio quando si ha a che fare con software fortemente personalizzati, installer complessi, dipendenze locali rigide, applicazioni aziendali con configurazioni proprietarie oppure contesti in cui il change management impone una validazione puntuale di ogni singola versione.

Scenari in cui l’approccio è particolarmente interessante:

  • browser e utility molto diffuse, con aggiornamenti frequenti e forte esposizione dal punto di vista della sicurezza
  • software relativamente standardizzato, senza packaging custom complesso, e con un ciclo di vita che beneficia di un modello evergreen
  • contesti in cui si vuole ridurre il lavoro ripetitivo senza rinunciare alla governance di Intune
  • applicazioni per cui l’obiettivo principale è governare uno stato desiderato più che distribuire, ogni volta, una build confezionata manualmente

Scenari in cui è meglio restare su un modello Win32 tradizionale:

  • applicazioni aziendali o verticali con installer molto personalizzati
  • software che richiede file collaterali, trasformazioni, chiavi di licenza o logiche specifiche non adatte a un approccio guidato da catalogo
  • casi in cui la versione esatta distribuita deve essere congelata, testata e approvata puntualmente prima del rilascio
  • scenari in cui il pacchetto disponibile tramite WinGet non offre il livello di copertura, controllo o prevedibilità richiesto per quello specifico software

Demo: un esempio pratico di implementazione

Per rendere più comprensibile il ragionamento, ho preparato una demo basata su 7-Zip. Prima di continuare, però, è importante ribadirlo ancora una volta: questo non è il cuore dell’articolo, ma la sua materializzazione pratica. L’obiettivo non è suggerire che tutti debbano costruire la stessa app per 7-Zip, ma mostrare come un pattern riutilizzabile come quello proposto in questo articolo possa essere tradotto in script e in una Win32 app governata da Intune.

Nel caso specifico, l’implementazione ruota attorno a tre script che ho preparato appositamente a corredo di questo articolo: uno di detection, uno di installazione e aggiornamento e uno di disinstallazione. Quest’ultimo non è utile soltanto in scenari Available, ma anche nei percorsi di Uninstall governati da Intune. Tutti e tre condividono la stessa idea di fondo: interrogare lo stato reale del software tramite WinGet e registrare il risultato in modo leggibile ed in linea con il comportamento atteso del deployment.

Nella demo implementeremo quindi una Win32 app e la assegneremo in modalità Required a un pool di dispositivi di test. L’obiettivo sarà mostrare come, attraverso il pattern proposto, sia possibile usare WinGet e PowerShell per installare o riallineare applicazioni disponibili nel catalogo WinGet, riducendo la necessità di ricostruire ogni volta un nuovo pacchetto .intunewin e di rivedere da zero la logica di installazione a ogni aggiornamento.

Prerequisiti

Prima di costruire la nostra Win32 app
evergreen, ci sono alcuni prerequisiti da considerare. Il primo è ovvio ma fondamentale: WinGet deve essere già disponibile e funzionante sui dispositivi target. Il secondo è che nel tenant sia disponibile l’opzione PowerShell script installer per le app Win32. Il terzo è di natura metodologica: occorre avere chiaro che la logica non sarà più centrata su un installer statico, ma sullo stato desiderato dell’applicazione.

Nel caso concreto mostrato più avanti, il pattern presuppone inoltre la disponibilità di script distinti per la detection e per la logica di installazione/aggiornamento, oltre a una convenzione di logging che renda semplice capire che cosa è successo sul client. La parte di rimozione può essere gestita con uno script dedicato e diventa particolarmente utile quando si vogliono coprire anche scenari di Uninstall oppure esperienze Available con disinstallazione esposta all’utente.

Quindi, per ricapitolare:

  • WinGet già distribuito e utilizzabile in modo affidabile sui dispositivi target
  • Tenant Intune con supporto a PowerShell script installer per le app Win32
  • Scelta di un’applicazione adatta a un modello evergreen
  • Script di detection e di installazione/aggiornamento
  • Eventuale script di disinstallazione, se si vogliono coprire anche i percorsi di rimozione
  • Strategia di logging e troubleshooting definita fin dall’inizio

Nel seguito della demo mi concentrerò su un’assegnazione Required, quindi la demo si focalizzerà soprattutto sui percorsi di installazione e riallineamento. Lo script di disinstallazione non è indispensabile per mostrare questa prima esperienza, ma resta parte integrante del modello se si vuole estendere la stessa app anche a scenari Available o Uninstall. Potete comunque trovare tutti gli script utilizzati in questo articolo nella repository GitHub
EvergreenWin32Apps – Microsoft Intune.

Nota importante:
gli script riportati nella repository GitHub sopraccitata non vanno interpretati come la soluzione da adottare così com’è, ma come un supporto per comprendere meglio il pattern evergreen descritto nell’articolo. Il valore del contenuto non sta infatti nello script in sé, ma nel modello che lo script aiuta a rendere realizzabile. Ogni amministratore potrà poi costruire la propria implementazione, adattando logica, controlli e flussi al software da gestire e ai requisiti del proprio contesto operativo.

Struttura generale del repository

La struttura dell’implementazione è volutamente semplice, ma il comportamento che ne deriva è molto più interessante di una Win32 app tradizionale. La detection non si limita a cercare un file, una chiave di registro o una versione hardcoded in modo statico. Nel modello proposto, interroga WinGet per capire se il pacchetto è presente sul dispositivo e, se presente, se risulta già allineato oppure se è disponibile un aggiornamento. Se l’applicazione manca o non è allineata, traduce questo stato in una non conformità; se invece il software è già aggiornato, restituisce uno stato positivo coerente con il modello di detection di Intune. La documentazione di Microsoft chiarisce infatti che, per una detection script, l’app viene considerata rilevata quando lo script termina con exit code 0 e scrive anche un output su STDOUT.

Lo script di installazione, a sua volta, non si limita a eseguire un comando in modo cieco. Prima verifica lo stato corrente; se l’app è già conforme, termina senza fare nulla; se non è installata, avvia l’installazione; se è presente ma non allineata, esegue l’upgrade; al termine, valida di nuovo il risultato. In questo modo la stessa Win32 app può coprire sia lo scenario “software assente” sia lo scenario “software presente ma da aggiornare“, senza dover cambiare oggetto o ricostruire il pacchetto a ogni versione. WinGet supporta nativamente le operazioni di installazione, aggiornamento e rimozione, mentre Intune continua a fornire il perimetro gestionale fatto di detection, assegnazioni, reporting e ciclo di valutazione.

Lo script di disinstallazione, se previsto, segue la stessa filosofia nel verso opposto: verifica che il pacchetto esista, avvia la rimozione tramite WinGet e conferma al termine che l’applicazione non venga più rilevata. Questo è particolarmente utile non solo nei percorsi di tipo Available con uninstall esposto all’utente dal Company Portal, ma anche negli scenari governati da un intent Uninstall.

Detect-WinGetApp.ps1 per capire lo stato dell’applicazione

Nel pattern proposto, la detection è il vero perno del comportamento evergreen. La sua responsabilità non è soltanto stabilire se un software è installato, ma capire se tale software è installato ed è già allineato rispetto a ciò che WinGet considera disponibile in quel momento.

Questa distinzione cambia profondamente il ruolo della detection. Non abbiamo più una semplice regola che fotografa una versione specifica definita a priori. Abbiamo invece una logica che interroga il motore applicativo e traduce quello stato in conformità o non conformità. In termini Intune, questo permette di riutilizzare lo stesso oggetto per coprire sia il caso app assente sia il caso app presente ma da aggiornare. A livello concettuale, quindi, la detection non risponde più soltanto alla domanda “l’app c’è?“, ma a una domanda molto più utile: “l’app è nello stato che considero accettabile su questo dispositivo?“. È proprio questo passaggio che rende possibile il comportamento evergreen.

Figura 2: Estratto script Detect-WinGetApp.ps1

Install-WinGetApp.ps1: un unico flusso per installazione e aggiornamento

Il secondo script incarna al meglio il valore dell’installer type basato su PowerShell. Invece di rappresentare una singola command line, può gestire un vero flusso decisionale. Prima effettua un pre-check sullo stato corrente. Se il software è già conforme, termina senza eseguire lavoro inutile. Se l’applicazione non è presente oppure risulta non allineata, decide se invocare un’installazione iniziale oppure un upgrade e poi verifica nuovamente il risultato.

Questo è uno dei punti in cui il pattern mostra tutta la sua praticità. L’oggetto Intune non deve più conoscere a priori una versione target definita in modo statico dentro il pacchetto. È il motore applicativo, interrogato dallo script, a determinare se l’azione necessaria sia installare, aggiornare oppure non intervenire. In altre parole, Intune continua a governare il deployment, ma la decisione operativa diventa molto più aderente allo stato reale del client. Dal punto di vista di WinGet, questa distinzione è perfettamente in linea con il modello documentato, infatti install serve a portare l’applicazione sul dispositivo, mentre upgrade aggiorna quella già presente.

Figura 3: Estratto script Install-WinGetApp.ps1

La gestione dell’applicazione in uso

Nell’implementazione di esempio è presente anche una logica dedicata al caso in cui l’applicazione sia aperta ed in utilizzo dall’utente. Questo elemento va letto come un raffinamento del pattern, non come un requisito universale. In alcuni scenari, infatti, può avere senso introdurre controlli per evitare un aggiornamento aggressivo mentre il processo è in esecuzione; in altri si può preferire un comportamento più semplice e lineare.

Il messaggio importante, però, è un altro: l’installer type basato su PowerShell consente di portare questo ragionamento direttamente dentro il flusso dell’app. Non si è più obbligati a una command line rigida e opaca. Si può decidere se interrompere in modo controllato, registrare il motivo del mancato intervento, demandare il riallineamento a una successiva rivalutazione oppure adottare una logica più conservativa su determinati processi. Intune continuerà poi a governare il comportamento complessivo della Win32 app attraverso assegnazioni, detection e cicli di valutazione.

Figura 4: Get-AppRunningProcesses function in Install-WinGetApp.ps1

Uninstall-WinGetApp.ps1 per la disinstallazione

Anche la disinstallazione, in questo modello, non dovrebbe essere pensata come una semplice riga di comando. Se l’idea è governare lo stato dell’applicazione, allora lo stesso principio va applicato anche al percorso di rimozione. Lo script proposto, infatti, verifica che il pacchetto sia effettivamente presente, esegue la disinstallazione tramite WinGet e controlla al termine che l’app non venga più rilevata.

Questo dettaglio è importante perché mantiene la simmetria del modello. Installazione, aggiornamento e rimozione non sono più tre attività eterogenee trattate con logiche diverse, ma tre movimenti dello stesso ciclo di vita. In Intune questa coerenza torna utile sia quando l’app viene resa disponibile con opzione di uninstall dal Company Portal, sia quando si usa un assegnamento esplicito di tipo Uninstall.

Figura 5: Estratto script Uninstall-WinGetApp.ps1

Logging strutturato

Uno degli aspetti più utili dell’implementazione è il logging. In un approccio come questo, in cui la logica vive dentro gli script, avere tracce leggibili è fondamentale. Per questo motivo l’esempio utilizza log separati per detection, installazione e disinstallazione, archiviati in una struttura prevedibile sotto ProgramData. Il logging è ciò che permette di trasformare un pattern elegante sulla carta in una soluzione realmente supportabile in esercizio. In fase di troubleshooting diventa molto più semplice capire se il dispositivo non ha trovato WinGet, se il pacchetto era già aggiornato, se era disponibile un upgrade oppure se la rimozione non è andata a buon fine. Questo approccio, inoltre, si integra bene con il comportamento nativo di WinGet, che produce già i propri log per impostazione predefinita: i log applicativi personalizzati servono quindi ad aggiungere contesto operativo e leggibilità, non a sostituire i meccanismi diagnostici del tool.

Configurazione della Win32 app in Intune

Una volta definiti e descritti gli script, il passaggio successivo è tradurre il modello nell’oggetto Intune. Vediamo quindi, passo dopo passo, come creare la nostra Win32 app in Microsoft Intune.

Poiché, in questo approccio, il comportamento applicativo è concentrato appunto negli script, il contenuto pacchettizzato può essere ridotto al minimo. In pratica, è possibile utilizzare un payload placeholder da racchiudere nel file .intunewin, lasciando che l’azione reale venga poi governata dal PowerShell script selezionato come installer type. Questo non significa che il pacchetto Win32 scompaia, significa che la Win32 app continua comunque a richiedere un file .intunewin come contenitore formale della distribuzione, preparato con il Microsoft Win32 Content Prep Tool, ma di fatto in questo modello quel pacchetto tende a essere creato una volta sola, mentre la logica applicativa continua a evolvere negli script senza obbligare a un nuovo repackaging per ogni versione.

Prima di proseguire, ricordiamo anche i requisiti principali del supporto PowerShell script come installer type per le Win32 app:

  • dimensione massima dello script: 50 KB
  • esecuzione silent: lo script deve essere eseguito senza interazione con l’utente
  • return code gestiti correttamente: l’esito restituito dallo script determina per Intune il successo o il fallimento dell’installazione
  • stesso contesto dell’app: lo script viene eseguito nello stesso contesto dell’app installer, quindi System oppure User

Attenzione: se nel tenant è abilitato Multi-Admin Approval (MAA), gli script PowerShell non possono essere caricati durante la creazione iniziale dell’app, ma devono essere aggiunti o modificati successivamente.

Creazione placeholder tramite Win32 Content Prep Tool

Per iniziare, utilizzeremo il Win32 Content Prep Tool per convertire il nostro contenuto placeholder nel formato .intunewin, necessario per la creazione della Win32 app in Microsoft Intune. Nel nostro caso, poiché la logica applicativa risiede negli script e non nel payload pacchettizzato, il contenuto della cartella sorgente può essere ridotto al minimo, ad esempio a un semplice file fittizio. Nel nostro esempio, utilizziamo un file denominato placeholder.txt vuoto.

Figura 6: Creazione file .intunewin tramite Win32 Content Prep Tool

Una volta eseguito il tool e completata l’operazione, nella cartella di output troveremo il file .intunewin generato, pronto per l’upload in Intune. Il file placeholder originale (placeholder.txt) resterà invece nella cartella sorgente, salvo il caso in cui si scelga intenzionalmente di usare la stessa directory anche come cartella di output.

Figura 7: Output folder con file di testo placeholder + file .intunewin

Creazione Win32 app

Passiamo adesso al Microsoft Intune Admin Center e vediamo passo dopo passo come implementare il tutto. Il processo sarà lo stesso per la creazione di una qualunque Win32 app, quindi navighiamo in Apps > Windows

Figura 8: Creazione Win32 app – Parte 1

A questo punto fate click su Create e, all’apparizione della finestra sulla destra dello schermo selezionare Windows app (Win32) come App type; infine, fare click su Select.

Figura 9: Creazione Win32 app – Parte 2

Nella pagina App information procediamo a selezionare e caricare il nostro file .intunewin facendo click su Select app package file e scegliendo il pacchetto dalla finestra di Esplora file che verrà aperta; una volta completato il caricamento, confermiamo con OK

Figura 10: Creazione Win32 app – Parte 3

A questo punto configuriamo le informazioni principali della nostra app. Per lo scopo di questa demo compilerò solo i campi essenziali. Una volta terminato, facciamo clic su Next

Figura 11: Creazione Win32 app – Parte 4

Nella pagina Program configureremo la Win32 app affinché utilizzi PowerShell script come Installer type. Dopo aver selezionato questa opzione, facciamo clic su Select custom script per caricare il file di installazione. Nella sezione laterale che compare a destra completiamo quindi i dettagli richiesti. Per questa demo imposteremo su No sia Enforce script signature check sia Run script as 32-bit process on 64-bit clients. Al termine, confermiamo con OK.

Nota: durante i miei test, documentati anche nell’articolo ICT Power Come utilizzare uno script PowerShell come installer type per le app Win32 in Microsoft Intune, ho osservato che, al momento, il menu Installer type può inizialmente apparire non modificabile finché non si interagisce con il campo Install command. Trattandosi però di un comportamento non documentato ufficialmente, è preferibile considerarlo come un’anomalia temporanea della UI e non come parte della procedura standard.

Figura 12: Creazione Win32 app – Parte 5

Nello scenario di questa demo non sarà necessario soffermarsi sul percorso di disinstallazione, perché l’esempio è focalizzato su un’assegnazione Required e sul comportamento di installazione o riallineamento dell’applicazione. Tuttavia, nel caso in cui si voglia estendere lo stesso oggetto anche a un’esperienza Available, può essere utile configurare correttamente anche le impostazioni legate alla rimozione. Come già visto in precedenza per le voci dedicate all’installazione, anche per la disinstallazione vedremo il campo Uninstaller type con solamente la voce Command line non modificabile e non dandoci ancora la possibilità di selezionare altro. Analogamente a quanto fatto prima per sbloccare la situazione, procediamo a scrivere qualsiasi cosa nel campo Uninstall command e la lista del campo Uninstaller type non sarà più in grigio. Una volta interagito con quel campo, potrete selezionare la voce PowerShell script anche per eseguire la disinstallazione del software. Analogamente a quanto fatto per lo script di installazione, possiamo selezionare PowerShell script dalla lista e alla voce Uninstall script facciamo click su Select custom script. Alla destra dello schermo comparirà la sezione per caricare lo script di Uninstall e completare i dettagli richiesti. Settiamo su No il toggle button Enforce script signature check e anche Run script as 32-bit process on 64-bit clients. Quando avrete terminato, fare click su Ok.

Figura 13: Creazione Win32 app – Parte 6

Configurate le opzioni Allow available uninstallInstall behavior e Device restart behavior secondo necessità. Nel caso di questa demo metteremo rispettivamente YesSystem e No specific action. Inoltre, se nello script vi siete basati su return code diversi da quelli di default indicati nella pagina, potrete aggiungerli. Nel nostro caso, i codici di default sono sufficienti. Una volta completata questa sezione, facciamo clic su Next per proseguire.

Figura 14: Creazione Win32 app – Parte 7

Da questo punto in avanti, il wizard prosegue nel modo consueto previsto per una Win32 app. Nella pagina Requirements configureremo quindi i requisiti minimi che i dispositivi dovranno soddisfare per poter installare l’applicazione, ad esempio l’architettura supportata e il sistema operativo minimo, per poi continuare con Next.

Figura 15: Creazione Win32 app – Parte 8

Nella pagina Detection rules configureremo una detection rule basata sullo script di detection. Nel caso di una Win32 app, Intune considera l’app rilevata quando lo script di detection termina con exit code 0 e scrive anche un valore su STDOUT. Questo aspetto è importante perché spiega perché, nel caso pratico, la detection non si limita a uscire con 0, ma produce anche un output solido quando il software è installato e aggiornato. Il rovescio della medaglia è altrettanto utile, infatti quando lo script determina che l’app non è presente oppure che è installata ma non allineata, restituisce uno stato non conforme e consente a Intune di attivare il flusso di installazione o aggiornamento. Quando avremo terminato, fare click su Next.

Figura 16: Creazione Win32 app – Parte 9

Nella pagina Dependencies è possibile configurare eventuali applicazioni che devono essere installate prima di quella principale. In Microsoft Intune, una dipendenza di una Win32 app deve essere a sua volta una Win32 app, e può anche essere installata automaticamente per soddisfare la relazione definita tra le due applicazioni. Nel caso di questa demo non abbiamo dipendenze da gestire, quindi possiamo lasciare invariata la configurazione e fare clic su Next.

Figura 17: Creazione Win32 app – Parte 10

Nella pagina Supersedence è invece possibile definire se l’app corrente debba aggiornare oppure sostituire un’altra applicazione già presente in Intune. Nel nostro scenario non stiamo costruendo una relazione di questo tipo, perché il comportamento evergreen è già gestito direttamente dalla logica dell’app stessa. Di conseguenza, anche in questo caso non dovremo configurare nulla e potremo proseguire facendo clic su Next.

Figura 18: Creazione Win32 app – Parte 11

A questo punto, nella pagina Assignments, possiamo assegnare la nostra Win32 app al gruppo desiderato. Come già detto in precedenza, per far emergere davvero il comportamento evergreen, questo tipo di oggetto esprime il suo valore soprattutto con un assignment di tipo Required, perché è in quel contesto che Intune continua a governare nel tempo il riallineamento dello stato desiderato. L’Intune Management Extension verifica periodicamente la presenza di nuove o aggiornate installazioni Win32 con un check-in ogni 8 ore, indipendente dal check-in MDM. Inoltre, per le app assegnate come Required, se l’app non risulta presente nello stato atteso, Intune la ripropone entro circa 24 ore. Questo non va interpretato come un comportamento real-time, ma di un meccanismo più che sufficiente per mostrare il valore del modello. Infatti, una volta che detection e install script lavorano sullo stato reale del software, l’oggetto continua a essere rivalutato nel tempo senza obbligare l’amministratore a ricostruire un nuovo pacchetto a ogni iterazione.

Per proseguire, facciamo quindi clic su Add group nella sezione Required, cerchiamo il gruppo desiderato, selezioniamolo tramite l’apposita casella e confermiamo con Select.

Figura 19: Creazione Win32 app – Parte 12

Sempre nella pagina Assignments verifichiamo che il gruppo selezionato sia stato correttamente aggiunto alla lista dei gruppi per il deploy Required. Nel caso di questa demo non abbiamo bisogno di aggiungere filtri, modificare la disponibilità del deployment o intervenire su altre opzioni avanzate di assegnazione, quindi possiamo proseguire facendo nuovamente clic su Next. I filtri di assegnazione, quando servono, vengono applicati in questa fase e consentono di includere o escludere dinamicamente i dispositivi in base a proprietà specifiche.

Figura 20: Creazione Win32 app – Parte 13

Nella pagina Review + create controlliamo nuovamente la correttezza di tutte le informazioni configurate per la nostra Win32 app. Se tutto è corretto, procediamo con la creazione facendo clic su Create.

Figura 21: Creazione Win32 app – Parte 14

Dopo alcuni istanti, Intune completerà la creazione della Win32 app e questa comparirà correttamente nell’elenco delle applicazioni gestite, pronta per essere monitorata e amministrata. Una volta creata, l’app può poi essere verificata dal relativo pannello, che include informazioni come stato del deployment, stato per utenti e stato per dispositivi.

Figura 22: Creazione Win32 app – Parte 15

Troubleshooting e risultato finale

Terminata la configurazione in Microsoft Intune, possiamo finalmente osservare il comportamento lato client. In questa sezione vedremo che cosa succede alla prima installazione dell’applicazione e che cosa accade successivamente quando il software è già presente, ma deve essere riallineato tramite upgrade.

Prima installazione

Se è la prima volta che l’app viene installata, il nostro script di detection verifica la presenza dell’applicazione utilizzando direttamente WinGet come motore di interrogazione. Nel caso mostrato in figura, il pacchetto 7zip.7zip non viene trovato e lo script termina con exit code 1, segnalando quindi che l’app non è installata.

Figura 23: Evergreen Win32 app – Prima installazione – Parte 1

Dopo l’exit 1 restituito dalla detection, viene avviato lo script di installazione. Anche questo script esegue inizialmente un pre-check, che nel caso mostrato conferma che il pacchetto 7zip.7zip non risulta installato.

Figura 24: Evergreen Win32 app – Prima installazione – Parte 2

Poiché il pacchetto non risulta installato, lo script avvia il comando di installazione. WinGet scarica quindi il pacchetto di 7-Zip, ne verifica l’hash, esegue l’installazione e, al termine, lo script effettua un post-check per confermare che l’applicazione sia ora correttamente rilevata.

Figura 25: Evergreen Win32 app – Prima installazione – Parte 3

Una volta completata l’installazione, lo script esegue nuovamente un controllo tramite WinGet per verificare che il pacchetto risulti correttamente installato e che non siano presenti ulteriori aggiornamenti disponibili; al termine, conclude il flusso con exit code 0.

Figura 26: Evergreen Win32 app – Prima installazione – Parte 4

Il software 7-Zip risulta installato correttamente. Possiamo verificarlo anche dal lato sistema, aprendo il Pannello di controllo e seguendo il percorso Programmi > Programmi e funzionalità, dove l’applicazione compare regolarmente nell’elenco del software installati.

Figura 27: Evergreen Win32 app – Prima installazione – Parte 5

Aggiornamento delle app

Abbiamo appena visto il comportamento alla prima installazione. Vediamo adesso che cosa succede quando lo script di detection rileva la disponibilità di un nuovo aggiornamento per l’app. Per questa prova, abbiamo installato sul client una versione meno recente di 7-Zip (versione 23.01).

Figura 28: Evergreen Win32 app – Aggiornamento applicazione – Parte 1

Come possiamo notare, lo script di detection rileva che per 7-Zip è disponibile una versione più recente, in questo caso la 26.00, e termina quindi con exit code 1.

Figura 29: Evergreen Win32 app – Aggiornamento applicazione – Parte 2

A questo punto entra in gioco lo script di installazione, che esegue il proprio pre-check e conferma effettivamente la presenza di un aggiornamento disponibile per l’applicazione.

Figura 30: Evergreen Win32 app – Aggiornamento applicazione – Parte 3

Successivamente, dopo aver verificato la disponibilità dell’aggiornamento, lo script esegue anche un controllo per capire se l’applicazione è attualmente in uso. Questo passaggio serve a evitare upgrade eseguiti mentre il processo è aperto, con il rischio di errori durante l’installazione o di chiusure forzate indesiderate. Se il software risultasse in esecuzione, lo script terminerebbe con exit code 1; se invece l’applicazione non è in uso, il flusso prosegue con l’upgrade. Nel caso mostrato, come si può vedere, 7-Zip non risulta in esecuzione e l’aggiornamento viene quindi avviato regolarmente.

Figura 31: Evergreen Win32 app – Aggiornamento applicazione – Parte 4

WinGet scarica quindi il pacchetto di aggiornamento e completa l’installazione della nuova versione. Al termine, lo script esegue un ulteriore post-check per verificare che il software risulti allineato e che non siano presenti altri aggiornamenti disponibili.

Figura 32: Evergreen Win32 app – Aggiornamento applicazione – Parte 5

Una volta confermato che non esistono ulteriori aggiornamenti pendenti, l’applicazione risulta aggiornata correttamente e lo script termina con exit code 0.

Figura 33: Evergreen Win32 app – Aggiornamento applicazione – Parte 6

A valle dell’upgrade, anche lo script di detection rileva che l’applicazione è ormai conforme e termina a sua volta con exit code 0.

Figura 34: Evergreen Win32 app – Aggiornamento applicazione – Parte 7

Infine, anche il Company Portal riporterà l’applicazione come installata.

Figura 35: Evergreen Win32 app – Aggiornamento applicazione – Parte 8

Come adattare il modello ad altre applicazioni

Una volta compreso il pattern, il caso di 7-Zip mostrato nella demo diventa semplicemente un esempio. Il modello può essere adattato ad altre applicazioni evergreen, anche se con livelli di complessità diversi a seconda del software. In molti casi cambieranno soprattutto il PackageId di WinGet e alcune eccezioni specifiche legate al comportamento dell’applicazione, ai processi da considerare come app in uso o a eventuali prerequisiti particolari.

Il punto essenziale è non confondere il pattern con la sua istanza concreta. Non esiste una sola app evergreen valida per tutti gli scenari. Esiste invece una struttura di ragionamento riutilizzabile: una detection basata sullo stato del software, un unico flusso per installazione e aggiornamento, un percorso di disinstallazione solido, un logging leggibile e la traduzione dell’intero modello in un oggetto Win32 governato da Intune.

In pratica, per adattare questo approccio ad altre applicazioni, conviene sempre seguire alcuni passaggi fondamentali:

  • individuare il PackageId corretto nel catalogo WinGet
  • capire se l’applicazione si presta davvero a un lifecycle evergreen e a un modello di aggiornamento guidato dal catalogo
  • valutare se siano necessarie eccezioni o controlli specifici per il caso app in uso
  • mantenere solidità tra detection, installazione, disinstallazione e logging

Inoltre, come già evidenziato, gli script utilizzati in questo articolo e disponibili nella repository GitHub EvergreenWin32Apps – Microsoft Intune non vanno interpretati come un modello unico o definitivo, ma come un semplice esempio utile a rendere concreto il pattern descritto. Ognuno è libero di costruire la propria implementazione, adattando script e logiche al software da gestire e al proprio scenario operativo.

Differenze e convivenza con l’Enterprise App Catalog

A questo punto è naturale farsi una domanda: se in Intune esiste anche l’Enterprise App Catalog, dove si colloca l’approccio di cui stiamo parlando in questo articolo? La risposta più onesta da dare è che i due modelli non sono in contrapposizione diretta e non vanno letti come alternative assolute. Hanno finalità parzialmente diverse e possono convivere senza problemi nello stesso tenant.

L’Enterprise App Catalog, all’interno di Enterprise App Management, mette a disposizione un catalogo di applicazioni Win32 già preparate e ospitate da Microsoft. Dal punto di vista operativo è particolarmente interessante quando si vuole un’esperienza più guidata, integrata nel portale Intune e basata su un catalogo Microsoft-hosted. La documentazione Microsoft descrive inoltre un modello di aggiornamento dedicato, basato su guided update supersedence, che consente di individuare nuove versioni disponibili nel catalogo e creare una nuova app con relazione di supersedence verso quella precedente.

Il pattern mostrato in questo articolo, invece, si colloca su un piano diverso. Non prova a replicare l’Enterprise App Catalog, ma sfrutta WinGet e PowerShell script come installer type per costruire oggetti più autonomi sul fronte evergreen, cioè app Win32 capaci di reagire allo stato reale del software e di riallinearlo nel tempo. In questo senso, i due approcci possono convivere: dove serve un catalogo Microsoft-curated e un’esperienza amministrativa più guidata, Enterprise App Catalog è una scelta molto sensata; dove invece si vuole controllare in modo più esplicito la logica applicativa e costruire un comportamento guidato da stato reale tramite WinGet, questo modello può affiancarlo senza problemi.

Considerazioni finali

Il filo conduttore dell’articolo, in fondo, è molto semplice. L’application lifecycle management non è un’attività che si fa una volta e poi scompare, e questo lo sappiamo tutti. Per una parte del catalogo applicativo, soprattutto quella più esposta e più soggetta ad aggiornamenti frequenti, diventa un lavoro continuo. È proprio da questa realtà che nasce il bisogno di un modello più efficiente.

Le app evergreen, costruite combinando WinGet e PowerShell script come installer type dentro una Win32 app governata da Intune, rappresentano un modo molto interessante per rispondere a questo problema. Non sostituiscono ogni forma di packaging, non sono la risposta giusta per qualunque software, né cancellano la necessità di governance, testing o change control, ma consentono di trattare in modo più intelligente quella porzione del catalogo applicativo in cui il costo del lifecycle rischia di diventare superiore al valore del packaging tradizionale.

È questo il motivo per cui, nel leggere l’esempio pratico basato su 7-Zip mostrato nella demo di questo articolo, conviene fermarsi un passo prima della soluzione e guardare prima il pattern. Perché il valore più interessante non è lo script in sé, ma il cambio di prospettiva: passare da una Win32 app che rappresenta un installer statico a una Win32 app che governa uno stato desiderato.

Ed è proprio qui che la combinazione tra WinGet e la feature PowerShell script come installer type mostra tutto il suo potenziale.