Créer un message contextuel avec image à l’aide de PowerShell pour les notifications Windows 

Une communication efficace avec les utilisateurs est essentielle pour les professionnels de l’informatique, en particulier dans les environnements de fournisseurs de services gérés (MSP). Les notifications système constituent un moyen pratique d’interagir avec les utilisateurs finaux. Ce script PowerShell permet aux administrateurs informatiques d’envoyer un message contextuel avec des images optionnelles, proposant ainsi une méthode conviviale pour diffuser des mises à jour importantes, des rappels ou des alertes. Voici un aperçu détaillé de ce script, de ses fonctionnalités et de ses applications potentielles.

Contexte et importance

Les notifications système servent de ligne de communication directe entre les administrateurs informatiques et les utilisateurs, en particulier dans les environnements où les notifications par e-mail ou par chat risquent d’être manquées ou ignorées. Ce script se distingue par le fait qu’il ne se contente pas de fournir des notifications toast personnalisables, mais qu’il permet également d’inclure des images, ce qui rend les notifications visuellement attrayantes.

Les MSP et les services informatiques utilisent souvent des outils de ce type pour améliorer la communication avec les utilisateurs, qu’il s’agisse d’annoncer une maintenance programmée, d’alerter les utilisateurs en cas de problèmes critiques ou de fournir des conseils étape par étape. En tirant parti du système de notification natif de Windows 10, ce script s’intègre de manière transparente dans le flux de travail de l’utilisateur sans nécessiter l’installation de logiciels supplémentaires.

Le script :

#Requires -Version 5.1

<#
.SYNOPSIS
    Sends a toast message/notification with a hero image to the currently signed in user. Please run as the Current Logged-on User. The script defaults to not using an image if none is provided.
.DESCRIPTION
    Sends a toast message/notification with a hero image to the currently signed in user. Please run as 'Current Logged on User'.
    This defaults to no image in the Toast Message, but you can specify any png formatted image from a url.
    You can also specify the "ApplicationId" to any string.
    The default ApplicationId is your company name found in the NINJA_COMPANY_NAME environment variable, but will fallback to "NinjaOne RMM" if it happens to not be set.

    The URL image should be less than 2MB in size or less than 1MB on a metered connection.

    By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
    Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
    Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
    Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
    Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
    Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
    Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
    EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).

.EXAMPLE
    -Title "My Title Here" -Message "My Message Here"
    Sends the title "My Title Here" and message "My Message Here" as a Toast message/notification to the currently signed in user.
.EXAMPLE
    -Title "My Title Here" -Message "My Message Here" -ApplicationId "MyCompany"
    Sends the title "My Title Here" and message "My Message Here" as a Toast message/notification to the currently signed in user.
        ApplicationId: Creates a registry entry for your toasts called "MyCompany".
        PathToImageFile: Downloads a png image for the icon in the toast message/notification.
.OUTPUTS
    None
.NOTES
    If you want to change the defaults then with in the param block.
    ImagePath uses C:\Users\Public\ as that is accessible by all users.
    If you want to customize the application name to show your company name,
        then look for $ApplicationId and change the content between the double quotes.

    Minimum OS Architecture Supported: Windows 10 (IoT editions are not supported due to lack of shell)
    Release Notes: Initial Release
#>

[CmdletBinding()]
param
(
    [string]$Title,
    [string]$Message,
    [string]$ApplicationId,
    [string]$PathToImageFile
)

begin {
    [string]$ImagePath = "$($env:SystemDrive)\Users\Public\PowerShellToastHeroImage.png"

    # Set the default ApplicationId if it's not provided. Use the Company Name if available, otherwise use the default.
    $ApplicationId = if ($env:NINJA_COMPANY_NAME) { $env:NINJA_COMPANY_NAME } else { "NinjaOne RMM" }

    Write-Host "[Info] Using ApplicationId: $($ApplicationId -replace '\s+','.')"

    if ($env:title -and $env:title -notlike "null") { $Title = $env:title }
    if ($env:message -and $env:message -notlike "null") { $Message = $env:message }
    if ($env:applicationId -and $env:applicationId -notlike "null") { $ApplicationId = $env:applicationId }
    if ($env:pathToImageFile -and $env:pathToImageFile -notlike "null") { $PathToImageFile = $env:pathToImageFile }

    if ([String]::IsNullOrWhiteSpace($Title)) {
        Write-Host "[Error] A Title is required."
        exit 1
    }
    if ([String]::IsNullOrWhiteSpace($Message)) {
        Write-Host "[Error] A Message is required."
        exit 1
    }

    if ($Title.Length -gt 64) {
        Write-Host "[Warn] The Title is longer than 64 characters. The title will be truncated by the Windows API to 64 characters."
    }
    if ($Message.Length -gt 200) {
        Write-Host "[Warn] The Message is longer than 200 characters. The message might get truncated by the Windows API."
    }

    function Test-IsSystem {
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        return $id.Name -like "NT AUTHORITY*" -or $id.IsSystem
    }

    if (Test-IsSystem) {
        Write-Host "[Error] Please run this script as 'Current Logged on User'."
        Exit 1
    }

    function Set-RegKey {
        param (
            $Path,
            $Name,
            $Value,
            [ValidateSet("DWord", "QWord", "String", "ExpandedString", "Binary", "MultiString", "Unknown")]
            $PropertyType = "DWord"
        )
        if (-not $(Test-Path -Path $Path)) {
            # Check if path does not exist and create the path
            New-Item -Path $Path -Force | Out-Null
        }
        if ((Get-ItemProperty -Path $Path -Name $Name -ErrorAction Ignore)) {
            # Update property and print out what it was changed from and changed to
            $CurrentValue = (Get-ItemProperty -Path $Path -Name $Name -ErrorAction Ignore).$Name
            try {
                Set-ItemProperty -Path $Path -Name $Name -Value $Value -Force -Confirm:$false -ErrorAction Stop | Out-Null
            }
            catch {
                Write-Host "[Error] Unable to Set registry key for $Name please see below error!"
                Write-Host "$($_.Exception.Message)"
                exit 1
            }
            Write-Host "[Info] $Path\$Name changed from:"
            Write-Host " $CurrentValue to:"
            Write-Host " $($(Get-ItemProperty -Path $Path -Name $Name -ErrorAction Ignore).$Name)"
        }
        else {
            # Create property with value
            try {
                New-ItemProperty -Path $Path -Name $Name -Value $Value -PropertyType $PropertyType -Force -Confirm:$false -ErrorAction Stop | Out-Null
            }
            catch {
                Write-Host "[Error] Unable to Set registry key for $Name please see below error!"
                Write-Host "$($_.Exception.Message)"
                exit 1
            }
            Write-Host "[Info] Set $Path\$Name to:"
            Write-Host " $($(Get-ItemProperty -Path $Path -Name $Name -ErrorAction Ignore).$Name)"
        }
    }

    # Utility function for downloading files.
    function Invoke-Download {
        param(
            [Parameter()]
            [String]$URL,
            [Parameter()]
            [String]$Path,
            [Parameter()]
            [int]$Attempts = 3,
            [Parameter()]
            [Switch]$SkipSleep
        )
        Write-Host "[Info] Used $PathToImageFile for the image and saving to $ImagePath"
    
        $SupportedTLSversions = [enum]::GetValues('Net.SecurityProtocolType')
        if ( ($SupportedTLSversions -contains 'Tls13') -and ($SupportedTLSversions -contains 'Tls12') ) {
            [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol::Tls13 -bor [System.Net.SecurityProtocolType]::Tls12
        }
        elseif ( $SupportedTLSversions -contains 'Tls12' ) {
            [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
        }
        else {
            # Not everything requires TLS 1.2, but we'll try anyways.
            Write-Host "[Warn] TLS 1.2 and or TLS 1.3 isn't supported on this system. This download may fail!"
            if ($PSVersionTable.PSVersion.Major -lt 3) {
                Write-Host "[Warn] PowerShell 2 / .NET 2.0 doesn't support TLS 1.2."
            }
        }
    
        $i = 1
        While ($i -le $Attempts) {
            # Some cloud services have rate-limiting
            if (-not ($SkipSleep)) {
                $SleepTime = Get-Random -Minimum 1 -Maximum 7
                Write-Host "[Info] Waiting for $SleepTime seconds."
                Start-Sleep -Seconds $SleepTime
            }
            if ($i -ne 1) { Write-Host "" }
            Write-Host "[Info] Download Attempt $i"
    
            $PreviousProgressPreference = $ProgressPreference
            $ProgressPreference = 'SilentlyContinue'
            try {
                # Invoke-WebRequest is preferred because it supports links that redirect, e.g., https://t.ly
                # Standard options
                $WebRequestArgs = @{
                    Uri                = $URL
                    MaximumRedirection = 10
                    UseBasicParsing    = $true
                    OutFile            = $Path
                }
    
                # Download The File
                Invoke-WebRequest @WebRequestArgs
    
                $ProgressPreference = $PreviousProgressPreference
                $File = Test-Path -Path $Path -ErrorAction SilentlyContinue
            }
            catch {
                Write-Host "[Error] An error has occurred while downloading!"
                Write-Warning $_.Exception.Message
    
                if (Test-Path -Path $Path -ErrorAction SilentlyContinue) {
                    Remove-Item $Path -Force -Confirm:$false -ErrorAction SilentlyContinue
                }
    
                $File = $False
            }
    
            if ($File) {
                $i = $Attempts
            }
            else {
                Write-Host "[Error] File failed to download."
                Write-Host ""
            }
    
            $i++
        }
    
        if (-not (Test-Path $Path)) {
            Write-Host "[Error] Failed to download file!"
            exit 1
        }
        else {
            return $Path
        }
    }

    function Show-Notification {
        [CmdletBinding()]
        Param (
            [string]
            $ApplicationId,
            [string]
            $ToastTitle,
            [string]
            [Parameter(ValueFromPipeline)]
            $ToastText
        )

        # Import all the needed libraries
        [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null
        [Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null
        [Windows.System.User, Windows.System, ContentType = WindowsRuntime] > $null
        [Windows.System.UserType, Windows.System, ContentType = WindowsRuntime] > $null
        [Windows.System.UserAuthenticationStatus, Windows.System, ContentType = WindowsRuntime] > $null
        [Windows.Storage.ApplicationData, Windows.Storage, ContentType = WindowsRuntime] > $null

        # Make sure that we can use the toast manager, also checks if the service is running and responding
        try {
            $ToastNotifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("$ApplicationId")
        }
        catch {
            Write-Host "$($_.Exception.Message)"
            Write-Host "[Error] Failed to create notification."
        }

        # Create a new toast notification
        $RawXml = [xml] @"
<toast>
    <visual>
    <binding template='ToastGeneric'>
        <text id='1'>$ToastTitle</text>
        <text id='2'>$ToastText</text>
        $(if($PathToImageFile){"<image placement='hero' src='$ImagePath' />"})
    </binding>
    </visual>
</toast>
"@

        # Serialized Xml for later consumption
        $SerializedXml = New-Object Windows.Data.Xml.Dom.XmlDocument
        $SerializedXml.LoadXml($RawXml.OuterXml)

        # Setup how are toast will act, such as expiration time
        $Toast = $null
        $Toast = [Windows.UI.Notifications.ToastNotification]::new($SerializedXml)
        $Toast.Tag = "PowerShell"
        $Toast.Group = "PowerShell"
        $Toast.ExpirationTime = [DateTimeOffset]::Now.AddMinutes(1)

        # Show our message to the user
        $ToastNotifier.Show($Toast)
    }
}
process {
    Write-Host "ApplicationID: $ApplicationId"

    if (-not $(Split-Path -Path $ImagePath -Parent | Test-Path -ErrorAction SilentlyContinue)) {
        try {
            New-Item "$(Split-Path -Path $ImagePath -Parent)" -ItemType Directory -ErrorAction Stop
            Write-Host "[Info] Created folder: $(Split-Path -Path $ImagePath -Parent)"
        }
        catch {
            Write-Host "[Error] Failed to create folder: $(Split-Path -Path $ImagePath -Parent)"
            exit 1
        }
    }

    $DownloadArguments = @{
        URL  = $PathToImageFile
        Path = $ImagePath
    }

    Set-RegKey -Path "HKCU:\SOFTWARE\Classes\AppUserModelId\$($ApplicationId -replace '\s+','.')" -Name "DisplayName" -Value $ApplicationId -PropertyType String
    if ($PathToImageFile -like "http*") {
        Invoke-Download @DownloadArguments
    }
    elseif ($PathToImageFile -match "^[a-zA-Z]:\\" -and $(Test-Path -Path $PathToImageFile -ErrorAction SilentlyContinue)) {
        Write-Host "[Info] Image is a local file, copying to $ImagePath"
        try {
            Copy-Item -Path $PathToImageFile -Destination $ImagePath -Force -ErrorAction Stop
            Set-RegKey -Path "HKCU:\SOFTWARE\Classes\AppUserModelId\$($ApplicationId -replace '\s+','.')" -Name "IconUri" -Value "$ImagePath" -PropertyType String
            Write-Host "[Info] System is ready to send Toast Messages to the currently logged on user."
        }
        catch {
            Write-Host "[Error] Failed to copy image file: $PathToImageFile"
            exit 1
        }
    }
    elseif ($PathToImageFile -match "^[a-zA-Z]:\\" -and -not $(Test-Path -Path $PathToImageFile -ErrorAction SilentlyContinue)) {
        Write-Host "[Error] Image does not exist at $PathToImageFile"
        exit 1
    }
    else {
        if ($PathToImageFile) {
            Write-Host "[Warn] Provided image is not a local file or a valid URL."
        }
        Write-Host "[Info] No image will be used."
    }

    try {
        Write-Host "[Info] Attempting to send message to user..."
        $NotificationParams = @{
            ToastTitle    = $Title
            ToastText     = $Message
            ApplicationId = "$($ApplicationId -replace '\s+','.')"
        }
        Show-Notification @NotificationParams -ErrorAction Stop
        Write-Host "[Info] Message sent to user."
    }
    catch {
        Write-Host "[Error] Failed to send message to user."
        Write-Host "$($_.Exception.Message)"
        exit 1
    }
    exit 0
}
end {
    
    
    
}

 

Gagnez du temps grâce à plus de 300 scripts du Dojo NinjaOne.

Obtenir l’accès

Description détaillée du script

Ce script PowerShell est conçu pour être exécuté par l’utilisateur actuellement connecté. Voici une explication étape par étape de son déroulement :

1. Paramètres et réglages par défaut

a. Le script accepte des paramètres pour le titre, le message, l’ID de l’application et un chemin d’accès facultatif à un fichier image.

b. Si l’ID de l’application n’est pas spécifié, le script prend par défaut le nom de la société stocké dans la variable d’environnement NINJA_COMPANY_NAME ou revient à “NinjaOne RMM.”

c. Si aucune image n’est fournie, la notification s’affichera sans image.

2. Validation de l’environnement

a. Le script vérifie s’il est exécuté en tant qu’utilisateur connecté. Si ce n’est pas le cas, il se termine avec une erreur.

3. Gestion du registre

a. Le script utilise une fonction d’aide pour créer ou mettre à jour les clés de registre pour le nom d’affichage de l’application et l’icône optionnelle. Cela permet de garantir une attribution et une personnalisation correctes pour les notifications.

4. Traitement des images

a. Le script peut télécharger une image à partir d’une URL ou utiliser un fichier local. Il garantit que l’image est sauvegardée dans un dossier public pour en faciliter l’accès.

b. Si aucune image valide n’est fournie, le script se poursuit sans image.

5. Création d’une notification

a. En utilisant les API de Windows, le script construit et affiche une notification toast.

b. La notification comprend le titre et le message spécifiés et inclut l’image si elle est fournie.

6. Gestion des erreurs

a. Le script comporte une gestion efficace des erreurs, y compris des avertissements pour les configurations non prises en charge, les échecs de téléchargement et les paramètres manquants.

Cas d’utilisation potentiels

Étude de cas : Annonce de maintenance informatique

Un administrateur informatique gérant un réseau d’entreprise doit informer les utilisateurs de la maintenance prévue. À l’aide de ce script, l’administrateur envoie une notification toast avec les détails suivants :

  • Titre : “Maintenance programmée à 22 heures”
  • Message : “Veuillez sauvegarder votre travail. Les systèmes seront interrompus pendant deux heures à partir de 22 heures”
  • Image : Un logo d’entreprise hébergé sur une URL publique.

Cette approche garantit que les utilisateurs reçoivent un message clair et au logo de l’entreprise directement sur leur bureau.

Comparaisons avec d’autres méthodes

Outils de notification intégrés

Bien que Windows dispose de fonctions de notification intégrées, celles-ci nécessitent souvent une configuration complexe ou un logiciel tiers. Ce script simplifie le processus et offre davantage de possibilités de personnalisation.

Solutions logicielles personnalisées

Les logiciels de notification personnalisés peuvent offrir des fonctionnalités similaires, mais à un coût plus élevé. Ce script propose une alternative légère et rentable, conçue pour les professionnels qui maîtrisent PowerShell.

Questions fréquemment posées

  1. Puis-je utiliser ce script sur Windows 7 ou des versions antérieures ?
    Non, le script est conçu pour Windows 10 et les versions ultérieures en raison de sa dépendance aux API Windows modernes.
  2. Quels sont les formats d’image compatibles ?
    Le script prend en charge les fichiers .png. Veillez à ce que la taille du fichier soit inférieure à 2 Mo pour des performances optimales.
  3. Est-il possible d’automatiser ce script pour plusieurs utilisateurs ?
    Oui, vous pouvez intégrer ce script dans un cadre d’automatisation plus large, mais il doit être exécuté dans le contexte de chaque utilisateur connecté.

Ce qu’implique l’utilisation de ce script

Le déploiement de notifications accompagnées d’images améliore l’engagement des utilisateurs et garantit que les informations essentielles sont vues. Toutefois, les administrateurs doivent faire preuve de prudence afin d’éviter une utilisation excessive, qui pourrait entraîner une lassitude face aux notifications. De plus, ce script souligne l’importance de canaux de communication sûrs et efficaces dans les opérations informatiques.

Bonnes pratiques lors de l’utilisation de ce script

  1. Personnalisez les notifications
    Adaptez le titre et le message pour garantir la pertinence et la clarté pour l’utilisateur final.
  2. Utilisez des images compressées
    Optimisez les images pour réduire la taille des fichiers et garantir un chargement rapide, en particulier sur les connexions limitées.
  3. Testez la notification dans un environnement contrôlé
    Avant de procéder à un déploiement à grande échelle, testez le script pour vous assurer de sa compatibilité et de son efficacité.
  4. Maintenez un registre propre
    Examinez régulièrement les entrées de registre créées par le script pour éviter l’encombrement.

Conclusion

PowerShell reste un outil polyvalent pour les professionnels de l’informatique, et ce script illustre son potentiel en matière de simplification de la communication avec les utilisateurs. NinjaOne complète ce type d’outils en proposant une suite efficace de solutions de gestion informatique, permettant aux MSP et aux départements informatiques de fournir une assistance pertinente et transparente. Que vous soyez un administrateur informatique ou un MSP, l’intégration de ces scripts dans votre flux de travail peut considérablement améliorer votre efficacité opérationnelle et la satisfaction utilisateur.

Pour aller plus loin

Pour créer une équipe informatique efficace et performante, il est essentiel d'avoir une solution centralisée qui joue le rôle de nœud principal pour vos services. NinjaOne permet aux équipes informatiques de surveiller, gérer, sécuriser et prendre en charge tous les appareils, où qu'ils soient, sans avoir besoin d'une infrastructure complexe sur site. Pour en savoir plus sur NinjaOne Endpoint Management, participez à une visite guidée, ou profitez d'un essai gratuit de la plateforme NinjaOne.

Catégories :

Vous pourriez aussi aimer

×

Voir NinjaOne en action !

En soumettant ce formulaire, j'accepte la politique de confidentialité de NinjaOne.

Termes et conditions NinjaOne

En cliquant sur le bouton “J’accepte” ci-dessous, vous indiquez que vous acceptez les termes juridiques suivants ainsi que nos conditions d’utilisation:

  • Droits de propriété: NinjaOne possède et continuera de posséder tous les droits, titres et intérêts relatifs au script (y compris les droits d’auteur). NinjaOne vous accorde une licence limitée pour l’utilisation du script conformément à ces conditions légales.
  • Limitation de l’utilisation: Les scripts ne peuvent être utilisés qu’à des fins personnelles ou professionnelles internes légitimes et ne peuvent être partagés avec d’autres entités.
  • Interdiction de publication: Vous n’êtes en aucun cas autorisé à publier le script dans une bibliothèque de scripts appartenant à, ou sous le contrôle d’un autre fournisseur de logiciels.
  • Clause de non-responsabilité: Le texte est fourni “tel quel” et “tel que disponible”, sans garantie d’aucune sorte. NinjaOne ne promet ni ne garantit que le script sera exempt de défauts ou qu’il répondra à vos besoins ou attentes particulières.
  • Acceptation des risques: L’utilisation du script est sous votre propre responsabilité. Vous reconnaissez qu’il existe certains risques inhérents à l’utilisation du script, et vous comprenez et assumez chacun de ces risques.
  • Renonciation et exonération de responsabilité: Vous ne tiendrez pas NinjaOne pour responsable des conséquences négatives ou involontaires résultant de votre utilisation du script, et vous renoncez à tout droit ou recours légal ou équitable que vous pourriez avoir contre NinjaOne en rapport avec votre utilisation du script.
  • EULA: Si vous êtes un client de NinjaOne, votre utilisation du script est soumise au contrat de licence d’utilisateur final qui vous est applicable (End User License Agreement (EULA)).