16

Is there a simple way to create shortcuts in Windows 7 on Python? I looked it up online but they did not seem that simple.

I have tried using this simple method:

hi = open("ShortcutFile.lnk", "w")
hi.close()

Which creates a shortcut file. But how would I edit the link it is connected to. Like the file it would open? Can someone give me a push in the right direction?

0Cool
  • 2,335
  • 4
  • 16
  • 16

8 Answers8

21

Old, but I would still like to post an answer to help out anyone who might have the same question and in need of a code example.

First, download pywin32 with pip install pywin32 or download the sourceforge binaries or the pywin32 wheel file and pip install.

import win32com.client
import pythoncom
import os
# pythoncom.CoInitialize() # remove the '#' at the beginning of the line if running in a thread.
desktop = r'C:\Users\Public\Desktop' # path to where you want to put the .lnk
path = os.path.join(desktop, 'NameOfShortcut.lnk')
target = r'C:\path\to\target\file.exe'
icon = r'C:\path\to\icon\resource.ico' # not needed, but nice

shell = win32com.client.Dispatch("WScript.Shell")
shortcut = shell.CreateShortCut(path)
shortcut.Targetpath = target
shortcut.IconLocation = icon
shortcut.WindowStyle = 7 # 7 - Minimized, 3 - Maximized, 1 - Normal
shortcut.save()

I have used the WindowStyle when I have a GUI with a debug console, and I don't want the console to pop up all the time. I haven't tried it with a program that isn't consoled.

Hope this helps!

Casey
  • 419
  • 5
  • 13
5

If you looking for a platform independent version that works with Python 3 look at swinlnk.

from swinlnk.swinlnk import SWinLnk
swl = SWinLnk()
swl.create_lnk('W:\Foo\Bar', '/mnt/win_share/playground/Bar_winlink.lnk')

This python script is based on the C / Bash Tool mslink.

Kound
  • 1,835
  • 1
  • 17
  • 30
  • 1
    It doesn't work in windows 7. The lnk is genereted, but the 'start in' propierter is not genered. When you try to launch te app through this shortcout the system trow an error as "Fatal error detected: Failed to execute scrpt [script name]". Look at this example. The "purple context one" the lnk generated by SWinLnk python library; the green one is the windows system's lnk generated by right "click->send to desktop" [ img -> https://yandex.com/collections/card/5dfe567d01cde45d70d4a0f4/ ] – Drumsman Dec 21 '19 at 17:32
  • This works for me finally: https://stackoverflow.com/questions/26986470/create-shortcut-files-in-windows-7-using-python/59441024#59441024 – Drumsman Dec 22 '19 at 01:25
  • I see that you want to execute a program - I only tested it to link to a folder. The start in path is not supported by swinlnk so far but the C tool mslink does offer it. So if you need an easy solution that offers the start in parameter have a look at this tool. The solution you proprose is obsolete as if you are working under Windows anyway, you simply could use pywin32 as already proprosed – Kound Dec 28 '19 at 17:20
3
import os
import pathlib
import tempfile
import subprocess


def create_shortcut(shortcut_path, target, arguments='', working_dir=''):
    shortcut_path = pathlib.Path(shortcut_path)
    shortcut_path.parent.mkdir(parents=True, exist_ok=True)

    def escape_path(path):
        return str(path).replace('\\', '/')

    def escape_str(str_):
        return str(str_).replace('\\', '\\\\').replace('"', '\\"')

    shortcut_path = escape_path(shortcut_path)
    target = escape_path(target)
    working_dir = escape_path(working_dir)
    arguments = escape_str(arguments)

    js_content = f'''
        var sh = WScript.CreateObject("WScript.Shell");
        var shortcut = sh.CreateShortcut("{shortcut_path}");
        shortcut.TargetPath = "{target}";
        shortcut.Arguments = "{arguments}";
        shortcut.WorkingDirectory = "{working_dir}";
        shortcut.Save();'''

    fd, path = tempfile.mkstemp('.js')
    try:
        with os.fdopen(fd, 'w') as f:
            f.write(js_content)
        subprocess.run([R'wscript.exe', path])
    finally:
        os.unlink(path)


if __name__ == '__main__':
    create_shortcut(
        R'D:\xxx\hello_world.lnk',
        R'cmd.exe',
        R'/c "echo hello world && pause"',
    )
Pamela
  • 549
  • 4
  • 7
  • It is a nice and clean solution that can run the python part on linux while copying the resulting .js file to windows and using ssh/paramiko to run it there. Thanks. – Zbyněk Winkler Mar 31 '22 at 16:26
1

You can generate a .bat file dinamically fod do that, and replacing specific parts with the corrected path for operate with spaces.

Te correct way to manage windows paths with spaces is wrap the spaced path secion with "". For example, if the path is

C:\Users\The Pc\Desktop

the corrected version is

C:\Users\"The Pc"\Desktop

The solution what I propose is this:

1- Generate a base .bat file with keywords for to replace with te correct path through Python.

2- Build the path according the current environ using the os Python library.

3- Open the base.bat file with Python and check line by line seaching for the keyword for to replace with the correctd path previously generated in the steep 2.

4- At the same time we check and replace our spetial keywords with te corrected path, we write a final .bat file with the updated lines of the base.bat file in the same for loop statament.

5- Execute the final.bat file with the subprocess Python library:


For explain it with code, I gonna use a personal screen recorder project, and it goes like this:

1) Our base.bat file (look at our [r] keywords):

=============================================================

@echo off

set dir=%LOCALAPPDATA%\srw

set sof=srw.exe

set name=Grabador de Pantalla

ECHO Set objShell = WScript.CreateObject("WScript.Shell") >>[r]

ECHO ficheroAccesoDirecto = "%USERPROFILE%\Desktop\%name%.lnk" >>[r]

ECHO Set objAccesoDirecto = objShell.CreateShortcut(ficheroAccesoDirecto) >>[r]

ECHO objAccesoDirecto.TargetPath = "%dir%\%sof%" >>[r]

ECHO objAccesoDirecto.Arguments = "" >>[r]

ECHO objAccesoDirecto.Description = "%name%" >>[r]

ECHO objAccesoDirecto.HotKey = "ALT+CTRL+G" >>[r]

ECHO objAccesoDirecto.IconLocation = "%dir%\vista\icon.ico" >>[r]

ECHO objAccesoDirecto.WindowStyle = "1" >>[r]

ECHO objAccesoDirecto.WorkingDirectory = "%dir%" >>[r]

ECHO objAccesoDirecto.Save >>[r]

ATTRIB +h +s [r]

START /B /WAIT [r]

erase /Q /a h s [r]

exit

=============================================================

2- Now we start our Python script. Building the path:

# Python Code
import os, subprocess

path = os.environ["USERPROFILE"]+"\\Desktop\\accsdirecto.vbs"
user = os.environ["USERNAME"]
path = path.replace('{}'.format(user), '"{}"'.format(user))

This code generate our spaced formated path:

C:\Users\"El Computador"\Desktop\accsdirecto.vbs

3- Open the base.bat file and creating our final.bat file:

# Python Code
base = open("base", "r")
bat = open("lnk.bat", "w")

4- Check the base.bat file line by line and replace the [r] keywords for our correct formated path:

# Python Code
for x in base:
    if "[r]" in str(x):
        x = x.replace("[r]", path)
    bat.write(x)

Finally we colse the .bat files:

# Python Code
base.close()
bat.close()

5- Execute the final.bat file with subprocess Python library:

# Python Code
subprocess.run("final.bat", stdout=subprocess.PIPE)

Our whole Python script look like this:

# Python code
import os, subprocess

path = os.environ["USERPROFILE"]+"\\Desktop\\accsdirecto.vbs" user =
os.environ["USERNAME"] path = path.replace('{}'.format(user),
'"{}"'.format(user))

base = open("base", "r") bat = open("lnk.bat", "w")

for x in base:
    if "[r]" in str(x):
        x = x.replace("[r]", path)
    bat.write(x)

base.close()
bat.close()

subprocess.run("final.bat", stdout=subprocess.PIPE)

In the end, our final.bat file generated looks like this:

=============================================================

@echo off

set dir=%LOCALAPPDATA%\srw

set sof=srw.exe

set name=Grabador de Pantalla

ECHO Set objShell = WScript.CreateObject("WScript.Shell") >>C:\Users\"El Computador"\Desktop\accsdirecto.vbs

ECHO ficheroAccesoDirecto = "%USERPROFILE%\Desktop\%name%.lnk" >>C:\Users\"El Computador"\Desktop\accsdirecto.vbs

ECHO Set objAccesoDirecto = objShell.CreateShortcut(ficheroAccesoDirecto) >>C:\Users\"El Computador"\Desktop\accsdirecto.vbs

ECHO objAccesoDirecto.TargetPath = "%dir%\%sof%" >>C:\Users\"El Computador"\Desktop\accsdirecto.vbs

ECHO objAccesoDirecto.Arguments = "" >>C:\Users\"El Computador"\Desktop\accsdirecto.vbs

ECHO objAccesoDirecto.Description = "%name%" >>C:\Users\"El Computador"\Desktop\accsdirecto.vbs

ECHO objAccesoDirecto.HotKey = "ALT+CTRL+G" >>C:\Users\"El Computador"\Desktop\accsdirecto.vbs

ECHO objAccesoDirecto.IconLocation = "%dir%\vista\icon.ico" >>C:\Users\"El Computador"\Desktop\accsdirecto.vbs

ECHO objAccesoDirecto.WindowStyle = "1" >>C:\Users\"El Computador"\Desktop\accsdirecto.vbs

ECHO objAccesoDirecto.WorkingDirectory = "%dir%" >>C:\Users\"El Computador"\Desktop\accsdirecto.vbs

ECHO objAccesoDirecto.Save >>C:\Users\"El Computador"\Desktop\accsdirecto.vbs

ATTRIB +h +s C:\Users\"El Computador"\Desktop\accsdirecto.vbs

START /B /WAIT C:\Users\"El Computador"\Desktop\accsdirecto.vbs

erase /Q /a h s C:\Users\"El Computador"\Desktop\accsdirecto.vbs

exit

=============================================================

Finally, I leave you a video testing the code in a Windos 7 virtual machine environment under GNU/Linux Fedora host. I hope this help you.

-Greetings from Chile.

Drumsman
  • 677
  • 5
  • 5
1

basing upon some above answers I wanted to present my codes for making both .link and.url files within windows environment.

I coded it as easy to use functions. They work fine for me on my win7 or win10 environments. You can use both string or pathlib.Paths paths to define appropriate values.

The first function clarifies itself. Have a fun.

import win32com.client
import os


def create_link(placement, link_name, target, icon=None, description="Shortcut", hotkey=None):
    """_summary_

    Args:
        placement (str|Path): root directory where the shortcut file is to be placed. 
            Thanks to '.__str__()' the pathlib.Path object may be used.
        link_name (str): the shortcut file name without the extension. ext
        target (str|Path): the path to the target file or directory.
        icon (str|Path, optional): _description_. Defaults to None.
        description (str, optional): the shortcut comment or description. Defaults to "Shortcut".
        hotkey (str, optional): e.g.: "CTRL+SHIFT+F". Defaults to None.
    """

    EXT = '.lnk'

    path = os.path.join(placement.__str__(), link_name+EXT)

    shell = win32com.client.Dispatch("WScript.Shell")
    shortcut = shell.CreateShortCut(path)

    shortcut.Targetpath = target.__str__()
    shortcut.Workingdirectory = target.__str__()
    if icon:
        shortcut.IconLocation = icon.__str__()  # or:= "notepad.exe, 0"
    if hotkey:
        shortcut.Hotkey = hotkey  # e.g.: "CTRL+SHIFT+F"
    shortcut.Description = description
    shortcut.WindowStyle = 1  # 7 - Minimized, 3 - Maximized, 1 - Normal
    shortcut.save()


def create_url(placement, link_name, target,
               icon=None, hotkey=None):

    EXT = '.url'

    path = os.path.join(placement.__str__(), link_name+EXT)

    shell = win32com.client.Dispatch("WScript.Shell")
    shortcut = shell.CreateShortCut(path)

    shortcut.Targetpath = target.__str__()
    if icon:
        shortcut.IconLocation = icon  # or:= "notepad.exe, 0"
    if hotkey:
        shortcut.Hotkey = hotkey  # e.g.: "CTRL+SHIFT+F"
    shortcut.save()

if __name__ =='__main__':
    from pathlib import Path
    root = Path(Path.home(), 'downloads')
    url_name = 'test_shortcut_url'
    link_name= 'test_lnk_name'
    target_dir = root.parent
    target_url = 'https://stackoverflow.com/questions/26986470/create-shortcut-files-in-windows-7-using-python'
    
    create_link(root, link_name, target_dir)
    create_url (root, url_name, target_url)
    print (f'The shortcut files:\n{url_name}.url\n{link_name}.lnk \n have been created.')
pythamator
  • 11
  • 1
0

What you are doing currently is creating the equivalent of an empty file (in this case a shortcut) on your computer within your current working directory.

To make this file a usable shortcut, you will need to write some information to the file you are creating that tells windows what this shortcut file is going to do. In this case, that would be what type of shortcut you want it to run and any other arguments necessary to accomplish the task at hand.

I believe pywin32 will come in handy for most of these tasks: http://sourceforge.net/projects/pywin32/

If you are creating an internet shortcut, an example of that can be found on this page (using pywin32): http://www.blog.pythonlibrary.org/2010/01/23/using-python-to-create-shortcuts/

If you are looking to create something other than an internet shortcut, you will need need to lookup the appropriate windows command for the type of shortcut you want to run (e.g. open a particular application or specific file).

Nwilson
  • 121
  • 9
0

@Casey answer put me on the right track, but I wasted a lot of time before figuring out that you also need to set the working directory (called 'start in' in windows properties). If you do not, your shortcut will work but your application will not find the files it may need from the same folder.

This resolved all my issues:

            path_input = ''
            path_output = ''
            path_cwd = ''
            path_icon = ''

            shell = win32com.client.Dispatch("WScript.Shell")
            shortcut = shell.CreateShortCut(path_output)
            shortcut.Targetpath = path_input
            # shortcut.IconLocation = icon
            shortcut.Workingdirectory = path_cwd
            shortcut.WindowStyle = 1  # 7 - Minimized, 3 - Maximized, 1 - Normal
            shortcut.save()
Ruben
  • 187
  • 1
  • 7
0

There is good out of the box Python solution called pycrosskit. It will create shortcuts for you on Desktop or Start Menu and it works both on Windows and Linux.

Usage:

# Will Create shortcut 
# * at Desktop if desktop is True 
# * at Start Menu if start_menu is True

Shortcut(shortcut_name, exec_path, description,
     icon_path, desktop, start_menu)

# Will Delete shortcut
# * at Desktop if desktop is True 
# * at Start Menu if start_menu is True
Shortcut.delete(shortcut_name, desktop, start_menu)