Managing Microsoft Remote Desktop 10 Bookmarks with handy Jamf Scripts

Microsoft introduced a handy feature in version 10 of their Remote Desktop client with little fanfare; the ability to manage bookmarks, feeds and gateways using the command line. I think it deserves some more attention.

It was possible to add bookmarks with the previous version 8 of Microsoft Remote Desktop using this method devised by Ben Toms, but sadly, version 10 no longer supports this way of doing it.

Introducing the --script argument

Be aware that these commands must run in the current logged in user’s context and will manage Microsoft Remote Desktop entries only for them. There’s isn’t an option to set these up for all users on a Mac at once.

Open a Terminal and run:

"/Applications/Microsoft Remote Desktop/Contents/MacOS/Microsoft Remote Desktop" --script

Behold the output:

Usage:

  --script  

  Modules:

    bookmark  Create, edit or delete a connection bookmark.
    feed      Subscribe to a resource feed, or edit or delete a subscription.
    gateway   Create, edit or delete a Remote Desktop gateway.

  To get help for a specific module:

    --script  help

  Examples:

    --script bookmark help
    --script feed help
    --script gateway help

So, if we want to manage a bookmark, say create one, we can use the help verb get more information about the commands and syntax we’d need to achieve this. For example, to see the commands available for bookmarks, run:

"/Applications/Microsoft Remote Desktop/Contents/MacOS/Microsoft Remote Desktop" --script bookmark help

Create, edit or delete a connection bookmark.

Usage:

  --script bookmark <command> <unique ID> <parameters>

  Commands:

    write   Create or edit a connection bookmark.
    delete  Delete a bookmark.
    list    List all stored bookmarks.
    export  Output a bookmark as a formatted string.

  To get help for a specific command:

    --script bookmark <command> help

  Examples:

    --script bookmark write help
    --script bookmark delete help
    --script bookmark list help
    --script bookmark export help

Then, to drill down further and see more information about creating (writing) a bookmark, run:

"/Applications/Microsoft Remote Desktop/Contents/MacOS/Microsoft Remote Desktop" --script bookmark write help

Create or edit a connection bookmark identified by a unique ID.

Usage:

  --script bookmark write <unique ID> <parameters>

  Parameters:

    --hostname <string>
      The hostname of the remote server. This value is required when creating
      the bookmark.

    --username <string>
      The username to use when connecting to the remote server. A user account
      will be created if an existing one cannot be found.

    --password <string>
      The password associated with the username.

    --friendlyname <string>
      The friendly name of the bookmark.

    --group <string>
      The name of the group wherein the bookmark should reside. A group will
      be created if an existing one could not be found.

    --gateway <string>
      The unique ID of an existing Remote Desktop gateway. If a gateway with
      the given ID does not exist, this parameter will be ignored.

    --gatewayhostname <string>
      The hostname of an existing Remote Desktop gateway. If a gateway with
      the given hostname does not exist, a new one will be created with the
      given hostname. If multiple gateways exist with the same hostname, the
      first one will be selected.

    --bypassgateway <true | false>
      If set to true, the Remote Desktop gateway will not be used if the Remote
      Desktop server is on the same network as the client machine. This
      parameter is true by default.

    --admin <true | false>
      If set to true, the client will connect to a session that is used for
      administrative purposes.

    --swapmousebuttons <true | false>
      If set to true, the left and right mouse buttons will be swapped.

    --autoreconnect <true | false>
      If set to true, the client will attempt to automatically reconnect if
      the connection is interrupted. This parameter is true by default.

    --useallmonitors <true | false>
      If set to true, all the local monitors will be used in the remote
      session.

    --fullscreen <true | false>
      If set to true, starts the connection in full screen mode (vs windowed
      mode). This parameter is true by default.

    --scaling <true | false>
      If set to true, the graphics output of the remote session will be
      scaled to fit inside the client window.

    --resolution "<integer integer>"
      The width and height of the remote session in pixels. The width and
      height must be positive integer values specified as a single string
      inside quotation marks (for example, "800 600").

    --colordepth <16 | 32>
      The color depth of the remote session in bits per pixel. Allowed
      values are 16 and 32.

    --retina <true | false>
      If set to true, the graphics output of the remote session is optimized
      for Retina displays. A value of true is not recommended for connections
      to versions of Windows prior to Windows 10 and Windows Server 2016.

    --dynamicdisplay <true | false>
      If set to true, the resolution of the remote session is dynamically
      updated to match the client window size. Dynamic display is only
      supported by Windows 8.1, Windows Server 2012 R2 and later.

    --audioplayback <0 | 1 | 2>
      Specifies how to handle audio streams sent by the remote server.
      0: Play the audio on the local computer.
      1: Play the audio on the remote server.
      2: Don't play any audio.
      This parameter is set to 0 by default.

    --redirectmicrophones <true | false>
      If set to true, microphones attached to the computer are redirected to
      the remote session.

    --redirectcameras <true | false>
      If set to true, video capture devices attached to the computer are redirected to
      the remote session.

    --redirectprinters <true | false>
      If set to true, printers attached to the computer are redirected to the
      remote session.

    --redirectfolders <true | false>
      If set to true, selected folders are redirected to the remote session.
      Due to sandboxing restrictions, users must manually select folders to
      redirect in the client UI.

    --redirectsmartcards <true | false>
      If set to true, smart card readers attached to the computer are redirected
      to the remote session.

    --redirectclipboard <true | false>
      If set to true, the local and remote clipboards are kept in sync. This
      parameter is true by default.

    --remoteappprogram <string>
      The file path of the remote app to launch on the remote server.

    --remoteappcmdline <string>
      Command line parameters to pass to the remote app when it is launched
      on the remote server.

    --remoteappworkingdir <string>
      The working directory assigned to the remote app when it is launched on
      the remote server.

    --rdpfilecontents <string>
      The contents of an RDP file which should be used to create a bookmark.
      The "\n" character must be used as a delimiter between properties.

  Examples:

    --script bookmark write 8725187 --hostname jumpbox.contoso.com --resolution "1024 768" --fullscreen false --group "Work PCs"
    --script bookmark write 5653454 --rdpfilecontents "full address:s:hostname\ngatewayaccesstoken:s:gyu7hj8o\nenablecredsspsupport:i:0"

Welp. That’s a lot of stuff! Can we make it more digestible?

Indeed! So, here are a couple of scripts I wrote that help make it manageable (for example, taking care of replacing pre-existing bookmark(s) with the same name, because Remote Desktop works with unique identifiers). Because Jamf is what I use, they’re written around that, but you can adapt them to your management tool of choice.

Run them as part of a login (whilst login hooks are still a thing) or self-service policy, because someone must be logged in (the Microsoft Remote Desktop binary needs to run in their context, remember?). If users have the Microsoft Remote Desktop application open when these scripts run, they must quit and re-open it before they see the changes.

Add or replace a bookmark

#!/bin/sh
# Add a Microsoft Remote Desktop bookmark entry for the specified computer.
#
# Neil Martin – https://soundmacguy.wordpress.com – @neilmartin83
#
############################
#
# Use Parameter 4 in Jamf to specify the hostname or IP address of the bookmark you wish to add e.g. myawesomepc.com (required)
#
# Use Parameter 5 in Jamf to specify the friendly name of the bookmark you wish to add, without quotes e.g. My Awesome PC (optional)
#
# Use Parameter 6 in Jamf to specify the resolution, without quotes e.g: 1024 768 (optional)
#
# Use Parameter 7 in Jamf to specify the group, if needed, without quotes e.g. Work PCs (optional)
#
# Use Parameter 8 in Jamf to specify the username, if needed, without quotes. Enter loggedInUser to use the current user's username! (optional)
#
# Use Parameter 9 in Jamf to specify the domain, if needed, without quotes e.g. myorg.com (optional)
#
# Use Parameter 10 in Jamf to specify other arguments as needed. Avoid specifying parameters that use quotes. (optional)
# For more information on available arguments, run:
# "/Applications/Microsoft Remote Desktop.app/Contents/MacOS/Microsoft Remote Desktop" –script bookmark add help
#
# Set Parameter 11 in Jamf to YES if you want to REPLACE all existing bookmarks that have the same hostname, if present. (optional)
# If this is not set, an additional bookmark for this hostname will be created if it already exists.
#
############################
hostname="${4}"
friendlyname="${5}"
resolution="${6}"
group="${7}"
username="${8}"
domain="${9}"
extraArgs=${10}
replace="${11}"
loggedInUser=$( echo "show State:/Users/ConsoleUser" | /usr/sbin/scutil | /usr/bin/awk '/Name :/ && ! /loginwindow/ { print $3 }' )
msrd="/Applications/Microsoft Remote Desktop.app/Contents/MacOS/Microsoft Remote Desktop"
if [ -z "${loggedInUser}" ]; then
/bin/echo "Nobody logged in, exiting…"
exit 1
else
/bin/echo "User: ${loggedInUser} is logged in…"
fi
if [ ! -f "${msrd}" ]; then
/bin/echo "Microsoft Remote Desktop not installed, exiting…"
exit 1
fi
if [ -z "${hostname}" ]; then
/bin/echo Hostname not specified, exiting…
exit 1
fi
if [ -z "${friendlyname}" ]; then
/bin/echo "Friendly name not specified, using ${hostname}"
friendlyname="${hostname}"
fi
if [ "${replace}" == "YES" ]; then
/bin/echo "Existing bookmarks for ${friendlyname} will be removed!"
entrylist=($(sudo -u "${loggedInUser}" "${msrd}" –script bookmark list 2>/dev/null | /usr/bin/grep -w "${friendlyname}" | /usr/bin/awk -F '", ' '{print $2}'))
if [ -z "${entrylist}" ]; then
/bin/echo "No existing entries found for ${friendlyname}"
else
for entry in "${entrylist[@]}"; do
/bin/echo "Deleting entry for ${friendlyname} and unique ID ${entry}"
sudo -u "${loggedInUser}" "${msrd}" –script bookmark delete "${entry}" 2>/dev/null
done
fi
fi
if [ -z "${username}" ]; then
/bin/echo "Username not specified, Creating bookmark: ${friendlyname}"
sudo -u "${loggedInUser}" "${msrd}" –script bookmark write $(uuidgen) –hostname "${hostname}" –friendlyname "${friendlyname}" –resolution "${resolution}" –group "${group}" ${extraArgs} 2>/dev/null
else
if [ "${username}" == "loggedInUser" ]; then
/bin/echo "Username specified, creating bookmark using logged in user's username…"
username="${loggedInUser}"
else
/bin/echo "Username specified, Creating bookmark for: ${username}"
fi
if [ -z "${domain}" ]; then
/bin/echo "Domain not specified, username will not be prefixed…"
else
username="${domain}"'\'"${username}"
/bin/echo "Domain specified, Username will be ${username}"
fi
/bin/echo "Creating bookmark: ${friendlyname}"
sudo -u "${loggedInUser}" "${msrd}" –script bookmark write $(uuidgen) –hostname "${hostname}" –friendlyname "${friendlyname}" –resolution "${resolution}" –group "${group}" –username "${username}" ${extraArgs} 2>/dev/null
fi

Use this to add a Microsoft Remote Desktop bookmark entry for the specified computer. The bookmark’s unique ID is generated automatically. Parameters should be filled out as follows:

Parameter 4: specify the hostname or IP address of the bookmark you wish to add e.g. mypc.com (required)

Parameter 5: specify the friendly name of the bookmark you wish to add, without quotes e.g. My PC (optional)

Parameter 6: specify the resolution, without quotes e.g: 1024 768 (optional)

Parameter 7: specify the group, if needed, without quotes e.g. Company PCs (optional)

Parameter 8: specify the username, if needed, without quotes. Or enter loggedInUser to use the current user’s username! (optional)

Parameter 9: specify the domain, if needed, without quotes e.g. myorg.com (optional)

Parameter 10: specify other arguments as needed. Avoid specifying parameters that use quotes. (optional)
For more information on available arguments, run:
"/Applications/Microsoft Remote Desktop.app/Contents/MacOS/Microsoft Remote Desktop" --script bookmark add help

Parameter 11: Set to YES if you want to REPLACE all existing bookmarks that have the same hostname, if present. (optional). If this is not set, an additional bookmark for this hostname will be created if it already exists.

Here’s an example of the parameters when they’re filled out:

And here’s some example output from the policy log, after a successful run:

A new bookmark will be created in Microsoft Remote Desktop, configured with your specified settings:

Delete a bookmark

#!/bin/sh
# Delete all Microsoft Remote Desktop bookmark entries for the specified hostname
#
# Neil Martin – https://soundmacguy.wordpress.com – @neilmartin83
#
############################
#
# Use Parameter 4 in Jamf to specify the friendly name or hostname of the bookmarks you wish to delete
# Friendly name always takes precedence. If the bookmark has no friendly name set, the hostname will be used instead.
#
############################
name="${4}"
loggedInUser=$( echo "show State:/Users/ConsoleUser" | /usr/sbin/scutil | /usr/bin/awk '/Name :/ && ! /loginwindow/ { print $3 }' )
msrd="/Applications/Microsoft Remote Desktop.app/Contents/MacOS/Microsoft Remote Desktop"
if [ -z "${loggedInUser}" ]; then
/bin/echo "Nobody logged in, exiting…"
exit 1
else
/bin/echo "User: ${loggedInUser} is logged in…"
fi
if [ ! -f "${msrd}" ]; then
/bin/echo "Microsoft Remote Desktop not installed, exiting…"
exit 1
fi
if [ -z "${name}" ]; then
/bin/echo Bookmark name not specified, exiting…
exit 1
fi
entrylist=($(sudo -u "${loggedInUser}" "${msrd}" –script bookmark list 2>/dev/null | /usr/bin/grep -w "${name}" | /usr/bin/awk -F '", ' '{print $2}'))
if [ -z "${entrylist}" ]; then
/bin/echo "No bookmarks found for ${name}, exiting…"
exit 0
else
for entry in "${entrylist[@]}"; do
/bin/echo "Deleting entry for ${name} and unique ID: ${entry}"
sudo -u "${loggedInUser}" "${msrd}" –script bookmark delete "${entry}" 2>/dev/null
done
fi

Use this to delete all bookmarks with the specified friendly or host name. Beware that if there are multiple bookmarks with the same name, this deletes them ALL! Friendly names take precedence, hostnames are used when the bookmark does not have a friendly name set. Parameters should be filled out as follows:

Parameter 4: specify the name of the bookmark you wish to delete, without quotes, e.g. My PC (if it has a friendly name) or mypc.com (if it only has the hostname). (required).

Here’s an example of the policy log, following a successful run:

Further learnings…

Check out the #microsoft-rdc channel in the MacAdmins Slack to ask questions and chat to others about their scripting workflows. Special thanks go to Elton Saul (@eltons) and Gieta Laksmana (@gietal) from Microsoft, who hang out there and provide an invaluable resource for the Mac Admin community. Without them, the scripting functionality in Microsoft Remote Desktop 10 wouldn’t even exist.

5 thoughts on “Managing Microsoft Remote Desktop 10 Bookmarks with handy Jamf Scripts”

  1. Hi,

    I tried running this script via Jamf but i get the following error

    Executing Policy Add Remote Desktop H&L
    Running script msrd10-add-remotedesktop…
    Script exit code: 132
    Script result: User: staff is logged in…
    Username specified, Creating bookmark for: sysnet
    Domain not specified, username will not be prefixed…
    Creating bookmark: H&L
    /Library/Application Support/JAMF/tmp/msrd10-add-remotedesktop: line 98: 7252 Illegal instruction: 4 sudo -u “${loggedInUser}” “${msrd}” –script bookmark write $(uuidgen) –hostname “${hostname}” –friendlyname “${friendlyname}” –resolution “${resolution}” –group “${group}” –username “${username}” ${extraArgs} 2> /dev/null
    Error running script: return code was 132.

    but if i jump on the computer and run sudo jamf policy the script runs, not sure why its not working via the Policy. Would you happen to know what the error is?

    Cheers!

    Like

    1. Heya! Can you try replacing line 97 with the following and let me know if this helps?


      su "${loggedInUser}" -c -l '"${msrd}" --script bookmark write $(uuidgen) --hostname "${hostname}" --friendlyname "${friendlyname}" --resolution "${resolution}" --group "${group}" --username "${username}" ${extraArgs} 2>/dev/null'

      Liked by 1 person

  2. Hi Neil,

    Thanks for getting back to me, i tried replacing line 97 and failed (see below)

    Executing Policy Add Remote Desktop H&L
    Running script msrd10-add-remotedesktop…
    Script exit code: 1
    Script result: User: staff is logged in…
    Username specified, Creating bookmark for: sysnet
    Domain not specified, username will not be prefixed…
    Creating bookmark: H&L
    /Library/Application Support/JAMF/tmp/msrd10-add-remotedesktop: line 97: /dev/null’: Operation not permitted
    Error running script: return code was 1.

    I then tried to run the policy via terminal and it doesn’t work whereas the first script did (see below)

    Checking for policies triggered by “recurring check-in” for user “staff”…
    Executing Policy Add Remote Desktop H&L
    Running script msrd10-add-remotedesktop…
    Script exit code: 1
    Script result: User: staff is logged in…
    Username specified, Creating bookmark for: sysnet
    Domain not specified, username will not be prefixed…
    Creating bookmark: H&L
    /Library/Application Support/JAMF/tmp/msrd10-add-remotedesktop: line 97: /dev/null’: Operation not permitted

    Error running script: return code was 1.

    Is this because i’m running it on the M1 iMac and the account is a standard account not administrator?

    Regards,
    Khuong

    Like

  3. I’m trying to use this script myself on macOS Monterey 12.4 and receive an ‘PromiseKit: warning: ‘wait()’ called on main thread! error.

    I also notice that the RDP app opens and script does not continue before I quit it.

    Like

    1. Hey Jordy,

      I just tried the add computer script on my Mac running 12.4 and MSRD 10.7.6 (App Store/VPP version) and it works without any problems – so I can’t replicate the issue I’m afraid.

      Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.