首页 > 解决方案 > 将 .ps1 文件转换为 Windows 服务

问题描述

我正在尝试将 .ps1 文件转换为作为 Windows 服务运行。这需要作为服务运行,因为它是业务连续性的要求(计划任务不是一个选项)。我一直使用 NSSM 来包装 .ps1,因为它将通过 NSSM 作为 exe 运行。

这适用于 Windows Server 2012 中的不同脚本,但此脚本略有不同,我需要让此服务在 Windows Server 2016 上运行。脚本本身连接到大量其他服务器(总共我会有 3 项服务 - Windows 服务/Windows 进程/Linux 进程),它们在 PowerShell 中运行时都可以正常工作。

下面是脚本开头的示例,因此您可以了解它是如何工作的(可能不相关);

 while ($test = 1)
{

         [string]$query
          [string]$dbServer = "DBSERVER"   # DB Server (either IP or hostname)
          [string]$dbName   = "DBNAME" # Name of the database
          [string]$dbUser   = "CONNECTIONUSER"    # User we'll use to connect to the database/server
          [string]$dbPass   = "CONNECTIONPASSWORD"     # Password for the $dbUser


    $conn = New-Object System.Data.Odbc.OdbcConnection
    $conn.ConnectionString = "Driver={PostgreSQL Unicode(x64)};Server=$dbServer;Port=5432;Database=$dbName;Uid=$dbUser;Pwd=$dbPass;"
    $conn.open()
    $cmd = New-object System.Data.Odbc.OdbcCommand("select * from DBNAME.TABLENAME where typeofcheck = 'Windows Service' and active = 'Yes'",$conn)
    $ds = New-Object system.Data.DataSet
    (New-Object system.Data.odbc.odbcDataAdapter($cmd)).fill($ds) | out-null
    $conn.close()

$results = $ds.Tables[0]
$Output = @()

        foreach ($result in $results)
        {

            $Hostone = $Result.hostone
            $Hosttwo = $Result.hosttwo
            $Hostthree = $Result.hostthree
            $Hostfour = $Result.hostfour

        Write-Output "checking DB ID $($result.id)"

            #Host One Check
            if (!$result.hostone)
            {
            $hostonestatus = 17
            $result.hostone = ""
            }
            else
            {
            try
               {
                    if(Test-Connection -ComputerName $result.hostone -quiet -count 1)
                    {
                    $hostoneres = GET-SERVICE -COMPUTERNAME $result.hostone -NAME $result.ServiceName -ErrorAction Stop
                    $hostonestatus = $hostoneres.status.value__
                    $Result.HostOneCheckTime = "Last checked from $env:COMPUTERNAME at $(Get-date)"
                    }
                    else
                    {
                    $hostonestatus = 0
                    $result.hostonestatus = "Failed"
                    $Result.HostOneCheckTime = "Last checked from $env:COMPUTERNAME at $(Get-date)"
                    }
                }
                catch
                {
                    $hostonestatus = 0
                    $result.hostonestatus = "Failed"
                    $Result.HostOneCheckTime = "Last checked from $env:COMPUTERNAME at $(Get-date) Errors Found"
                }
                    if ($hostonestatus -eq 4)
                        {
                            $result.hostonestatus = "Running"
                        }
                    if ($hostonestatus -eq 1)
                        {
                            $result.hostonestatus = "Stopped"
                        }
                    elseif ($hostonestatus -eq 0)
                        {
                            $result.hostonestatus = "Failed"
                        }

                    }

如前所述,独立运行的确切脚本可以无缝运行

将其作为服务运行的最佳方式是什么,或者在 Windows Server 2016 中使用 NSSM 时是否存在任何已知问题?

我还发现下面可能指向正确的方向,因为我在日志中间歇性地得到了这些;

DCOM 事件 ID 10016 记录在 Windows 中

标签: powershellserviceservernssm

解决方案


Windows 系统管理员在这里。

从纯粹的面向服务的角度来看,使用几种不同的方法来完成此任务。

--- 1 ---

如果您使用的是 Server 2016,我相信 Powershell 命令“New-Service”可能是最干净的方法之一。看看下面的语法,如果它适合你的用例——

https://support.microsoft.com/en-au/help/137890/how-to-create-a-user-defined-service

此 CMDlet 采用凭据参数,因此根据您的用例,可能会很好地访问其他外部机器上的资源。

--- 2 ---

另一种方法是在 Windows 中使用旧的可信赖的内置 SC.exe 实用程序。

SC CREATE <servicename> Displayname= "<servicename>" binpath= "srvstart.exe <servicename> -c <path to srvstart config file>" start= <starttype>

一个例子 -

SC CREATE Plex Displayname= "Plex" binpath= "srvstart.exe Plex -c C:PlexService.ini" start= auto

据我所知,这将创建一个将在本地系统上下文下执行的服务。有关更多信息,请查看以下内容:

https://support.microsoft.com/en-au/help/251192/how-to-create-a-windows-service-by-using-sc-exe

https://www.howtogeek.com/50786/using-srvstart-to-run-any-application-as-a-windows-service/

--- 3 ---

您可能需要考虑手动注入一些注册表项来创建自己的服务(这本质上就是 SC.exe 在后台所做的)。

虽然很遗憾我目前无法提供样板代码,但我鼓励您查看以下资源:

https://www.osronline.com/article.cfm%5Eid=170.htm 

注意 - 您需要提供所有必需的子键才能使其工作。

与任何注册表更改一样,请在进行任何更改之前备份您的注册表并执行编辑,风险自负。如果可能,我只能建议在实施到产品之前在备用/测试 VM 上尝试此操作。


推荐阅读