No More Desktop Shortcuts featured image

No More Desktop Shortcuts

October 3, 2021

I like having a clean desktop. Whenever I install a new application on my Windows computer, I always uncheck the "Create a Desktop Shortcut" checkbox.

Unfortunately, if you install an app on Windows for "All Users" and you select to not have a shortcut show up on your desktop, some apps will still install a shortcut on the CommonDesktopDirectory, which is a place where all users can see shortcuts (C:\Users\Public\Desktop). Or, the app will create a shortcut in that CommonDesktopDirectory when it upgrades, which is what was happening to me.

This can get annoying. Let's do something about it.

Planning the App

First, we need a plan. This is pretty simple:

  1. On startup, search for any shortcuts on the common desktop directory.
  2. If any are found, move them to the Recycle Bin.
  3. In case something goes wrong, let's keep a log of what happened.

Searching for Shortcuts

On Windows, shortcut files have a file extension of .lnk (can be upper or lower case). So we'll be searching for files with that ending.

Where should we be looking for these files? If you ran into what I ran into with the CommonDesktopDirectory issue, the directory is most-likely:

C:\Users\Public\Desktop

Move Shortcuts to the Recycle Bin

Just in case something goes wrong and we delete something that we actually wanted to keep, we'll want to recover it. Putting the shortcut in the Recycle Bin allows us to undo something we didn't mean to do.

How do we move a shortcut to the Recycle Bin? It's not as easy as using fs.unlink in node.js, because that actually deletes the file permanently.

Luckily, there's an npm package called trash written and maintained by Sindre Sorhus which handles this for us (and is cross-platform, too).

Keep a Log

We'll be using Winston to log when this app runs and what it does (or fails to do). The logs will be stored in the same directory as the app folder.

Run on Startup

Windows will run a batch file on startup when it is in the Startup directory. To find out where this directory is for your profile, hit the WindowsKey+r, then type in shell:startup and press OK. The File Explorer will pop up with the directory you need to create the batch file in.

The Code

Note, I'm using node.js v16. Also, in my package.json file, I am using "type": "module" to use ECMAScript module syntax (reference).

// index.js

import * as fs from 'fs/promises';
import * as path from 'path';
import { fileURLToPath } from 'url';
import trash from 'trash';
import createLog from './logger.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

process.chdir(__dirname);

const logger = createLog();
const startPath = 'C:\\Users\\Public\\Desktop';
const files = await fs.readdir(startPath);

files.forEach(async (file) => {
  const filename = path.join(startPath, file);

  try {
    const stat = await fs.lstat(filename);
    if (stat.isFile && filename.toLowerCase().endsWith('.lnk')) {
      logger.info(`Moving file to recycle bin: ${filename}`);
      trash(filename);
    }
  } catch (error) {
    logger.error(`Error moving file to recycle bin: ${filename}`);
    logger.error(error);
  }
});

And here's the logger file:

// logger.js
import pkg from 'winston';
const { createLogger, format, transports } = pkg;

export default () => {
  const logger = createLogger({
      level: 'info',
      format: format.combine(
        format.timestamp({
          format: 'YYYY-MM-DD HH:mm:ss'
        }),
        format.errors({ stack: true }),
        format.splat(),
        format.json()
      ),
      defaultMeta: { service: 'shortcut-killer' },
      transports: [
        new transports.File({ filename: 'error.log', level: 'error' }),
        new transports.File({ filename: 'combined.log' })
      ]
    });

    if (process.env.NODE_ENV !== 'production') {
      logger.add(new transports.Console({
        format: format.combine(
          format.colorize(),
          format.simple()
        )
      }));
    }

    return logger;
};

If you're wondering about this part in index.js:

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

process.chdir(__dirname);

It's because __filename and __dirname are no longer available when using ECMAScript modules, so we need to create them ourselves. The reason I needed to change the working directory was for the logger to put the logs where the app lives (rather than in the context of the executing app, which could be the Windows Startup context).

Host the App

After putting this app together. I copied the entire contents to a new directory on my machine C:\Startup_Apps. The reason for this is because if I want to make a change to the app, I can have a work-in-progress in my development directory and not affect the "production" version, which the batch file refers to.

Batch File for Startup

Now we need a batch file to start this app at startup.

Here's the batch script for the app (adjust for your path names):

set NODE_ENV=production&& "C:\[path_to_node]\node.exe" "C:\Startup_Apps\[app_name_dir]\index.js"

One important note, when setting the NODE_ENV variable in a batch script, the && must not have a space before it (so what you see above is not a typo).

Host this .bat file in your Startup directory (WindowsKey+r, shell:startup).

Note: run this code at your own risk.

Conclusion

And with that, we're done. No more desktop shortcuts on the CommonDesktopDirectory. If you use a computer that is used by others, this might not be the solution for you, but for me, I'm the only person using this computer so it's no big deal.