使用 sc 启动 c# 服务

Posted

技术标签:

【中文标题】使用 sc 启动 c# 服务【英文标题】:Starting a c# service with sc 【发布时间】:2021-10-30 22:45:57 【问题描述】:

我正在使用 c# Visual Studio 中的工作服务模板为 windows 和 macos 编写一个小型自包含服务。

它使用相同的代码库,因此在 Program.cs 中进行检查

我已经编写了该服务,并且在从 Visual Studio 中启动时它可以在 Windows 上运行。

我已经发布了它使用

dotnet publish .\WorkerServiceTest2\ -c Release -r win-x64 -- self-contained true /p:PublishSingleFile=true /p:PublishedTrimmed=true

并尝试使用安装它

runas /user:MYUSERNAME "sc.exe create WorkerServiceTest2 c:\Users\MYYUSERNAME\Documents\bla\bla\bla\WorkerServiceTest2.exe"

但它没有出现在服务列表中,并且

sc.exe start WorkerServiceTest2 

说没有安装这个服务。

有没有什么地方可以看到 sc.exe 创建的结果? 或者也许有人可以看到我做错了什么?

非常感谢

我的服务 Program.cs 看起来像这样

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Runtime.InteropServices;

namespace WorkerServiceTest2

    public class Program
    
        public static void Main(string[] args)
        
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                Console.WriteLine("WinOS");
                CreateHostBuilderWin(args).Build().Run(); 
             else
            
                Console.WriteLine("MacOS");
                CreateHostBuilderMac(args).Build().Run();
            

        

        private static void configureServices(HostBuilderContext context, IServiceCollection services)
        
            services.AddHostedService<Worker>();
        

        public static IHostBuilder CreateHostBuilderWin(string[] args) =>
           Host.CreateDefaultBuilder(args)
           .UseWindowsService()
           .ConfigureServices((hostContext, services) =>
           
               services.AddHostedService<Worker>();
           );

        public static IHostBuilder CreateHostBuilderMac(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureServices(configureServices);
    



我的 Worker.cs 看起来像这样

using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;
using WorkerServiceTest2.SocketService;

namespace WorkerServiceTest2


    public class Worker : BackgroundService
    
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        
            while (!stoppingToken.IsCancellationRequested)
            
                //Her skal business logic være.
                SocketServer socketServer = new SocketServer();
                await socketServer.start();
            
        
    


【问题讨论】:

你介意用powershell代替sc吗? 那么最后它应该安装在带有脚本的用户机器上,这会有问题吗? 可能没有,但我对您的基础架构一无所知。但是我可以给你一个 powershell 脚本,我可以用它来安装我的所有服务。 感谢您的帮助,非常感谢!我想要这样,只是想看看那里是否有适合我的东西。泰! 【参考方案1】:

这是一个您可以使用的脚本。它将检查服务是否已安装。如果它已经存在,它将卸载它并安装新的。将其保存为MyScript.ps1(或您自己的偏好)并运行如下:

.\MyScript.ps1 -serviceName name_of_service -serviceUsername some_username -servicePassword some_password -binaryPath "C:\yourProgram.exe"

脚本:

# Sample: howto run ps-script from power-shell:
#.\Install-WindowsService_v3.ps1 -serviceName aTestservice -serviceUsername some_username -servicePassword some_password -binaryPath "C:\yourProgram.exe"

param
     (
     [string]$serviceName,
     [string]$serviceUsername,
     [string]$servicePassword,
     [string]$binaryPath,
     [string]$startupType='Automatic',
     [string]$dependsOn
     )

$secpasswd = ConvertTo-SecureString  $servicePassword -AsPlainText -Force

Write-Output "########################################"
Write-Output "Starting installation of windows service."

Write-Output "[serviceName] = $serviceName"
Write-Output "[serviceUsername] = $serviceUsername" -verbose
Write-Output "[binaryPath] = $binaryPath"

#Check Parameters
if (!$binaryPath)  throw "[binaryPath] parameter missing" 
if ((Test-Path $binaryPath)-eq $false)

    Write-Output "Path doesn't exist: $binaryPath"
    Write-Output "Service will not be installed."
    throw [System.IO.FileNotFoundException] "$binaryPath doesn't exist."


# verify if the service already exists, and if yes remove it first
if (Get-Service $serviceName -ErrorAction SilentlyContinue)

    Stop-Service -Name $serviceName
    # using WMI to remove Windows service because PowerShell does not have CmdLet for this
    $serviceToRemove = Get-WmiObject -Class Win32_Service -Filter "name='$serviceName'"
    $serviceToRemove.delete()
    Write-Output "Service $serviceName was stopped and uninstalled."

else

    Write-Output "Service didn't exist on the server"



if ($startupType -eq "AutomaticDelayedStart" ) 
 
    $startupType = "Automatic"
    $enableDelayed = "true" 



Write-Output "Installing service"

# creating credentials which can be used to run my windows service
$mycreds = New-Object System.Management.Automation.PSCredential ($serviceUsername, $secpasswd)

# creating windows service using all provided parameters
New-Service -name $serviceName -binaryPathName $binaryPath -displayName $serviceName -startupType $startupType -credential $mycreds -DependsOn $dependsOn


# Set "automatic delayed" after service was installed, since it is not a valid argument when using "New-Service"
if ($enableDelayed -eq "true" ) 
   
    $command = "sc.exe config $serviceName start= delayed-auto"
    $Output = Invoke-Expression -Command $Command -ErrorAction Stop
    if($LASTEXITCODE -ne 0)
       Write-Host "$Computer : Failed to set $serviceName to delayed start. 
        More details: $Output" -foregroundcolor red
       $failedcomputers +=$ComputerName
     else 
       Write-Host "$Computer : Successfully changed $serviceName  
        to delayed start" -foregroundcolor green
       $successcomputers +=$ComputerName
    


# verify if the service exists after installation
if (Get-Service $serviceName -ErrorAction SilentlyContinue)

    Write-Output "Installation complete."

else

    throw "Installation failed."
 
Write-Output "########################################"

另外,在我的所有应用程序中,我都是这样启动它们的:

    static async Task Main(string[] args)
    
        isService = !(Debugger.IsAttached || args.Contains("--console"));
        IWebHost host = CreateWebHostBuilder(args).Build();

        if (isService)
        
            var hostService = new MyCustomWebService(host);
            ServiceBase.Run(hostService);
        
        else
        
            await host.RunAsync();
        
    


public class MyCustomWebService: WebHostService

    private ILogger<MyCustomWebService> logger;

    public MyCustomWebService(IWebHost host) : base(host)
    
        var loggerFactory = host.Services.GetService<ILoggerFactory>();
        logger = loggerFactory.CreateLogger<MyCustomWebService>();
        logger.LogInformation("Starting...");
    

    protected override void OnStopped()
    
        logger.LogInformation("Will stop now.");
        base.OnStopped();
    

需要Microsoft.AspNetCore.Hosting.WindowsServices

进一步推荐阅读: https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-5.0&tabs=visual-studio

https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.hosting.windowsservices?view=aspnetcore-5.0

【讨论】:

非常感谢,我会尽快解决的 :) 这会要求用户提供凭据吗? (以前从未见过 powershell 脚本 凭据作为参数传递给 powershell 脚本。这些是服务将运行的凭据。 @KimSandberg - 如果sc 是唯一的选择。试试SC CREATE "name_of_service" binpath= "C:\yourProgram.exe" 代码中的一切都是一样的。 是的,谢谢您的评论。我就是这样做的。它需要更高的权限,但这不是问题。 :) 谢谢你的时间和帮助!

以上是关于使用 sc 启动 c# 服务的主要内容,如果未能解决你的问题,请参考以下文章

windows sc使用方法之一

Windows安装服务命令sc

Dell SC1425 设置USB启动

用sc create 创建的Tomcat服务不能启动 报错:1053

命令行取消自动启动服务

从 C# 调用 Advapi32.dll 本机 EventWrite 函数?