如何让 windows 服务自行更新
How do I get a windows service to update itself
我正在开发一个将 运行 作为 windows 服务的应用程序,我正在尝试让它自动更新。
我目前的方法是执行一个 powershell 脚本,它将停止服务,运行一个 msi 安装程序,然后重新启动服务。
此时powershell脚本是这样的
Start-Sleep -s 10
Write-Host "update start"
Stop-Service ServiceName1
msiexec /i c:\ProgramData\ProgramName\Install\ServiceName.Setup.msi /passive /l*v C:\ProgramData\ProgramName\Install\log.txt | Out-Null
Start-Service ServiceName1
Write-Host "update finished"
这就是我从应用程序运行中获取它的方式
Process.Start("Powershell", @"C:\ProgramData\ProgramName\Install\UpdateApp.ps1");
发生了什么,服务停止并重新启动,但它没有更新。就好像 msi 永远不会 运行。日志文件甚至没有出现。
当我从提升的命令提示符 运行 服务作为命令行应用程序时,它按预期工作并且应用程序得到更新,所以我目前的理论是该服务不是 运行使用管理员权限运行 powershell 脚本。
Other questions suggest that I set up the log on settings for the service to use an administrator account,所以我将服务设置为 运行 作为我当前登录的帐户,该帐户能够手动打开提升的命令提示符 and/or 运行 安装程序,但这样做并没有改变任何东西。
有什么方法可以做我想做的事吗?
我目前没有致力于任何特定的自动更新策略,但我知道我希望这项服务能够自行更新。因此,如果我做错了什么,我 100% 愿意尝试不同的方法。
更新:
我进行了以下更改以记录 msiexecc 的错误和输出
Try{
c:\windows\system32\msiexec.exe /i c:\ProgramData\ProgramName\Install\ServiceName.msi /passive /l*v C:\ProgramData\ProgramName\Install\log.txt | Out-File -filepath C:\ProgramData\ProgramName\Install\output.txt
}
Catch {
$_ | Out-File C:\ProgramData\ProgramName\Install\errors.txt -Append
}
在 运行 运行该脚本后,我发现了以下错误:
The term 'msiexec' is not recognized as the name of a cmdlet, function, script file, or operable program..
看起来对 msiexec
的调用实际上并不是针对 c:\windows\system32\msiexec.exe
根据 this question 看来 Powershell 没有使用标准的 PATH 环境变量,而是有自己的方案,在系统服务的上下文中可能无法按预期工作。
最简单的解决方法,如你所说,就是指定完整路径,大概就是c:\windows\system32\msiexec.exe
。
但是,在生产中,避免使用硬编码路径可能是明智的,因为您可能 运行 遇到本地化、操作系统更改等问题。您也许可以使用服务中的 SearchPath 或 .NET 等效项,并实时写出 Powershell 脚本或将路径传递给 msiexec
作为命令行选项,或者可能有一个明智的选择Powershell 解决方案。
我正在开发一个将 运行 作为 windows 服务的应用程序,我正在尝试让它自动更新。
我目前的方法是执行一个 powershell 脚本,它将停止服务,运行一个 msi 安装程序,然后重新启动服务。
此时powershell脚本是这样的
Start-Sleep -s 10
Write-Host "update start"
Stop-Service ServiceName1
msiexec /i c:\ProgramData\ProgramName\Install\ServiceName.Setup.msi /passive /l*v C:\ProgramData\ProgramName\Install\log.txt | Out-Null
Start-Service ServiceName1
Write-Host "update finished"
这就是我从应用程序运行中获取它的方式
Process.Start("Powershell", @"C:\ProgramData\ProgramName\Install\UpdateApp.ps1");
发生了什么,服务停止并重新启动,但它没有更新。就好像 msi 永远不会 运行。日志文件甚至没有出现。
当我从提升的命令提示符 运行 服务作为命令行应用程序时,它按预期工作并且应用程序得到更新,所以我目前的理论是该服务不是 运行使用管理员权限运行 powershell 脚本。
Other questions suggest that I set up the log on settings for the service to use an administrator account,所以我将服务设置为 运行 作为我当前登录的帐户,该帐户能够手动打开提升的命令提示符 and/or 运行 安装程序,但这样做并没有改变任何东西。
有什么方法可以做我想做的事吗?
我目前没有致力于任何特定的自动更新策略,但我知道我希望这项服务能够自行更新。因此,如果我做错了什么,我 100% 愿意尝试不同的方法。
更新:
我进行了以下更改以记录 msiexecc 的错误和输出
Try{
c:\windows\system32\msiexec.exe /i c:\ProgramData\ProgramName\Install\ServiceName.msi /passive /l*v C:\ProgramData\ProgramName\Install\log.txt | Out-File -filepath C:\ProgramData\ProgramName\Install\output.txt
}
Catch {
$_ | Out-File C:\ProgramData\ProgramName\Install\errors.txt -Append
}
在 运行 运行该脚本后,我发现了以下错误:
The term 'msiexec' is not recognized as the name of a cmdlet, function, script file, or operable program..
看起来对 msiexec
的调用实际上并不是针对 c:\windows\system32\msiexec.exe
根据 this question 看来 Powershell 没有使用标准的 PATH 环境变量,而是有自己的方案,在系统服务的上下文中可能无法按预期工作。
最简单的解决方法,如你所说,就是指定完整路径,大概就是c:\windows\system32\msiexec.exe
。
但是,在生产中,避免使用硬编码路径可能是明智的,因为您可能 运行 遇到本地化、操作系统更改等问题。您也许可以使用服务中的 SearchPath 或 .NET 等效项,并实时写出 Powershell 脚本或将路径传递给 msiexec
作为命令行选项,或者可能有一个明智的选择Powershell 解决方案。