Schritt-für-Schritt-Guide: Wie man Desktop-Verknüpfungen mit PowerShell erstellen kann

Die programmgesteuerte Erstellung von Desktop-Verknüpfungen kann IT-Experten viel Zeit und Mühe ersparen, insbesondere bei der Verwaltung von Umgebungen mit mehreren Benutzer:innen. PowerShell, eine leistungsstarke, Windows-eigene Skriptsprache, bietet die Flexibilität und Funktionalität, um diese Aufgabe effizient zu automatisieren.

In diesem Blogbeitrag wird ein umfassendes PowerShell-Skript zur Erstellung von Desktop-Verknüpfungen für ausführbare Dateien vorgestellt, wobei die Verwendung, die Funktionalität und die Vorteile für IT-Experten und Managed Service Provider (MSPs) ausführlich beschrieben werden.

Kontext

In großen IT-Umgebungen kann die Verwaltung von Benutzer-Desktops und die Gewährleistung der Einheitlichkeit aller Systeme eine Herausforderung darstellen. Desktop-Verknüpfungen sind ein einfacher, aber wesentlicher Bestandteil dieser Verwaltung, da sie einen schnellen Zugriff auf Anwendungen, Webseiten und Dateien ermöglichen.

Die manuelle Erstellung dieser Verknüpfungen für jeden Benutzer ist nicht praktikabel, insbesondere in Unternehmen mit zahlreichen Anwender:innen. Hier ist die Automatisierung mit PowerShell-Skripten von unschätzbarem Wert. Das Skript im Fokus erstellt nicht nur Verknüpfungen, sondern ermöglicht auch die Anpassung mit Parametern wie Symbolpfaden, ausführbaren Argumenten und benutzerspezifischen Einstellungen.

Das Skript zur Erstellung von Desktop-Verknüpfungen

<#
.SYNOPSIS
    This script creates a desktop shortcut for an executable with specified options. It can create a shortcut for all users (including new ones) or for existing users only.
.DESCRIPTION
    This script creates a desktop shortcut for an executable with specified options. 
    It can create a shortcut for all users (including new ones) or for existing users only.

    You can also provide a base64 string on line 79 enclosed in quotes and an icon directory, and the script will use that instead.
.EXAMPLE
    This will create a shortcut that opens www.google.com in Firefox on JohnSmith's desktop. This is not limited to just browsers; you can specify any executable you would normally be able to via the "Create Shortcut" menu.
    
    -Name "ERP App" -EXEPath "C:\Program Files\Mozilla Firefox\firefox.exe" -StartIn "C:\Program Files\Mozilla Firefox" -IconPath "C:\ProgramData\ERPapp\customicon.ico" -Arguments "https://www.google.com" -User "JohnSmith"

    Creating Shortcut at C:\Users\JohnSmith\Desktop\ERP App.lnk

.PARAMETER NAME
    The name of the shortcut, e.g., "Login Portal".

.PARAMETER ExePath
    The target field in the shortcut, excluding arguments.

.PARAMETER Arguments
    The arguments for the executable inside the shortcut.

.PARAMETER StartIn
    Some executables require that they be opened in a specific directory.

.PARAMETER Icon
    The path to an image file to use for the shortcut. You could also place the base64 string on line 79 and specify an IconDirectory with the below parameter.

.PARAMETER IconDirectory
    Path to store the .ico file to use for the shortcut.

.PARAMETER IconURL
    A link to an image file you would like to use for the shortcut. You could also place the base64 string on line 79 and specify an IconDirectory using '-IconDirectory'.

.PARAMETER AllExistingUsers
    Creates the shortcut for all existing users but not for new users, e.g., C:\Users\*\Desktop\shortcut.lnk.

.PARAMETER AllUsers
    Creates the shortcut in C:\Users\Public\Desktop.

.OUTPUTS
    None
.NOTES
    Minimum OS Architecture Supported: Windows 7, Windows Server 2008
    Release Notes: Split the script into three separate scripts, added script variable support, and improved icon support.
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).
#>

[CmdletBinding()]
param (
    [Parameter()]
    [String]$Name,
    [Parameter()]
    [String]$ExePath,
    [Parameter()]
    [String]$Arguments,
    [Parameter()]
    [String]$StartIn,
    [Parameter()]
    [String]$Icon,
    [Parameter()]
    [String]$IconDirectory,
    [Parameter()]
    [String]$IconUrl,
    [Parameter()]
    [Switch]$AllExistingUsers,
    [Parameter()]
    [String]$ExcludeUsers,
    [Parameter()]
    [Switch]$AllUsers
)

begin {
    Add-Type -AssemblyName System.Drawing

    # If the line below is replaced with $IconBase64 = 'YourBase64EncodedImageInQuotes', the script will decode it and use it for the desktop shortcut. Be sure to provide an Icon Storage Directory.
    $IconBase64 = $null

    # Replace existing parameters with Form Variables if used.
    if ($env:shortcutName -and $env:shortcutName -notlike "null") { $Name = $env:shortcutName }
    if ($env:createTheShortcutFor -and $env:createTheShortcutFor -notlike "null") { 
        if ($env:createTheShortcutFor -eq "All Users") { $AllUsers = $True }
        if ($env:createTheShortcutFor -eq "All Existing Users") { $AllExistingUsers = $True }
    }
    if ($env:exePath -and $env:exePath -notlike "null") { $ExePath = $env:exePath }
    if ($env:exeArguments -and $env:exeArguments -notlike "null") { $Arguments = $env:exeArguments }
    if ($env:exeShouldStartIn -and $env:exeShouldStartIn -notlike "null") { $StartIn = $env:exeShouldStartIn }
    if ($env:linkToIconFile -and $env:linkToIconFile -notlike "null") { $IconUrl = $env:linkToIconFile }
    if ($env:iconStorageDirectory -and $env:iconStorageDirectory -notlike "null") { $IconDirectory = $env:iconStorageDirectory }

    # Ensure a user is specified for shortcut creation.
    if (-not $AllUsers -and -not $AllExistingUsers -and -not $User) {
        Write-Host "[Error] You must specify which desktop to create the shortcut on!"
        exit 1
    }

    $invalidFileNames = '[<>:"/\\|?*\x00-\x1F]|\.$|\s$'
    if ($Name -match $invalidFileNames) {
        Write-Host '[Error] The name you specified contains one of the following invalid characters or ends with a period. <>:"/\|?*'
        exit 1
    }

    $ExitCode = 0
    
    # Icons are secondary. If no information is given, continue without them, but notify the technician.
    if (($Icon -or $IconUrl) -and -not $IconDirectory) {
        Write-Warning "An icon was provided, but no storage location was specified. Use the Icon Storage Directory parameter to specify a directory to store it. (You may want this directory to be accessible by all users.)"
        Write-Warning "Ignoring supplied icon info."
        $ExitCode = 1
        $Icon = $null
        $IconUrl = $null
    }

    if ($Icon) {
        $FileName = Split-Path $Icon -Leaf

        # Check for valid icon formats. Only support .png, .jpg, .jpeg, .ico, and .gif.
        if ($FileName -notmatch '\.bmp$' -and $FileName -notmatch '\.png$' -and $FileName -notmatch '\.jpg$' -and $FileName -notmatch '\.jpeg$' -and $FileName -notmatch '.ico$' -and $FileName -notmatch '.gif$') {
            Write-Warning "Your icon is in an invalid format. Only .png, .jpg, .jpeg, .ico, and .gif formats are supported. Switching to the default icon. You can re-run the script to replace the icon."
            $Icon = $null
        }

        if (-not (Test-Path $Icon -ErrorAction SilentlyContinue)) {
            Write-Warning "It looks like your icon is missing. Skipping for now; re-run the script with a valid path to add the icon."
            $Icon = $null
        }
    }

    # Create the directory for the icon if it doesn't exist.
    if ($IconDirectory -and -not (Test-Path $IconDirectory -ErrorAction SilentlyContinue)) {
        New-Item -ItemType Directory -Path $IconDirectory | Out-Null
    }

    # For PowerShell 2.0 and 3.0 compatibility we're going to need to create a Get-FileHash function
    if ($PSVersionTable.PSVersion.Major -lt 4) {
        function Get-FileHash {
            param (
                [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
                [string[]]$Path,
                [Parameter(Mandatory = $false)]
                [ValidateSet("SHA1", "SHA256", "SHA384", "SHA512", "MD5")]
                [string]$Algorithm = "SHA256"
            )
            $Path | ForEach-Object {
                # Only hash files that exist
                $CurrentPath = $_
                if ($(Test-Path -Path $CurrentPath -ErrorAction SilentlyContinue)) {
                
                    $HashAlgorithm = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm)
                    $Hash = [System.BitConverter]::ToString($hashAlgorithm.ComputeHash([System.IO.File]::ReadAllBytes($CurrentPath)))
                    @{
                        Algorithm = $Algorithm
                        Path      = $Path
                        Hash      = $Hash.Replace('-', '')
                    }
                }
            }
        }
    }

    # Convert a Base64 string to a file.
    function ConvertFrom-Base64 {
        param(
            $Base64,
            $Path
        )
        $bytes = [Convert]::FromBase64String($Base64)

        [IO.File]::WriteAllBytes($Path, $bytes)
    }

    # Utility function for downloading files.
    function Invoke-Download {
        param(
            [Parameter()]
            [String]$URL,
            [Parameter()]
            [String]$BaseName,
            [Parameter()]
            [int]$Attempts = 3,
            [Parameter()]
            [Switch]$SkipSleep
        )

        # In case 'https://' is omitted from the URL.
        if ($URL -notmatch "^http(s)?://") {
            Write-Warning "http(s):// is required to download the file. Adding https:// to your input...."
            $URL = "https://$URL"
            Write-Warning "New Url $URL."
        }
    
        Write-Host "Downloading using $URL"

        $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-Warning "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-Warning "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 3 -Maximum 15
                Write-Host "Waiting for $SleepTime seconds."
                Start-Sleep -Seconds $SleepTime
            }
            if ($i -ne 1) { Write-Host "" }
            Write-Host "Download Attempt $i"

            try {
                # Invoke-WebRequest is preferred because it supports links that redirect, e.g., https://t.ly
                if ($PSVersionTable.PSVersion.Major -lt 4) {
                    # Figures out the type of file
                    $WebClient = New-Object System.Net.WebClient
                    $Response = $WebClient.OpenRead($Url)
                    $MimeType = $WebClient.ResponseHeaders["Content-Type"]
                    $DesiredExtension = switch -regex ($MimeType) {
                        "image/jpeg|image/jpg" { "jpg" }
                        "image/png" { "png" }
                        "image/gif" { "gif" }
                        "image/bmp|image/x-windows-bmp|image/x-bmp" { "bmp" }
                        "image/x-icon|image/vnd.microsoft.icon|application/ico" { "ico" }
                        default { 
                            throw "[Error] The URL you provided does not provide a supported image type. Image Types Supported: jpg, jpeg, ico, bmp, png and gif. Image Type detected: $MimeType"
                        }
                    }
                    # Downloads the file preserving the extension
                    $Path = "$BaseName.$DesiredExtension"
                    $WebClient.DownloadFile($URL, $Path)
                }
                else {
                    # Standard options
                    $WebRequestArgs = @{
                        Uri                = $URL
                        MaximumRedirection = 10
                        UseBasicParsing    = $true
                        Method             = "GET"
                    }

                    # Figures out the type of file
                    $Response = Invoke-WebRequest @WebRequestArgs
                    $MimeType = $Response.Headers.'Content-Type'
                    $DesiredExtension = switch -regex ($MimeType) {
                        "image/jpeg|image/jpg" { "jpg" }
                        "image/png" { "png" }
                        "image/gif" { "gif" }
                        "image/bmp|image/x-windows-bmp|image/x-bmp" { "bmp" }
                        "image/x-icon|image/vnd.microsoft.icon|application/ico" { "ico" }
                        default { 
                            throw "[Error] The URL you provided does not provide a supported image type. Image Types Supported: jpg, jpeg, ico, bmp, png and gif. Image Type detected: $MimeType"
                        }
                    }
                    # Define the path for saving the file
                    $Path = "$BaseName.$DesiredExtension"

                    # Save the content to the file
                    $Response.Content | Set-Content -Path $Path -Encoding Byte
                }

                $File = Test-Path -Path $Path -ErrorAction SilentlyContinue
            }
            catch {
                Write-Warning "An error has occurred while downloading!"
                Write-Warning $_.Exception.Message
                $_

                if ($Path -and (Test-Path -Path $Path -ErrorAction SilentlyContinue)) {
                    Remove-Item $Path -Force -Confirm:$false -ErrorAction SilentlyContinue
                }

                $File = $False
            }

            if ($File) {
                $i = $Attempts
            }
            else {
                Write-Warning "File failed to download. Check the link/URL and ensure it is correct, please note Ninja may have stripped out the following characters '&|;$><`!' from the link/URL."
                Write-Host ""
            }

            $i++
        }

        if ($Path -and -not (Test-Path $Path)) {
            Write-Warning "Failed to download file!"
        }
        else {
            return $Path
        }
    }

    # Convert an image to an icon file. This method creates a png and then forms an ico file by appending the png's binary.
    function ConvertFrom-Image {
        param(
            $ImagePath,
            $Path
        )

        # Grab an instance of the image and blank bitmap
        try {
            $image = [Drawing.Image]::FromFile($ImagePath)
        }
        catch [System.OutOfMemoryException] {
            Write-Host "[Error] Loading Image file is either an unsupported file, or to large to process."
            return
        }
        catch {
            Write-Host "[Error] $($_.Message)"
            return
        }

        # Resize the image to 255px by 255px while maintaining quality.
        # If you want transparency, you'll need an Alpha channel in the pixel format.
        $bitmap = New-Object System.Drawing.Bitmap (255, 255, [system.drawing.imaging.PixelFormat]::Format32bppArgb)
        $bitmap.SetResolution(255, 255)

        # Create a graphics object which will be used to resize the image to 255px by 255px
        $graphics = [System.Drawing.Graphics]::FromImage($bitmap)

        # Set some quality settings for the resize operation
        $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality
        $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
        $graphics.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality

        # Draw the image onto the bitmap
        $graphics.DrawImage($Image, 0, 0, 255, 255)
        
        # Temporarily save the image as a png
        $RandomNumber = Get-Random -Maximum 1000000
        $bitmap.Save("$env:TEMP\image-$RandomNumber.png", [System.Drawing.Imaging.ImageFormat]::Png)
        $png = "$env:TEMP\image-$RandomNumber.png"

        # Build the ico file using the png binary.
        if ($PSVersionTable.PSVersion.Major -gt 5) {
            $pngBytes = Get-Content -Path $png -AsByteStream
        }
        elseif ($PSVersionTable.PSVersion.Major -gt 2) {
            $pngBytes = Get-Content -Path $png -Encoding Byte -Raw
        }
        else {
            $pngBytes = [System.IO.File]::ReadAllBytes($png)
        }
        $icoHeader = [byte[]] @(0, 0, 1, 0, 1, 0)
        $imageDataSize = $pngBytes.Length
        $icoDirectory = [byte[]] @(
            255, 255, # icon size
            0, 0, # color count
            0, 0, # reserved
            0, 0, # hotspot x, hotspot y
            ($imageDataSize -band 0xFF),
            ([Math]::Floor($imageDataSize / [Math]::Pow(2, 8)) -band 0xFF),
            ([Math]::Floor($imageDataSize / [Math]::Pow(2, 16)) -band 0xFF),
            ([Math]::Floor($imageDataSize / [Math]::Pow(2, 24)) -band 0xFF),
            22, 0, 0, 0  # offset to image data
        )
        $iconData = $icoHeader + $icoDirectory + $pngBytes

        # Save the completed icon file and clean up any temporary files.
        if (Test-Path $Path -ErrorAction SilentlyContinue) { Remove-Item $Path -Force }
        [System.IO.File]::WriteAllBytes($Path, $iconData)

        if (Test-Path $png -ErrorAction SilentlyContinue) { Remove-Item $png -Force }
        $bitmap.Dispose()
        $image.Dispose()
        $graphics.Dispose()
        [System.GC]::Collect()

        # Refresh the icon cache depending on the OS version.
        if ([System.Environment]::OSVersion.Version.Major -ge 10) {
            Invoke-Command { ie4uinit.exe -show }
        }
        else {
            Invoke-Command { ie4uinit.exe -ClearIconCache }
        }
    }

    # Verify if the script is being run with elevated privileges.
    function Test-IsElevated {
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        $p = New-Object System.Security.Principal.WindowsPrincipal($id)
        $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
    }

    if (-not (Test-IsElevated)) {
        Write-Host -Object "[Error] Access Denied. Please run with Administrator privileges."
        exit 1
    }

    # Retrieve all registry paths for actual users (excluding system or network service accounts).
    function Get-UserHives {
        param (
            [Parameter()]
            [ValidateSet('AzureAD', 'DomainAndLocal', 'All')]
            [String]$Type = "All",
            [Parameter()]
            [String[]]$ExcludedUsers,
            [Parameter()]
            [switch]$IncludeDefault
        )

        # Different SID patterns for user account types: AzureAD, Domain, or Local.
        $Patterns = switch ($Type) {
            "AzureAD" { "S-1-12-1-(\d+-?){4}$" }
            "DomainAndLocal" { "S-1-5-21-(\d+-?){4}$" }
            "All" { "S-1-12-1-(\d+-?){4}$" ; "S-1-5-21-(\d+-?){4}$" } 
        }

        # Extract user profiles that match the SID patterns. 
        $UserProfiles = Foreach ($Pattern in $Patterns) { 
            Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*" |
                Where-Object { $_.PSChildName -match $Pattern } | 
                Select-Object @{Name = "SID"; Expression = { $_.PSChildName } }, 
                @{Name = "UserHive"; Expression = { "$($_.ProfileImagePath)\NTuser.dat" } }, 
                @{Name = "UserName"; Expression = { "$($_.ProfileImagePath | Split-Path -Leaf)" } },
                @{Name = "Path"; Expression = { $_.ProfileImagePath } }
        }

        # Handle situations where information from the .Default user is required.
        switch ($IncludeDefault) {
            $True {
                $DefaultProfile = "" | Select-Object UserName, SID, UserHive, Path
                $DefaultProfile.UserName = "Default"
                $DefaultProfile.SID = "DefaultProfile"
                $DefaultProfile.Userhive = "$env:SystemDrive\Users\Default\NTUSER.DAT"
                $DefaultProfile.Path = "C:\Users\Default"

                $DefaultProfile | Where-Object { $ExcludedUsers -notcontains $_.UserName }
            }
        }

        $UserProfiles | Where-Object { $ExcludedUsers -notcontains $_.UserName }
    }

    # The actual shortcut creation
    function New-Shortcut {
        [CmdletBinding()]
        param(
            [Parameter()]
            [String]$Arguments,
            [Parameter()]
            [String]$IconPath,
            [Parameter(ValueFromPipeline = $True)]
            [String]$Path,
            [Parameter()]
            [String]$Target,
            [Parameter()]
            [String]$WorkingDir
        )
        process {
            Write-Host "Creating Shortcut at $Path"
            $ShellObject = New-Object -ComObject ("WScript.Shell")
            $Shortcut = $ShellObject.CreateShortcut($Path)
            $Shortcut.TargetPath = $Target
            if ($WorkingDir) { $Shortcut.WorkingDirectory = $WorkingDir }
            if ($Arguments) { $ShortCut.Arguments = $Arguments }
            if ($IconPath) { $Shortcut.IconLocation = $IconPath }
            $Shortcut.Save()

            if (-not (Test-Path $Path -ErrorAction SilentlyContinue)) {
                Write-Host "[Error] Unable to create Shortcut at $Path"
                exit 1
            }
        }
    }
}
process {
    $ShortcutPath = New-Object System.Collections.Generic.List[String]

    # Creating the filename's for the path
    if ($Url) { $File = "$Name.url"; $Target = $Url }
    if ($ExePath) { $File = "$Name.lnk"; $Target = $ExePath }
    if ($RDPTarget) { $File = "$Name.rdp" }

    # Grabing the excluded users
    if ($ExcludeUsers) { $ExcludedUsers = ($ExcludeUsers -split ",").trim() }

    # Building the path's and adding it to the ShortcutPath list
    if ($AllUsers) { $ShortcutPath.Add("$env:Public\Desktop\$File") }

    if ($AllExistingUsers) {
        $UserProfiles = Get-UserHives -ExcludedUsers $ExcludedUsers
        # Loop through each user profile
        $UserProfiles | ForEach-Object { $ShortcutPath.Add("$($_.Path)\Desktop\$File") }
    }

    if ($User) { 
        $UserProfile = Get-UserHives | Where-Object { $_.Username -like $User }
        $ShortcutPath.Add("$($UserProfile.Path)\Desktop\$File")
    }

    $ShortcutArguments = @{
        Target     = $Target
        WorkingDir = $StartIn
        Arguments  = $Arguments
    }

    # If we're given a url we'll want to download it
    if ($IconUrl) {
        $DownloadArguments = @{
            URL      = $IconUrl
            BaseName = "$IconDirectory\$Name"
        }
        if ($SkipSleep) { $DownloadArguments["SkipSleep"] = $True }

        $Icon = Invoke-Download @DownloadArguments
        if ($Icon -and -not (Test-Path $Icon -ErrorAction SilentlyContinue)) {
            $ExitCode = 1
            $Icon = $Null
            $IconUrl = $Null
        }
    }

    # This will convert the base64 into an image and save it to the temp folder
    if ($IconBase64 -and $IconDirectory -and -not $Icon -and -not $IconUrl) {
        Write-Verbose "Converting Icon base64 to original image and saving to $IconDirectory..."
        ConvertFrom-Base64 -Base64 $IconBase64 -Path "$IconDirectory\$Name.Png"
        $Icon = "$IconDirectory\$Name.Png"
    }

    if ($Icon -and (Get-Item -Path $Icon).Extension -notlike ".ico") {
        $FileHash = "$((Get-FileHash -Path $Icon -Algorithm MD5).Hash)"
        Write-Verbose "Converting image to icon and saving to $IconDirectory\$FileHash.ico ..."
        ConvertFrom-Image -ImagePath $Icon -Path "$IconDirectory\$FileHash.ico"
        Remove-Item -Path $Icon -Force
        $Icon = "$IconDirectory\$FileHash.ico"
    }
    elseif ($Icon -and (Test-Path $Icon -ErrorAction SilentlyContinue)) {
        $FileHash = "$((Get-FileHash -Path $Icon -Algorithm MD5).Hash)"
        Move-Item -Path $Icon -Destination "$IconDirectory\$FileHash.ico"
        $Icon = "$IconDirectory\$FileHash.ico"
    }

    if ($Icon -and (Test-Path $Icon -ErrorAction SilentlyContinue)) {
        $ShortcutArguments["IconPath"] = $Icon
    }
    elseif ($Icon) {
        $ExitCode = 1
    }

    $ShortcutPath | New-Shortcut @ShortcutArguments

    exit $ExitCode
}end {
    
    
    
}

 

Greifen Sie auf über 300 Skripte im NinjaOne Dojo zu.

Zugang erhalten

Detailansicht

Skript-Synopse und Parameter

Die Hauptfunktion des PowerShell-Skripts besteht darin, Desktop-Verknüpfungen für ausführbare Dateien mit bestimmten Optionen zu erstellen. Es unterstützt die Erstellung von Verknüpfungen für alle Benutzer:innen, einschließlich neuer Anwender:innen, oder nur für bestehende. Hier finden Sie eine Übersicht über die Parameter und Funktionen:

  • Name: Der Name der Verknüpfung, zum Beispiel ‘Login Portal’.
  • ExePath: Der Pfad zur ausführbaren Datei.
  • Arguments: Alle Argumente, die an die ausführbare Datei übergeben werden.
  • StartIn: Das Verzeichnis, in dem die ausführbare Datei gestartet werden soll.
  • Icon: Pfad zu einer Bilddatei für das Verknüpfungssymbol.
  • IconDirectory: Verzeichnis zum Speichern der Symboldatei.
  • IconURL: URL zu einer Bilddatei für das Verknüpfungssymbol.
  • AllExistingUsers: Erzeugt die Verknüpfung für alle vorhandenen Benutzer:innen.
  • AllUsers: Erstellt die Verknüpfung für alle Anwender:innen, auch für neue.
  • ExcludeUsers: Liste der Benutzer:innen, die von der Erstellung von Verknüpfungen ausgeschlossen werden sollen.

Skript-Funktionalität

Ersteinrichtung

Das Skript beginnt mit dem Hinzufügen der erforderlichen .NET-Assembly zum Zeichnen, die für die Handhabung von Bilddateien entscheidend ist. Es enthält auch einen Abschnitt für den Umgang mit base64-kodierten Symbolen, was Flexibilität für die dynamische Symbolerstellung bietet.

Handhabung der Parameter

Umgebungsvariablen können die angegebenen Parameter überschreiben, sodass sich das Skript an unterschiedliche Laufzeitbedingungen anpassen kann. Dies ist besonders in automatisierten Bereitstellungsszenarien nützlich.

Benutzer-Validierung

Bevor das Skript fortfährt, prüft es, ob ein Benutzer für die Erstellung der Verknüpfung angegeben wurde. Dadurch werden Fehler vermieden und sichergestellt, dass das Skript auf die richtigen Benutzerprofile abzielt.

Verarbeitung von Symbolen

Das Skript enthält eine robuste Verarbeitung von Symbolen:

  • es prüft auf gültige Dateiformate,
  • lädt Symbole von URLs herunter, falls angegeben,
  • konvertiert base64-kodierte Bilder in Symbol-Dateien und
  • konvertiert bei Bedarf verschiedene Bildformate in .ico-Dateien.

Erstellung von Verknüpfungen

Mit Hilfe des COM-Objekts WScript.Shell erstellt das Skript Verknüpfungen mit den angegebenen Parametern. Es unterstützt mehrere Benutzerprofile, indem es durch Benutzerverzeichnisse iteriert.

Potenzielle Anwendungsfälle

Praxisnahes Szenario

Stellen Sie sich eine IT-Abteilung in einem großen Unternehmen vor, die ein neues Unternehmensressourcenplanung (ERP)-System einführen muss. Das IT-Team kann dieses Skript verwenden, um eine Desktop-Verknüpfung für die ERP-Anwendung auf den Desktops aller Benutzer:innen zu erstellen. Durch die Angabe des ausführbaren Pfads, des Startverzeichnisses und des benutzerdefinierten Symbols gewährleistet das Team eine einheitliche und professionelle Benutzererfahrung. Die Fähigkeit des Skripts, mehrere Benutzerprofile zu verwalten, vereinfacht die Bereitstellung im gesamten Unternehmen.

Vergleiche

Die manuelle Erstellung von Desktop-Verknüpfungen oder über Gruppenrichtlinien kann im Vergleich zur Verwendung eines PowerShell-Skripts umständlich und weniger flexibel sein. Gruppenrichtlinien bieten ein gewisses Maß an Automatisierung, aber nicht die detaillierte Kontrolle und Anpassung, die dieses Skript bietet. Außerdem kann das Skript dynamische Szenarien wie das Herunterladen von Symbolen von URLs oder die Konvertierung von base64-kodierten Bildern handhaben, was mit herkömmlichen Methoden nicht möglich ist.

FAQs

  1. Kann dieses Skript auf allen Versionen von Windows ausgeführt werden? Das Skript unterstützt Windows 7 und neuere Versionen, einschließlich Windows Server 2008 und höher.
  2. Was passiert, wenn die Symboldatei nicht gültig ist? Das Skript erstellt die Verknüpfung standardmäßig ohne ein Symbol, wenn die angegebene Symboldatei ungültig ist.
  3. Wie geht das Skript mit Berechtigungen um? Das Skript prüft, ob es über erhöhte Rechte verfügt, um sicherzustellen, dass es die erforderlichen Berechtigungen zur Erstellung von Desktop-Verknüpfungen über mehrere Benutzerprofile hinweg besitzt.
  4. Kann das Skript so verändert werden, dass es zusätzliche Parameter unterstützt? Ja, das Skript ist modular aufgebaut und kann leicht erweitert werden, um zusätzliche Parameter oder Funktionen zu unterstützen.

Folgen

Die Automatisierung der Erstellung von Desktop-Verknüpfungen mit diesem PowerShell-Skript kann den IT-Betrieb erheblich rationalisieren, da der manuelle Aufwand reduziert und das Risiko menschlichen Versagens minimiert wird. Es ist jedoch essenziell, dafür zu sorgen, dass das Skript mit den entsprechenden Berechtigungen ausgeführt wird, um Sicherheitsprobleme zu vermeiden. Die ordnungsgemäße Verwaltung und Bereitstellung von Verknüpfungen trägt auch dazu bei, eine saubere und organisierte Desktop-Umgebung für Benutzer:innen zu erhalten.

Empfehlungen

Wenn Sie dieses Skript verwenden:

  • Testen Sie es immer in einer Staging-Umgebung, bevor Sie die Software an alle Anwender:innen verteilen.
  • Stellen Sie sicher, dass das Symbolverzeichnis für alle Benutzer:innen zugänglich ist.
  • Aktualisieren Sie das Skript regelmäßig, um neue Benutzerprofile und veränderte Anforderungen zu berücksichtigen.
  • Führen Sie eine klare Dokumentation für alle am Skript vorgenommenen Änderungen.

Abschließende Überlegungen

PowerShell-Skripte wie dieses sind leistungsstarke Tools, die IT-Experten Automatisierungs- und Anpassungsmöglichkeiten zur Optimierung von Routineaufgaben bieten. Für IT-Abteilungen und MSPs kann der Einsatz solcher Skripte zu einem effizienteren Betrieb und einer besseren Erfahrung für die Endbenutzer:innen führen.

NinjaOne, eine umfassende IT-Management-Plattform, kann solche Skripte in seine Automatisierungs-Workflows integrieren und bietet damit eine nahtlose und leistungsstarke Lösung für die Verwaltung von skalierten IT-Umgebungen. Durch das Verständnis und die Verwendung dieses PowerShell-Skripts können IT-Experten ihr Toolkit erweitern und eine effiziente und effektive Verwaltung von Desktop-Umgebungen sicherstellen.

Nächste Schritte

Der Aufbau eines effizienten und effektiven IT-Teams erfordert eine zentralisierte Lösung, die als einheitliches Tool zur Bereitstellung von IT-Dienstleistungen fungiert. NinjaOne ermöglicht es IT-Teams, alle Geräte zu überwachen, zu verwalten, zu sichern und zu unterstützen, unabhängig vom Standort, ohne dass eine komplexe Infrastruktur vor Ort erforderlich ist.

Erfahren Sie mehr über NinjaOne Remote Script Deployment, sehen Sie sich eine Live-Tour an oder starten Sie Ihre kostenlose Testversion unserer NinjaOne Plattform.

Kategorien:

Das könnte Sie auch interessieren

×

Sehen Sie NinjaOne in Aktion!

Mit dem Absenden dieses Formulars akzeptiere ich die Datenschutzerklärung von NinjaOne.

NinjaOne Allgemeine Geschäftsbedingungen für Skripte

Indem Sie unten auf die Schaltfläche “Ich akzeptiere” klicken, erklären Sie Ihr Einverständnis mit den folgenden rechtlichen Bedingungen sowie mit unseren Nutzungsbedingungen:

  • Eigentumsrechte: NinjaOne besitzt und wird weiterhin alle Rechte, Titel und Interessen an dem Skript (einschließlich des Urheberrechts) behalten. NinjaOne gewährt Ihnen eine eingeschränkte Lizenz zur Nutzung des Skripts in Übereinstimmung mit diesen rechtlichen Bedingungen.
  • Einschränkung der Nutzung: Sie dürfen das Skript nur für Ihre legitimen persönlichen oder internen Geschäftszwecke verwenden und es nicht an Dritte weitergeben.
  • Verbot der Wiederveröffentlichung: Sie sind unter keinen Umständen berechtigt, das Skript in einer Skriptbibliothek, die einem anderen Softwareanbieter gehört oder von diesem kontrolliert wird, erneut zu veröffentlichen.
  • Gewährleistungsausschluss: Das Skript wird “wie gesehen” und “wie verfügbar” bereitgestellt, ohne jegliche Garantie. NinjaOne gibt keine Versprechen oder Garantien, dass das Skript frei von Fehlern ist oder dass es Ihre speziellen Bedürfnisse oder Erwartungen erfüllt.
  • Risikoübernahme: Die Verwendung des Skripts erfolgt auf eigene Gefahr. Sie erkennen an, dass die Nutzung des Skripts mit bestimmten Risiken verbunden ist, und Sie verstehen und übernehmen jedes dieser Risiken.
  • Verzicht und Freigabe: Sie machen NinjaOne nicht für nachteilige oder unbeabsichtigte Folgen verantwortlich, die sich aus Ihrer Nutzung des Skripts ergeben, und Sie verzichten auf alle gesetzlichen oder billigkeitsrechtlichen Rechte oder Rechtsmittel, die Sie gegen NinjaOne im Zusammenhang mit Ihrer Nutzung des Skripts haben könnten.
  • EULA: Wenn Sie ein NinjaOne-Kunde sind, unterliegt Ihre Nutzung des Skripts dem für Sie geltenden Endbenutzer-Lizenzvertrag (EULA).