Windows permite crear y administrar servicios desde PowerShell sin necesidad de instalar herramientas externas como NSSM. Sin embargo, el cmdlet New-Service no convierte directamente un script .ps1 en un servicio nativo: necesita un ejecutable que implemente el funcionamiento de un servicio de Windows.
En este tutorial vamos a crear un servicio llamado MiServicioPowerShell utilizando Windows PowerShell, C# y las bibliotecas integradas de .NET. El servicio se ejecutará en segundo plano, escribirá un registro cada minuto y podrá iniciarse, detenerse y eliminarse desde PowerShell.
1. Requisitos previos
Para realizar esta práctica necesitas:
- Windows con Windows PowerShell 5.1.
- Una cuenta con permisos de administrador.
- El entorno .NET Framework disponible en Windows.
- Conocimientos básicos de PowerShell.
Abre Windows PowerShell como administrador. Puedes comprobar la versión con el siguiente comando:
$PSVersionTable.PSVersion
En esta práctica utilizaremos Windows PowerShell 5.1 para generar el ejecutable mediante Add-Type.
2. Crear la carpeta de trabajo
Primero creamos una carpeta para almacenar el código compilado y el ejecutable del servicio.
New-Item -Path "C:\MiServicio" -ItemType Directory -Force
3. Crear el código del servicio
El servicio estará implementado en C#. PowerShell se encargará de compilar el código y generar el ejecutable, sin necesidad de utilizar NSSM.
El programa realizará las siguientes operaciones:
- Registrará el inicio del servicio.
- Ejecutará una tarea cada 60 segundos.
- Escribirá la fecha y la hora en un archivo de registro.
- Registrará cuándo se detiene el servicio.
Copia y ejecuta el siguiente bloque completo:
$codigo = @'
using System;
using System.IO;
using System.ServiceProcess;
using System.Timers;
public class MiServicio : ServiceBase
{
private Timer temporizador;
private readonly string archivo =
@"C:\ProgramData\MiServicio\servicio.log";
public MiServicio()
{
ServiceName = "MiServicioPowerShell";
CanStop = true;
AutoLog = true;
}
protected override void OnStart(string[] args)
{
Directory.CreateDirectory(
@"C:\ProgramData\MiServicio"
);
Registrar("Servicio iniciado.");
temporizador = new Timer(60000);
temporizador.AutoReset = true;
temporizador.Elapsed += (sender, e) =>
{
Registrar("Servicio en ejecución.");
};
temporizador.Start();
}
protected override void OnStop()
{
if (temporizador != null)
{
temporizador.Stop();
temporizador.Dispose();
}
Registrar("Servicio detenido.");
}
private void Registrar(string mensaje)
{
File.AppendAllText(
archivo,
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
+ " - " + mensaje + Environment.NewLine
);
}
public static void Main()
{
ServiceBase.Run(new MiServicio());
}
}
'@
Add-Type
-TypeDefinition $codigo
-Language CSharp
-OutputAssembly "C:\MiServicio\MiServicio.exe"
-OutputType WindowsApplication
-ReferencedAssemblies @(
"System.dll",
"System.ServiceProcess.dll"
)
El método OnStart() se ejecuta cuando Windows inicia el servicio. Por su parte, OnStop() se ejecuta cuando se solicita su detención.
El temporizador permite realizar una operación periódica sin mantener un bucle infinito bloqueando el hilo principal del servicio.
4. Comprobar que se ha generado el ejecutable
Antes de registrar el servicio, verificamos que el archivo existe:
Test-Path "C:\MiServicio\MiServicio.exe"
El resultado esperado es:
True
También puedes consultar las propiedades del archivo:
Get-Item "C:\MiServicio\MiServicio.exe" |
Select-Object FullName, Length, LastWriteTime
Si la compilación genera un error, comprueba que estás utilizando Windows PowerShell 5.1 y que están disponibles las bibliotecas de .NET Framework necesarias.
5. Registrar el servicio en Windows
Una vez generado el ejecutable, utilizamos New-Service para registrarlo en el Administrador de control de servicios de Windows.
New-Service-Name "MiServicioPowerShell"-BinaryPathName "C:\MiServicio\MiServicio.exe"-DisplayName "Mi servicio de prueba"-Description "Servicio de ejemplo desarrollado con PowerShell y C#."-StartupType Automatic
Los parámetros principales son:
-Name: nombre interno del servicio.-BinaryPathName: ruta del ejecutable que implementa el servicio.-DisplayName: nombre descriptivo que aparecerá en la consola de servicios.-Description: descripción de su finalidad.-StartupType Automatic: configura el inicio automático con Windows.
6. Iniciar el servicio
Para iniciar el servicio recién registrado, ejecuta:
Start-Service -Name "MiServicioPowerShell"
Comprueba su estado:
Get-Service -Name "MiServicioPowerShell"
El estado esperado es Running.
También puedes consultar sus propiedades:
Get-CimInstance Win32_Service
-Filter "Name='MiServicioPowerShell'" |
Select-Object Name, DisplayName, State, StartMode, PathName
Este comando permite verificar el estado, el tipo de inicio y la ruta del ejecutable asociado.
7. Consultar el registro de actividad
El servicio escribe sus registros en el siguiente archivo:
C:\ProgramData\MiServicio\servicio.log
Para consultar las últimas entradas:
Get-Content "C:\ProgramData\MiServicio\servicio.log" -Tail 10
Para observar cómo aparecen nuevas entradas:
Get-Content "C:\ProgramData\MiServicio\servicio.log" -Wait
La salida tendrá un formato similar a este:
2026-10-17 10:00:00 - Servicio iniciado.
2026-10-17 10:01:00 - Servicio en ejecución.
2026-10-17 10:02:00 - Servicio en ejecución.
Las fechas y horas del ejemplo son ilustrativas. El archivo contendrá las marcas temporales reales del equipo.
8. Detener y reiniciar el servicio
Para detenerlo:
Stop-Service -Name "MiServicioPowerShell"
Para volver a iniciarlo:
Start-Service -Name "MiServicioPowerShell"
Para reiniciarlo directamente:
Restart-Service -Name "MiServicioPowerShell"
Puedes comprobar el resultado de cada operación con Get-Service.
9. Configurar el inicio automático
El servicio ya se ha registrado con inicio automático. Si necesitas comprobar o modificar esta configuración, ejecuta:
Set-Service-Name "MiServicioPowerShell"-StartupType Automatic
Para consultar el tipo de inicio configurado:
Get-CimInstance Win32_Service
-Filter "Name='MiServicioPowerShell'" |
Select-Object Name, StartMode, State
Ten presente que el inicio automático no significa necesariamente que el servicio se ejecute antes de que todos los componentes del sistema estén disponibles.
10. Eliminar el servicio
Si quieres retirar el servicio, primero detenlo:
Stop-Service
-Name "MiServicioPowerShell"
-ErrorAction SilentlyContinue
Después solicita su eliminación:
sc.exe delete MiServicioPowerShell
Windows puede marcar el servicio para su eliminación y completar el proceso cuando ya no esté en uso.
Una vez confirmada su eliminación, puedes borrar los archivos creados durante la práctica:
Remove-Item "C:\MiServicio" -Recurse -Force
Remove-Item "C:\ProgramData\MiServicio" -Recurse -Force
Precaución: el último comando elimina también el registro de actividad. Si necesitas conservarlo para documentar la práctica, copia el archivo antes de borrarlo.
11. Diferencias entre un servicio y una tarea programada
Aunque ambos mecanismos pueden ejecutar operaciones automáticamente, tienen finalidades diferentes.
| Característica | Servicio de Windows | Tarea programada |
|---|---|---|
| Funcionamiento habitual | En segundo plano | Según un horario o evento |
| Inicio automático | Sí | Sí, según su configuración |
| Ejecución diaria a una hora concreta | Requiere implementar esa lógica | Función incorporada |
| Interacción directa con el escritorio | No es su finalidad | Puede configurarse para la sesión interactiva |
| Administración desde PowerShell | Get-Service, Start-Service, Stop-Service | Get-ScheduledTask, Start-ScheduledTask |
| Ejemplo de uso | Supervisión, procesamiento periódico y servicios de soporte | Copias de seguridad, informes y apertura de aplicaciones |