Crear accesos directos con Windows Script Host en Windows

  • WSH permite crear accesos directos .lnk y .url con WScript.Shell y SpecialFolders.
  • Ejemplos prácticos en Visual FoxPro, VB/VBA y PowerShell para despliegues.
  • Estrategia MSIX+PSF con AppExecutionAlias para rutas estables sin versión.

accesos directos con Windows Script Host

Si trabajas en Windows y necesitas automatizar tareas, crear accesos directos con Windows Script Host (WSH) es un recurso rapidísimo y fiable. Con unos pocos objetos COM y líneas de código puedes generar .lnk y .url, controlar iconos, atajos de teclado, estilos de ventana, argumentos e incluso carpetas especiales del sistema.

En esta guía práctica vamos a reunir, unificar y ampliar lo mejor de varios enfoques reales: desde Visual FoxPro y VB/VBA hasta PowerShell, y también escenarios modernos con paquetes MSIX y PSF usando AppExecutionAlias. Verás ejemplos completos, trucos, advertencias de compatibilidad y soluciones a errores típicos en scripts de despliegue.

¿Qué es Windows Script Host y por qué usarlo?

Windows Script Host (WSH) es la infraestructura de scripting de Microsoft que ejecuta VBScript y JScript de forma nativa en Windows, con acceso a métodos COM para automatizar el sistema. Está integrado desde Windows 98/2000 y puede añadirse en Windows NT 4.0 mediante el Paquete de Opciones, por lo que sigue siendo útil en entornos actuales y heredados.

comandos para diagnosticar problemas windows 11
Artículo relacionado:
Comandos para diagnosticar problemas en Windows 11

La clase más utilizada para accesos directos es WScript.Shell, que expone métodos como CreateShortcut, Run, Exec, Popup, SendKeys, LogEvent, Sleep y la colección SpecialFolders. A través de ella puedes: crear .lnk y .url, leer carpetas especiales (Escritorio, Programas, Favoritos…), lanzar procesos y más.

Compatibilidad, requisitos y contexto

WSH ejecuta scripts VBScript/JScript y permite automatizar con COM desde diversos lenguajes, como Visual FoxPro, VB6/VBA o PowerShell (este último a través de New-Object -ComObject). En sistemas antiguos (Windows 95/NT 4.0) puede requerir instalación adicional, mientras que en versiones modernas viene integrado de serie.

Además de WScript.Shell, en muchos escenarios puedes complementar con WshNetwork (CreateObject(«WScript.Network»)) para impresoras, unidades de red y otras operaciones; y con APIs de shell32 (SHGetSpecialFolderLocation/SHGetPathFromIDList) en VB para resolver rutas especiales con precisión.

Crear accesos directos con WScript.Shell: patrón general

accesos directos con Windows Script Host

El patrón base para un acceso directo es siempre el mismo: instancias el objeto, obtienes la ruta de destino (por ejemplo, el Escritorio) y llamas a CreateShortcut. Luego configuras propiedades como TargetPath, Arguments, IconLocation, Hotkey y WorkingDirectory, y finalmente guardas con .Save().

Este patrón se replica en VBScript, PowerShell, VB/VBA y Visual FoxPro. La colección SpecialFolders(«Desktop») te da la ruta del escritorio del usuario. También puedes apuntar al Escritorio público si necesitas un acceso directo para todos los perfiles.

Ejemplos rápidos con Visual FoxPro (WSH)

Desde Visual FoxPro puedes utilizar COM para hablar con WSH y crear accesos directos en el Escritorio. Los siguientes ejemplos muestran variantes típicas: un acceso directo simple, otro con argumentos y un enlace .URL.

Ejemplo 1: acceso directo básico maximizado con icono y hotkey

WshShell = CreateObject("WScript.Shell")
strDesktop = WshShell.SpecialFolders("Desktop")
oMyShortcut = WshShell.CreateShortcut(strDesktop + "\\Sample.lnk")

* 3=Maximizado, 7=Minimizado, 4=Normal
oMyShortcut.WindowStyle = 3

* Icono personalizado
oMyShortcut.IconLocation = "C:\\myicon.ico"

* Ejecutable de destino
oMyShortcut.TargetPath = "%windir%\\notepad.exe"

* Atajo de teclado Alt+Ctrl+F
oMyShortcut.Hotkey = "ALT+CTRL+F"

* Guardar el .lnk
oMyShortcut.Save

Este patrón combina la ruta especial del Escritorio con TargetPath y opciones visuales (estilo de ventana e icono), de modo que el acceso directo queda listo con una hotkey global.

Ejemplo 2: acceso directo con argumentos y directorio de trabajo

WshShell = CreateObject("WScript.Shell")
strDesktop = WshShell.SpecialFolders("Desktop")
oMyShortCut = WshShell.CreateShortcut(strDesktop + "\\Foxtest.lnk")

* 7=Minimizado, 0=Maximizado (ojo con la convención), 4=Normal
oMyShortCut.WindowStyle = 7

* Icono desde una ruta específica (ej. recursos del IDE)
oMyShortCut.IconLocation = HOME() + "wizards\\graphics\\builder.ico"

* Ejecutable de destino (ej. VFP)
oMyShortCut.TargetPath = "C:\\Program Files\\Microsoft Visual Studio\\VFP98\\vfp6.exe"

* Argumentos de línea de comandos
oMyShortCut.Arguments = '-c' + '"' + HOME() + 'config.fpw' + '"'

* Directorio de trabajo
oMyShortCut.WorkingDirectory = "C:\\"

* Guardar el .lnk
oMyShortCut.Save

La clave aquí es combinar TargetPath, Arguments y WorkingDirectory para abrir aplicaciones con parámetros, algo muy útil en herramientas de desarrollo o lanzadores.

  Tutoriales sobre el comando dxdiag

Ejemplo 3: enlace a una URL en el Escritorio

WshShell = CreateObject("WScript.Shell")
strDesktop = WshShell.SpecialFolders("Desktop")
oUrlLink = WshShell.CreateShortcut(strDesktop + "\\Microsoft Web Site.URL")

oUrlLink.TargetPath = "http://www.microsoft.com"

oUrlLink.Save

Para accesos a sitios web basta con crear un archivo .URL apuntando a la dirección; es rápido y muy ligero para recursos corporativos.

Rutas especiales con VB6/VBA y APIs de shell32

En proyectos VB puedes crear una interfaz para listar carpetas especiales de Windows y elegir dónde guardar el acceso directo. Los ejemplos clásicos usan SHGetSpecialFolderLocation y SHGetPathFromIDList de shell32.dll para resolver rutas de Escritorio, Programas, Favoritos, Inicio, Documentos recientes y más.

Entre los identificadores más utilizados están: CSIDL_DESKTOP, CSIDL_PROGRAMS, CSIDL_PERSONAL, CSIDL_FAVORITES, CSIDL_STARTUP, CSIDL_RECENT, CSIDL_STARTMENU, CSIDL_COMMON_STARTMENU, CSIDL_COMMON_PROGRAMS, CSIDL_COMMON_STARTUP y CSIDL_COMMON_FAVORITES. Con ellos llenas un ComboBox y el usuario elige el destino antes de crear el .lnk.

Una vez resuelta la ruta, el patrón es el mismo: con CreateObject(«WScript.Shell») y .CreateShortcut construyes el acceso directo, asignas .TargetPath (por ejemplo, App.Path & «\\» & App.EXEName) y llamas a .Save para finalizar el proceso.

Plantilla avanzada en VBA: descripción, icono, hotkey y estilo

En aplicaciones Office/Access, un procedimiento en VBA puede generar accesos directos completos con TargetPath, Arguments, IconLocation, Description, Hotkey y estilo de ventana. Es una base muy flexible para crear lanzadores corporativos.

Dim wshShell As Object ' IWshShell3 (late binding)
Dim wshShortcut As Object ' IWshShortcut
Dim strFolderShortcut As String
Dim strTargetPath As String

Set wshShell = CreateObject("WScript.Shell")
strFolderShortcut = wshShell.SpecialFolders("Desktop") & "\\" & strShortcutName & ".lnk"

' Si existe un acceso anterior, eliminarlo para recrearlo con nuevos parámetros
If Not Dir(strFolderShortcut, vbNormal) = "" Then Kill (strFolderShortcut)

' Construir el destino uniendo WorkingDirectory + FileName
strTargetPath = strWorkingDirectory & IIf(Right(strWorkingDirectory, 1) = "\\", Null, "\\") & strFileName

' Validación básica cuando no se usan variables de entorno
If Not (Left(strTargetPath, 1) = "%") And Dir(strTargetPath, vbArchive) = "" Then
    MsgBox "El programa de destino no existe en: " & strTargetPath, vbCritical
Else
    Set wshShortcut = wshShell.CreateShortcut(strFolderShortcut)
    With wshShortcut
        .TargetPath = strTargetPath
        If Not strArguments = "" Then .Arguments = strArguments
        If Not strIconLocation = "" Then .IconLocation = strIconLocation
        .WorkingDirectory = strWorkingDirectory
        ' 3=Maximizado, 7=Minimizado, 4=Normal
        .WindowStyle = IIf(bytWindowsStyle = 0, 3, bytWindowsStyle)
        If Not strDescription = "" Then .Description = strDescription
        If Not strHotkey = "" Then .Hotkey = "ALT+CTRL+" & strHotkey
        .Save
    End With
End If

Set wshShortcut = Nothing
Set wshShell = Nothing

Con este enfoque puedes crear accesos directos «de catálogo» para aplicaciones propias o de terceros, ajustando iconos, argumentos y hotkeys sin depender de instaladores.

Crear accesos directos con PowerShell (WSH vía COM)

accesos directos con Windows Script Host

PowerShell es ideal para despliegues en masa (por ejemplo, con Intune) aprovechando New-Object -ComObject WScript.Shell. Así combinamos la potencia de WSH con la distribución moderna y el control de permisos.

Un caso típico: crear una carpeta «SharePoint Shortcuts» en el Escritorio del usuario y añadir accesos a aplicaciones o URLs. Con WScript.Shell puedes configurar TargetPath, Arguments, IconLocation y WorkingDirectory como harías en VBScript.

Errores típicos y cómo arreglarlos en un script real

En un script real de Intune detectamos varios problemas habituales: variables no inicializadas (por ejemplo, $DesktopDir sin asignación a nivel de script), parámetros no declarados (se usa $ShortcutArguments pero la función Add-Shortcut no lo recibe), discrepancias en nombres de carpeta («Sharepoint» vs «SharePoint») y rutas sin comillas cuando contienen espacios.

Solución rápida: devolver Get-DesktopDir a una variable global o de script, pasar $DesktopDir como argumento a las funciones que lo usan, añadir el parámetro $ShortcutArguments a Add-Shortcut, normalizar el nombre de la carpeta y usar Join-Path y comillas adecuadamente.

comandos para reparar problemas en Windows 11
Artículo relacionado:
Los mejores comandos para diagnosticar y reparar problemas en Windows 11

Script PowerShell corregido y robusto

[CmdletBinding()]
Param(
  [Parameter(Mandatory=$true)] [String]$ShortcutTargetPath,
  [Parameter(Mandatory=$true)] [String]$ShortcutDisplayName,
  [Parameter(Mandatory=$false)] [Switch]$PinToStart=$false,
  [Parameter(Mandatory=$false)] [String]$IconFile=$null,
  [Parameter(Mandatory=$false)] [String]$ShortcutArguments=$null,
  [Parameter(Mandatory=$false)] [String]$WorkingDirectory=$null
)

function Test-RunningAsSystem {
  try { return ( (whoami -user) -match "S-1-5-18" ) } catch { return $false }
}

function Get-DesktopDir {
  if (Test-RunningAsSystem) { Join-Path -Path $env:PUBLIC -ChildPath "Desktop" }
  else { [Environment]::GetFolderPath("Desktop") }
}

function Ensure-DesktopFolder([string]$DesktopDir,[string]$FolderName) {
  $target = Join-Path $DesktopDir $FolderName
  if (-not (Test-Path -LiteralPath $target)) {
    New-Item -Path $target -ItemType Directory -Force | Out-Null
  }
  return $target
}

function Add-Shortcut {
  param(
    [Parameter(Mandatory)] [String]$ShortcutTargetPath,
    [Parameter(Mandatory)] [String]$DestinationPath,
    [Parameter()] [String]$WorkingDirectory,
    [Parameter()] [String]$ShortcutArguments,
    [Parameter()] [String]$IconFile
  )
  $WshShell = New-Object -ComObject WScript.Shell
  $Shortcut = $WshShell.CreateShortcut($DestinationPath)
  $Shortcut.TargetPath = $ShortcutTargetPath
  if ($ShortcutArguments) { $Shortcut.Arguments = $ShortcutArguments }
  if ($WorkingDirectory) { $Shortcut.WorkingDirectory = $WorkingDirectory }
  if ($IconFile) { $Shortcut.IconLocation = $IconFile }
  $Shortcut.Save()
  [Runtime.InteropServices.Marshal]::ReleaseComObject($WshShell) | Out-Null
}

function Get-StartDir {
  if (Test-RunningAsSystem) {
    Join-Path $env:ALLUSERSPROFILE "Microsoft\\Windows\\Start Menu\\Programs"
  } else {
    Join-Path ([Environment]::GetFolderPath("StartMenu")) "Programs"
  }
}

# 1) Determinar Escritorio
$DesktopDir = Get-DesktopDir

# 2) Asegurar carpeta destino coherente
$folderName = "SharePoint Shortcuts"
$ShortcutFolder = Ensure-DesktopFolder -DesktopDir $DesktopDir -FolderName $folderName

# 3) Crear acceso directo en el escritorio
$destinationPath = Join-Path -Path $ShortcutFolder -ChildPath ("{0}.lnk" -f $ShortcutDisplayName)
Add-Shortcut -DestinationPath $destinationPath -ShortcutTargetPath $ShortcutTargetPath -WorkingDirectory $WorkingDirectory -ShortcutArguments $ShortcutArguments -IconFile $IconFile

# 4) (Opcional) Crear entrada en el Menú Inicio
if ($PinToStart.IsPresent) {
  $startDest = Join-Path -Path (Get-StartDir) -ChildPath ("{0}.lnk" -f $ShortcutDisplayName)
  Add-Shortcut -DestinationPath $startDest -ShortcutTargetPath $ShortcutTargetPath -WorkingDirectory $WorkingDirectory -ShortcutArguments $ShortcutArguments -IconFile $IconFile
}

Con este guion puedes invocar algo como: .\u200bCreateDesktopIcon.ps1 -ShortcutTargetPath «%ProgramFiles(x86)%\Microsoft\Edge\Application\msedge.exe» -ShortcutDisplayName «Carpetas de Archivo» -IconFile «%systemroot%\System32\SHELL32.dll,13» -ShortcutArguments «https://tenant.sharepoint.com/sites/archive/Archive%20Folders».

  Windows 11 va lento: causas, diagnóstico y soluciones reales

Generar un .lnk «al vuelo» con PowerShell (sin copiar archivos)

Si no quieres desplegar un .lnk prehecho, basta con crearlo en tiempo de ejecución mediante WScript.Shell. Ejemplo mínimo para el Escritorio público:

$shell = New-Object -ComObject WScript.Shell
$lnk = $shell.CreateShortcut("$env:PUBLIC\Desktop\Internet Explorer.lnk")
$lnk.TargetPath = "$env:ProgramFiles\Internet Explorer\iexplore.exe"
$lnk.IconLocation = "$env:SystemRoot\System32\SHELL32.dll,220"
$lnk.WorkingDirectory = "$env:ProgramFiles\Internet Explorer"
$lnk.Save()
[Runtime.InteropServices.Marshal]::ReleaseComObject($shell) | Out-Null

El valor de IconLocation admite dll,ico e índices; si el ejecutable no existe en el equipo, revisa rutas y sustitutos (por ejemplo, Edge). Este patrón sirve para cualquier aplicación corporativa.

MSIX + PSF: crear accesos directos con AppExecutionAlias

En aplicaciones empacadas con MSIX puedes evitar rutas con números de versión usando AppExecutionAlias. La idea es definir un alias en el manifiesto y crear el acceso directo apuntando a ese alias (por ejemplo, contosoexpenses.exe), de modo que no dependas de la ruta con versión dentro de WindowsApps.

Paso 1. Agrega espacios de nombres al manifiesto de la app: uap3 y desktop:

xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"

Paso 2. Decláralos como ignorables en IgnorableNamespaces: «uap uap3 desktop rescap build» para evitar warnings durante la validación.

Paso 3. Define la extensión del alias de ejecución tras el bloque VisualElements:

<Extensions>
  <uap3:Extension Category="windows.appExecutionAlias" Executable="ContosoExpenses\ContosoExpenses.exe" EntryPoint="Windows.FullTrustApplication">
    <uap3:AppExecutionAlias>
      <desktop:ExecutionAlias Alias="contosoexpenses.exe" />
    </uap3:AppExecutionAlias>
  </uap3:Extension>
</Extensions>

Tras guardar y cerrar el manifiesto, vuelve a generar e instalar el paquete y lanza la app con el alias (por ejemplo, Win+R y escribir contosoexpenses) para validar que todo funciona.

Paso 4. Crea el acceso directo usando el alias y ajusta icono y propiedades. Para que el icono no dependa de la carpeta versionada de WindowsApps, puedes copiar el .ico a %localappdata%\Packages\{PackageId}\LocalCache\Roaming y referenciarlo desde ahí.

Paso 5. Integra PSF en el paquete (PSFBinaries.zip) y, si procede, cambia el ejecutable del manifiesto al lanzador de PSF (por ejemplo, PSFLauncher32.exe):

<Application Executable="PSFLauncher32.exe" EntryPoint="Windows.FullTrustApplication">

Paso 6. Crea config.json en la raíz del paquete para ejecutar un script la primera vez que se inicie la app (por ejemplo, para copiar el .lnk y el .ico al Escritorio y AppData):

{
  "applications": [
    {
      "id": "App",
      "executable": "ContosoExpenses\\ContosoExpenses.exe",
      "workingDirectory": "ContosoExpenses\\",
      "startScript": {
        "scriptPath": "createshortcut.ps1",
        "runInVirtualEnvironment": false,
        "waitForScriptToFinish": true,
        "showWindow": false,
        "runOnce": true
      }
    }
  ]
}

Paso 7. Script PowerShell de apoyo (copiar el .lnk y el icono al usuario):

Copy-Item "Contoso Expenses.lnk" "$env:USERPROFILE\Desktop\Contoso Expenses.lnk"
Copy-Item "contoso.ico" "$env:APPDATA\contoso.ico"

Incluye en la carpeta de la app dentro del paquete: Contoso Expenses.lnk, Contoso.ico, StartingScriptWrapper.ps1 y createshortcut.ps1. Así, en la primera inicialización se crea el acceso directo en el Escritorio del usuario con el icono resuelto desde AppData.

  Qué es el programa ESU en Windows 10 del que tanto se habla

Más cosas útiles de WSH Shell y WshNetwork

WSH no se limita a accesos directos. Con la clase Shell puedes usar AppActivate, Run, Exec, LogEvent, Popup, SendKeys, SpecialFolders o Sleep para automatizar tareas. Y con WshNetwork, mapear unidades, gestionar impresoras o enumerar conexiones de red.

Entre prácticas habituales que puedes implementar: EnumPrinterConnections, AddWindowsPrinterConnection, RemovePrinterConnection, MapNetworkDrive, RemoveNetworkDrive, EnumNetworkDrives; abrir diálogos de selección de carpeta; leer y escribir en el Registro (RegRead, RegWrite, RegDelete) para inicializar programas con el sistema o crear asociaciones de archivo; obtener datos como la velocidad del procesador del Registro; o capturar la salida de comandos de DOS a tu aplicación.

Recuerda que algunos métodos requieren permisos elevados y que no todas las variantes de Shell están presentes en todos los Windows o contextos bloqueados. Por seguridad, valida entradas y evita ejecutar comandos arbitrarios provenientes de usuarios no confiables.

Mensajes temporizados y otras utilidades rápidas

Además de accesos directos, con WSH puedes mostrar mensajes temporizados mediante Popup, algo útil para guiones de instalación o notificaciones breves a usuarios; y controlar ventanas con AppActivate o SendKeys cuando no exista otra API disponible.

Estos pequeños recursos ahorran tiempo en scripts de soporte, sin necesidad de compilar utilidades ad hoc; y están disponibles tanto desde VBScript/JScript como desde PowerShell a través de COM.

Buenas prácticas al crear accesos directos en Windows Script Host

Antes de escribir, define si el acceso directo va al Escritorio del usuario o al público. Usa siempre SpecialFolders o APIs para resolver rutas. Cita rutas con espacios, emplea Join-Path en PowerShell y valida que el destino existe (o usa variables de entorno como %windir% y %systemroot%).

Si el icono depende de archivos dentro de paquetes versionados (MSIX), ubícalo en ubicaciones sin versión como %localappdata%\Packages\{PackageId}\LocalCache\Roaming. Y si despliegas con Intune, prueba el script como SYSTEM y como usuario final para detectar diferencias de rutas y permisos.

Solución de problemas frecuente

Si el .lnk no aparece, comprueba que .Save() realmente se ejecuta, que la carpeta de destino existe, que las rutas están entre comillas y que IconLocation apunta a un recurso válido. En PowerShell, libera el objeto COM si lo necesitas para evitar bloqueos de archivo.

Si usas MSIX/PSF y el acceso directo no funciona, valida el alias con Win+R, revisa IgnorableNamespaces y la extensión windows.appExecutionAlias, y confirma que PSFLauncher32.exe (o 64) está correctamente referenciado en el manifiesto de la app.

Controlar Procesos y Servicios con CMD Comandos Taskkill y Sc
Artículo relacionado:
Controlar Procesos y Servicios con CMD: Comandos Taskkill y Sc

Con este recorrido ya puedes crear accesos directos sólidos en cualquier entorno Windows: VFP, VB/VBA, PowerShell o MSIX/PSF. Elige la técnica que mejor encaje en tu proyecto, cuida rutas e iconos y, sobre todo, automatiza con cabeza para no llenar el Escritorio de accesos innecesarios. Comparte este tutorial y más usuarios sabrán sobre Windows Script Host.