Crear accesos directos con Windows Script Host

  • WSH y PowerShell permiten crear accesos .lnk y .url con iconos, argumentos y carpetas de trabajo.
  • SpecialFolders y la API de shell resuelven Escritorio, Inicio y otras rutas especiales del sistema.
  • PowerShell accede a COM (.WScript.Shell) y .NET (EventLog) para automatizar sin depender de cmdlets.
  • En despliegues (Intune), cuida el scope de variables y permisos para que los accesos se creen bien.

Windows Script Host

Si trabajas a diario en Windows, crear accesos directos bien configurados te ahorra muchísimos clics y quebraderos de cabeza. Con Windows Script Host (WSH) y PowerShell puedes automatizar la creación de accesos directos de escritorio, del menú Inicio o incluso a URL, con iconos personalizados, argumentos y carpetas de trabajo. En este artículo recopilo y reescribo, con un enfoque práctico, todo lo necesario para lograrlo apoyándome en ejemplos reales de VBScript, Visual FoxPro y PowerShell.

Para contextualizar, Microsoft documentó desde hace años esta capacidad en su base de conocimiento (KB 244677) explicando cómo generar accesos directos de escritorio con WSH y ampliando el modelo de objetos disponible. Además, veremos cómo aprovechar New-Object en PowerShell para manejar objetos .NET y COM (incluido WSH), y cómo esquivar algunas limitaciones de cmdlets en remoto con clases .NET como System.Diagnostics.EventLog.

¿Qué es Windows Script Host (WSH) y en qué sistemas funciona?

Windows Script Host es la infraestructura de Microsoft que permite ejecutar scripts de VBScript y JScript de forma nativa en Windows. Integra un modelo de objetos accesible vía COM (por ejemplo, el célebre WScript.Shell) con el que puedes lanzar aplicaciones, manipular archivos, leer el Registro, abrir cuadros de diálogo y, por supuesto, crear accesos directos.

A nivel de compatibilidad, WSH se integró de serie en Windows 98, Windows 2000 y versiones posteriores. Para Windows NT 4.0 se podía instalar como parte del «Windows NT 4.0 Option Pack». En su día, Microsoft centralizaba la descarga y documentación en el sitio de Scripting, pero hoy en Windows modernos lo tienes ya disponible sin pasos extra.

En contextos prácticos, WSH brilla porque reduce a unas pocas líneas tareas que, manualmente, serían tediosas. Con sus objetos (Shell, Network, FileSystemObject) y carpetas especiales bien definidas, puedes dejar automatizadas acciones comunes de administración y despliegue de software.

Métodos y propiedades clave de WshShell para accesos directos

La clase más usada es WScript.Shell. Con ella crearás el acceso directo y ajustarás sus propiedades. Entre sus métodos prácticos destacan:

  • CreateShortcut: genera un .lnk (o .url) en la ruta que le indiques.
  • Run y Exec: ejecutan comandos y procesos, esperando o no a su finalización.
  • AppActivate y SendKeys: útiles para automatizar ventanas y pulsaciones.
  • Popup y LogEvent: muestran mensajes o escriben en el registro de eventos.
  • SpecialFolders: devuelve rutas de carpetas especiales (Escritorio, Favoritos, etc.).
  • Sleep: pausa la ejecución el tiempo indicado.

Además, expone propiedades como CurrentDirectory (directorio actual), Environment (variables de entorno) y la colección SpecialFolders (solo lectura, con rutas de sistema predefinidas). Estas APIs se usan igual tanto desde VBScript como desde lenguajes que creen objetos COM (por ejemplo, PowerShell con New-Object -ComObject).

Crear accesos directos con WSH en la práctica

La idea base es simple: creas el objeto WScript.Shell, calculas la ruta donde se guardará el .lnk (normalmente el Escritorio del usuario o el Escritorio público) y llamas a CreateShortcut. Después configuras propiedades del acceso directo como TargetPath (destino), Arguments (argumentos), IconLocation (icono), WorkingDirectory (carpeta de trabajo) y guardas con Save().

Ejemplos en Visual FoxPro (vía COM WScript.Shell)

Estos ejemplos, documentados históricamente para Visual FoxPro, demuestran lo poco que necesitas para producir un .lnk funcional con WSH. En todos ellos se usa la colección SpecialFolders(‘Desktop’) para localizar el Escritorio del usuario actual.

Ejemplo 1: acceso directo básico

WshShell = CreateObject("Wscript.shell")
strDesktop = WshShell.SpecialFolders("Desktop")
oMyShortcut = WshShell.CreateShortcut(strDesktop + \\ "Sample.lnk")
oMyShortcut.WindowStyle = 3  && 3=Maximizada, 7=Minimizada, 4=Normal
oMyShortcut.IconLocation = "C:\\myicon.ico"
oMyShortcut.TargetPath = "%windir%\\notepad.exe"
oMyShortCut.Hotkey = "ALT+CTRL+F"
oMyShortCut.Save

En este bloque se fijan estilo de ventana, icono, destino y atajo de teclado, todo de una tacada. Observa que el destino admite variables de entorno como %windir%.

Ejemplo 2: añadir argumentos de línea de comandos

WshShell = CreateObject("WScript.Shell")
strDesktop = WshShell.SpecialFolders("Desktop")
oMyShortCut = WshShell.CreateShortcut(strDesktop + \\ "Foxtest.lnk")
oMyShortCut.WindowStyle = 7  && 7=Minimizada, 0=Maximizada, 4=Normal
oMyShortcut.IconLocation = home() + "wizards\\graphics\\builder.ico"
oMyShortCut.TargetPath = "c:\\Program Files\\Microsoft Visual Studio\\VFP98\\vfp6.exe"
oMyShortCut.Arguments = "-c " + """ " + Home() + "config.fpw" + """
oMyShortCut.WorkingDirectory = "c:\\"
oMyShortCut.Save

Además del destino, aquí se pasa una cadena de argumentos y se establece la carpeta de trabajo. También se muestra cómo formar correctamente comillas dentro de la línea de argumentos.

Ejemplo 3: acceso directo a una URL

WshShell = CreateObject("WScript.Shell")
strDesktop = WshShell.SpecialFolders("Desktop")
oUrlLink = WshShell.CreateShortcut(strDesktop + \\ "Microsoft Web Site.URL")
oUrlLink.TargetPath = "http://www.microsoft.com"
oUrlLink.Save

Si estableces como TargetPath una dirección http(s), WSH genera un archivo .url que el navegador predeterminado abrirá directamente.

Ejemplo en Visual Basic 6: localizar carpetas especiales y crear el .lnk

Crear accesos directos con Windows Script Host

Otro enfoque clásico consistía en resolver las carpetas especiales con la API de shell (SHGetSpecialFolderLocation y SHGetPathFromIDList) y después invocar CreateObject(‘WScript.Shell’). Este patrón es útil si quieres listar opciones como Escritorio, Programas, Favoritos, Inicio, etc., y dejar que el usuario elija dónde guardar el acceso directo.

' Declaraciones resumidas (VB6)
Private Const CSIDL_DESKTOP = &H0
Private Const CSIDL_PROGRAMS = &H2
Private Const CSIDL_FAVORITES = &H6
Private Const CSIDL_STARTUP = &H7
Private Const CSIDL_RECENT = &H8
Private Const CSIDL_STARTMENU = &HB
Private Declare Function SHGetSpecialFolderLocation Lib "shell32.dll" _
(ByVal hwndOwner As Long, ByVal nFolder As Long, pidl As ITEMIDLIST) As Long
Private Declare Function SHGetPathFromIDList Lib "shell32.dll" Alias "SHGetPathFromIDListA" _
(ByVal pidl As Long, ByVal pszPath As String) As Long

' Uso de WScript.Shell para crear el acceso directo en la ruta elegida
Set obj = CreateObject("WScript.Shell")
Set acceso_directo = obj.CreateShortcut(Combo1 & "\\" & Text1)
With acceso_directo
  .TargetPath = App.Path & "\\" & App.EXEName
  .Save
End With
Set obj = Nothing

Esta muestra combina resolución de rutas especiales con la creación del .lnk. En la interfaz sugerida se ofrecía una lista con varias rutas del sistema (Escritorio, Programas, Favoritos, etc.) y un cuadro de texto para el nombre del acceso directo.

PowerShell: crear accesos directos con COM y depurar un caso real de Intune

PowerShell permite acceder a COM igual que VBScript, pero con sintaxis moderna. Lo normal es crear el objeto WScript.Shell con New-Object y llamar a CreateShortcut. Es un enfoque sencillo y compatible con todos los Windows modernos.

Crear un .lnk en el Escritorio del usuario

$WshShell = New-Object -ComObject WScript.Shell
$lnk = $WshShell.CreateShortcut("$HOME\\Desktop\\PSHome.lnk")
$lnk.TargetPath = $PSHome
$lnk.Save()

Ten en cuenta la diferencia entre comillas simples y dobles: con dobles, PowerShell interpela variables. Por ejemplo: «$HOME\\Desktop» produce la ruta completa, mientras que ‘$HOME\\Desktop’ mantiene el literal sin expandir.

Usar New-Object con .NET y COM

# Crear referencias .NET
New-Object -TypeName System.Diagnostics.EventLog
New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application

# Crear WSH y otros objetos COM
New-Object -ComObject WScript.Shell
New-Object -ComObject WScript.Network
New-Object -ComObject Scripting.Dictionary
New-Object -ComObject Scripting.FileSystemObject

Estas líneas muestran cómo PowerShell puede trabajar tanto con clases .NET (para superar límites de algunos cmdlets en remoto) como con objetos COM (para tareas como crear accesos directos).

Escenario real con Intune: crear accesos en una carpeta del Escritorio

Un caso frecuente de despliegue con Intune consiste en generar accesos directos dentro de una carpeta específica del Escritorio de cada usuario y, opcionalmente, anclarla al Acceso rápido. A continuación tienes un guion representativo (resumido) con funciones auxiliares, detección de si el proceso corre como SYSTEM y resolución de las rutas adecuadas para Escritorio y Menú Inicio:

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

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

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

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

# Preparar la carpeta contenedora en el Escritorio
$DesktopDir = Get-DesktopDir
$ShortcutsFolder = Join-Path $DesktopDir "SharePoint Shortcuts"
if (-not (Test-Path $ShortcutsFolder)) { New-Item -Path $ShortcutsFolder -ItemType Directory | Out-Null }

# Crear el acceso directo
$destinationPath = Join-Path $ShortcutsFolder "$ShortcutDisplayName.lnk"
Add-Shortcut -DestinationPath $destinationPath -ShortcutTargetPath $ShortcutTargetPath -WorkingDirectory $WorkingDirectory

# (Opcional) Crear entrada en el Menú Inicio (Programas)
if ($PinToStart.IsPresent) {
  $destinationPath = Join-Path (Get-StartDir) "$ShortcutDisplayName.lnk"
  Add-Shortcut -DestinationPath $destinationPath -ShortcutTargetPath $ShortcutTargetPath -WorkingDirectory $WorkingDirectory
}

En varios guiones reales he visto errores típicos: no capturar el valor de Get-DesktopDir en una variable (se llamaba sin asignación y luego se referenciaba $DesktopDir esperando que el propio método la estableciera), inconsistencias en el nombre de la carpeta (Sharepoint vs SharePoint) o uso de una variable $ShortcutArguments sin declararla como parámetro de Add-Shortcut. Con el patrón anterior, el scope queda claro y todo fluye.

Accesos directos de URL, iconos, argumentos y otras propiedades

Con WSH se controlan muchas propiedades del acceso directo. Las más habituales son TargetPath (ruta al ejecutable o URL), Arguments (parámetros de línea de comandos), WorkingDirectory (carpeta de trabajo), IconLocation (archivo de icono con índice) y WindowStyle (normal, maximizada, minimizada).

Ejemplo mínimo para crear un .url que abre el navegador en una ruta corporativa:

$WshShell = New-Object -ComObject WScript.Shell
$lnk = $WshShell.CreateShortcut("$HOME\\Desktop\\Intranet.URL")
$lnk.TargetPath = "https://intranet.empresa.local"
$lnk.Save()

Para iconos, recuerda que puedes apuntar a archivos .ico, .dll o .exe. Si el icono reside en una DLL o EXE con varios recursos, añade «,<índice>» al final (por ejemplo, «%WinDir%\\System32\\SHELL32.dll,66»). En VBScript o VFP se setea con IconLocation; en PowerShell, exactamente igual sobre el objeto COM devuelto por CreateShortcut.

Carpetas especiales: Escritorio, Menú Inicio y más

Para que tus accesos aparezcan donde toca, hay que resolver la carpeta correcta. Con WshShell.SpecialFolders puedes pedir rutas como ‘Desktop’ (Escritorio del usuario) o ‘AllUsersDesktop’ (Escritorio de todos), y con la API de shell (en VB6) se obtiene una lista aún más amplia.

Estos son los identificadores más útiles que se emplean en scripts heredados y actuales: AllUsersDesktop, AllUsersStartMenu, AllUsersPrograms, AllUsersStartUp, Desktop, Favorites, Fonts, MyDocuments, NetHood, PrintHood, Programs, Recent, SendTo, StartMenu, StartUp, Templates. Seleccionando cada uno consigues que el acceso directo aparezca para el usuario actual o para todos los usuarios, incluso en la carpeta ‘Programas’ del Menú Inicio o en la de ‘Inicio’ para ejecutar algo al iniciar sesión.

En un script histórico de VBScript muy completo (atribuido a un autor llamado Fernando en 2010) se ofrecía una utilidad de línea de comandos para crear accesos .lnk y .url en cualquiera de estas carpetas, con parámetros como /Nombre (obligatorio), /Carpeta (carpeta especial), /URL o /Aplicacion (uno de los dos, para diferenciar .url de .lnk), /Icono e /IndiceIcono, /RutaTrabajo, /Forzar y /Argumentos. La ayuda detallaba cómo, en caso de .url, se modificaba el archivo resultante para insertar IconFile e IconIndex si correspondía. La lógica también contemplaba copiar iconos .ico a la carpeta temporal del usuario si era necesario.

Automatización adicional desde PowerShell: .NET, COM e Internet Explorer

Más allá de los accesos directos, PowerShell te deja usar clases .NET y objetos COM para múltiples tareas de administración. Algunos cmdlets clásicos no funcionan bien en remoto, por lo que tirar de .NET salva la papeleta.

Con System.Diagnostics.EventLog puedes conectarte al registro de eventos local o remoto, consultar entradas, borrarlo o escribir sucesos. Observa cómo se instancia y cómo se pasa el nombre del registro (y el equipo remoto) por argumentos del constructor:

# Registro de Aplicación local
$AppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application
$AppLog.Clear()   # Borrado (requiere permisos adecuados)

# Registro remoto (indicando host o IP)
$RemoteAppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application, 192.168.1.81
$RemoteAppLog.Clear()

Para automatizar aplicaciones COM, el patrón es idéntico. Con InternetExplorer.Application puedes lanzar y controlar IE (útil en entornos heredados), ajustar Visible a $true y navegar con Navigate(). Recuerda cerrar con Quit() y liberar referencias si fuese necesario.

Catálogo de tareas WSH habituales (ideas y recuerdos útiles)

Además de crear accesos directos, WSH ha servido décadas para automatizar pequeñas tareas de administración. Un compendio clásico incluía ejemplos para imprimir y gestionar conexiones de impresoras de red, mapear y eliminar unidades (MapNetworkDrive y RemoveNetworkDrive), enumerar recursos de red con EnumNetworkDrives, abrir el cuadro de diálogo de seleccionar carpeta, leer la configuración regional y valores del Registro con RegRead, escribir en Run para arrancar programas al inicio con RegWrite, listar rutas especiales, leer del Registro la velocidad de CPU, asociar extensiones de archivo o incluso modificar combinaciones de teclas del sistema en versiones antiguas (como Ctrl+Alt+Supr en XP/NT) mediante cambios en el Registro.

Hoy en día, casi todo eso se cubre de forma más robusta con PowerShell y políticas de grupo o Intune, pero WSH sigue siendo una navaja suiza compatible y extremadamente ligera para scripting puntual.

Notas de compatibilidad, seguridad y buenas prácticas

Algunas operaciones (escritura en Program Files, cambios en el Registro bajo HKLM, manipulación del Acceso rápido o del Menú Inicio común) requieren privilegios elevados. Asegúrate de ejecutar PowerShell con permisos de administrador cuando el destino así lo exija o planifica el despliegue con la cuenta del sistema (por ejemplo, en Intune con el contexto del dispositivo).

Si compartes scripts, valora firmarlos, limitar el uso a orígenes de confianza y evitar ejecutar código descargado sin revisar. En escenarios de empresa, conviene capturar errores (Try/Catch), registrar lo que va pasando y aplicar validación de parámetros estricta para no generar accesos rotos ni rutas inesperadas.

Finalmente, recuerda que estos procedimientos solo tienen sentido en Windows. El modelo COM y WSH no existe en macOS o Linux. Cuando necesites compatibilidad cruzada, evalúa alternativas específicas de cada sistema o enfoques web.

Todo lo anterior pone sobre la mesa que, con una combinación sensata de WSH y PowerShell, puedes crear accesos directos de escritorio y menú Inicio con iconos y argumentos, generar enlaces a URL, ajustar estilos de ventana y carpetas de trabajo, resolver carpetas especiales para usuario o equipo, y aprovechar clases .NET y objetos COM cuando los cmdlets se quedan cortos, ya sea localmente o en despliegues gestionados como Intune.