Repeatedly, I face clients needing predefined desktop shortcuts for apps, sites, or web apps. To streamline distribution and updates, I devised a PowerShell script. It deploys desktop shortcuts via Intune, optionally with unique icons. This is encompassed in a win32 application for version control.
Table of Contents
- Preparation
- Distribution - PowerShell Script
- The detection rule
- Intune win32 package
- Installation Demo (Company Portal)
Preparation
Here you can find my template including two example links:
My solution offers the possibility of either using predefined links or maintaining them in a CSV.
You can simply store the predefined shortcuts under ".\Desktop". Make sure that if icons are stored, they only work as long as they are also available on the target system at the appropriate location.
In the CSV (link-list.csv) you only have to enter the shortcut name, the link and the icon. Place the icon in the "icon" folder.
Distribution - PowerShell Script
The entire distribution is handled by the "install.ps1" file.
In a first step I define the package name and the version. I also start a transcript of the process to have a log locally on the device.
$PackageName = "DesktopIcon_SLZ"
$Version = "1"
$Path_local = "$Env:Programfiles\MEM"
Start-Transcript -Path "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs\$PackageName-install.log" -Force
Code language: PowerShell (powershell)
In the second step, I define and create the paths or folders that I need for the links and icons.
# Paths
$DesktopTMP = "$Path_local\Data\Desktop\$PackageName"
$DesktopIcons = "$Path_local\Data\icons\$PackageName"
# Create Folders
New-Item -Path $DesktopTMP -ItemType directory -force
New-Item -Path $DesktopIcons -ItemType directory -force
New-Item -Path "C:\Users\Public\Desktop" -ItemType directory -force
Code language: PowerShell (powershell)
Third, I remove possible previous versions of the package, its shortcuts on the desktop, and icons in the local folder.
# Remove old shortcuts and icons
$OLD_Items = Get-ChildItem -Path $DesktopTMP
foreach($OLD_Item in $OLD_Items){
Remove-Item "C:\Users\Public\Desktop\$($OLD_Item.Name)" -Force
}
Remove-Item "$DesktopTMP\*" -Force
Remove-Item "$DesktopIcons\*" -Force
Code language: PowerShell (powershell)
In the fourth step I copy all predefined icons from the "Desktop" folder to the temporary local folder on the PC.
# Copy New shortcuts
Copy-Item -Path ".\Desktop\*" -Destination $DesktopTMP -Recurse
Copy-Item -Path ".\icons\*" -Destination $DesktopIcons -Recurse
Code language: PowerShell (powershell)
Then I read in the CSV and also create the defined shortcuts in the temporary desktop folder.
# shortcuts from list
$shortcuts = Import-CSV "link-list.csv"
foreach($shortcut in $shortcuts){
$WshShell = New-Object -comObject WScript.Shell
$Shortcut_file = $WshShell.CreateShortcut("$DesktopTMP\$($shortcut.name).lnk")
$Shortcut_file.TargetPath = $shortcut.link
$Shortcut_file.IconLocation = "$DesktopIcons\$($shortcut.icon)"
$Shortcut_file.Save()
}
Code language: PowerShell (powershell)
After the copying process and the creation of all shortcuts, I copy them to the public desktop of the device.
# Copy icons to public Desktop
Copy-Item -Path "$DesktopTMP\*" -Destination "C:\Users\Public\Desktop" -Recurse
Code language: PowerShell (powershell)
Finally, I create a file that acts as a detection rule and contains the version of my package. I also stop the transcript.
# Validation
New-Item -Path "$Path_local\Validation\$PackageName" -ItemType "file" -Force -Value $Version
Stop-Transcript
Code language: PowerShell (powershell)
The detection rule
The detection rule reads the validation file and its content and compares it with the version number. If everything is correct, this is reported to Intune. If you adjust the package name or the version in "install.ps1", you must also do this in "check.ps1".
$PackageName = "DesktopIcon_SLZ"
$Version = "1"
$Path_local = "$Env:Programfiles\MEM"
$ProgramVersion_current = Get-Content -Path "$Path_local\Validation\$PackageName"
if($ProgramVersion_current -eq $Version){
Write-Host "Found it!"
}
Code language: PowerShell (powershell)
Intune win32 package
With the Intune Win32 Prep Tool the package is created after the CSV and/or the desktop folder is filled:
We then upload the created "install.intunewin" file to MEM/Intune and set the appropriate parameters. (red mandatory, orange optional, but helpful if the company portal is used.)
Name | Desktop shortcuts or individually |
Description | Note on the links |
Publisher | individually |
Icon | freely selectable |
installation command | %SystemRoot%\sysnative\WindowsPowerShell\v1.0\powershell.exe -executionpolicy bypass -command .\install.ps1 |
uninstall command | %SystemRoot%\sysnative\WindowsPowerShell\v1.0\powershell.exe -executionpolicy bypass -command .\uninstall.ps1 |
Conditions | x64 and 2004 (Windows version not relevant) |
Detection rule | custom script, check.ps1 |
dependency | none |
Assignment | depending on requirements |
Would you like to automatically upload the link(s) right away?
Then I have an article for you here: win32 app deployment automated
Installation Demo (Company Portal)
This is the installation process via the company portal, with the user initiating the installation. Distribution via targeting also works. The process of using Intune to distribute a desktop shortcut with an icon is so very simple and practical. Updates are also implemented quickly.
What happens if a new shortcut is added or one removed? Will it do so on next sync?
Based on the last package configuration old icons will be removed and new added.
For this purpose, I save a copy of the package's shortcuts unter "C:\Program Files\MEM\Data\Desktop"
It is important to raise the version number for this scenario.
Can I use this to deploy multiple icons at once? For example, I'm looking to deploy, Outlook, Word, Excel and Powerpoint icons within one go so I can add this to the company portal. How would I do that?
Yes, you can do that. Just paste all those shortcuts in the "Desktop" folder in my template and deploy it like that.
Great script. But how do I include a shortcut to open in Inprivate window?
I tried to add another csv (link-list1.csv) with the following PS, but didn't worked.
$shortcuts1 = Import-CSV "link-list1.csv"
foreach($shortcut1 in $shortcuts1){
$WshShell = New-Object -comObject WScript.Shell
$Shortcut_file1 = $WshShell.CreateShortcut("$DesktopTMP\$($shortcut1.name).lnk")
$Shortcut_file1.WorkingDirectory = $shortcut1.path
$Shortcut_file1.TargetPath = $shortcut1.link
$Shortcut_file1.IconLocation = "$DesktopIcons\$($shortcut1.icon)"
$Shortcut_file1.Save()
}
Hi Sahil, you could create a custom shortcut and place it in the "Desktop" folder. Within the CSV only direct url/links are possible.
The custom URL would look like:
"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" -inprivate "https://scloud.work"
Hi Florian,
Yes, I tried that. But the link is not opening in inprivate window.
I also tried adding the custom URL in CSV, but still won't work
Hey Florian: I figured out. You have to place the incognito shortcut in the Desktop folder with the icon in icons folder and then in the CSV add the shortcut name and icon entries keeping the link field empty.
It was also creating duplicate shortcuts - .url copied from the $DesktopTMP folder and .lnk created from the link-list.csv. So I just added incognito shortcuts in the Desktop folder and other shortcuts added in the csv file.
Thank you again for this great script.
Hi Sahil, thanks for your feedback. Happy it worked for you.
Hi Sahil,
I'm looking to add a shortcut that opens in Incognito mode like you, but I can't get this to work after following your amendment - the shortcut appears on the Desktop, but the target location is 'Desktop'. I added a shortcut in the 'Desktop' folder pointing to: "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" -inprivate "https://linktomysite.com".
I then amended the csv to add a the name of the shortcut under 'name' (identically matching), the link column is blank, and the icon column has the name of the icon in the 'Icons' folder.
Not sure where I'm going wrong?
When the script runs it is creating two icons on the desktop. one that the correct shortcut and one that looks like a broken shortcut how can this be resolved ?
Do you deploy the icons via the "Desktop" Folder or the CSV?
If you don't use one of the methods delete the other.
I deployed this script as required to a device group and users seem to be getting prompted for UAC when it tries to install. Could this be due to the fact that the users I pushed it to are Local Admin on their workstations? Or is there something else that may be causing this? From my knowledge, if this is being pushed in system context then it should not prompt for anything.
Did you choose the "system context" in the win32 app in Intune?
This is mandatory, cause only admins and the system user have access to the public desktop.
Hello, tks for your work, I have a question when someone deletes the shortcut will the intune put the shortcut again?
Regards,
PauloP
No in this construct. But the shortcuts are delivered to the public desktop, where a standard user can delete any shortcuts.
I'm confused about your parameter $PackageName. If I store a file in the Desktop folder and it's called "ABC.txt", does $PackageName need to be "ABC.txt" as well? What is the $PackageName for.
The variable
$PackageName
is only used for the name of the log and the validation/detection rule.Hi, where does the uninstall.ps1 reside? Does it have to be uploaded? I see it is part of the uninstall command but how does it make its way in to the computer as uninstall.ps1 to be able to run?
When the "intunewin" file is created, all the content in that folder is zipped into that intunewin. This makes uninstall.ps1 available to Intune.
Can the icon file be jpg or png?
No, but you can convert it easily with: https://convertio.co/png-ico/
Florian, thank you for sharing this, great guide 🤝