Windows 服务恢复,无法执行 PS-脚本

Windows Service Recovery, Unable to execute PS-script

OS: 赢得 2012 R2

嗨,

我尝试设置某些服务,以便在它们第二次失败时触发 powershell 脚本,该脚本会向某些人发送电子邮件。这是通过 services > (specific service) > properties > recovery.

完成的

尝试了几乎所有可以想到的程序组合: Powershell.exe, C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe, 与上一个相同但大写 "P".

命令行参数:-NoProfile -Executionpolicy bypass C:\users\username\appdata\local\myscript.ps1,脚本路径后的参数

脚本未签名。

现在我的脚本使用 Send-MailMessage 并且密码使用 ConvertFrom-SecureString 保存,我在想 service/user 实际上 运行 脚本可能不能'不要解密密码,因为它是用我的管理员帐户创建的。

我尝试使用与 运行 我想监控的进程相同的服务帐户登录,并从他们的用户创建加密的密码文件并将其保存在不需要该用户的路径中成为管理员(即 %localappdata%),但是当我在 PID.

上使用 pskill 时脚本仍然无法触发

在 PS 中手动执行命令时一切正常,我没有收到任何提示。它做的正是它应该做的。

现在我对 Windows 管理场景还很陌生,所以 userservice 实际上触发了 PowerShell 脚本? 运行 服务的身份是否相同,即我指定的特定服务帐户?还是其他原因?

我很乐意 post 这里的代码,但它在我的另一台计算机上,稍后我会用它更新。在谷歌上搜索了几个小时并尝试了几乎所有的方法,这可能是我所缺少的基本内容。

非常感谢您的帮助 - TheSwede86

编辑:这是代码,我也尝试了 Ronald Rink 'd-fens' 建议,当我手动执行脚本时它会记录用户(显示带有我的用户名的事件)但当我尝试模拟服务时不会失败。

$PSEmailServer = "<address to smtp-server>"
$SMTPPort = <port>
$SMTPUsername = "<email-address to send from>"
$EncryptedPasswordFile = "<path and filename to pwd-file, currently on C:\>.securestring"
$SecureStringPassword = Get-Content -Path $EncryptedPasswordFile | ConvertTo-SecureString
$EmailCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $SMTPUsername,$SecureStringPassword
$MailTo = "<email-address to mail to>"
$MailFrom = $SMTPUsername
$hostname = Hostname
$service = Get-Service -Name "<Servicename*>" | Where-Object {$_.Status -eq "Stopped"}
$MailSubject = "ALERT: Service on $hostname has stopped and failed to restart after one attempt"
$MailBody = "$service"
$OtherEmail = "<Other email-address to send to>"
$whoami = whoami
Send-MailMessage -From $MailFrom -To $MailTo -Bcc $OtherEmail -Subject $MailSubject -Body $MailBody -Port $SMTPPort -Credential $EmailCredential -UseSsl -Priority High
Write-EventLog –LogName Application –Source “PowerShell Script Debug” –EntryType Information –EventID 1 -Message $whoami

已编辑的电子邮件地址、SMTP 服务器等

编辑 1:添加了尝试记录执行脚本的用户。


编辑 2:@Ronald Rink 'd-fens'

我尝试了以下方法:

$PlainPassword = "<passwordForEmailToSendFrom>"
$SecurePassword = $PlainPassword | ConvertTo-SecureString -AsPlainText -Force | Out-File -FilePath C:\temp\<filename>.securestring

我在上面让服务失败了一次,所以它将明文密码转换为一个安全字符串文件,然后我在我的脚本中调用它;这不起作用。

如果我尝试你的建议:

1)

$password = "<passwordForEmailToSendFrom>" | ConvertTo-SecureString -asPlainText -Force
$username = "<domain\serviceAccountWhichRunsTheService>" 
$credential = New-Object System.Management.Automation.PSCredential($username,$password)

$credential | Export-CliXml C:\temp\credential.xml

它在我选择的路径中成功创建了 "credential.xml"

2)

$credential = Import-CliXml C:\temp\credential.xml
$decryptedCredential = "{0} - {1}" -f $credential.UserName, $credential.GetNetworkCredential().Password
$decryptedCredential | Out-File C:\temp\ServiceRecovery.txt -Append -Force

我在 "ServiceRecovery.txt" 和 SYSTEM 中得到未加密的密码。

我将"SYSTEM"添加到本地"Administrators"组并再次尝试; 它只是向 "ServiceRecovery.txt" 添加了另一行,其中包含我在“1”中指定的用户名和未加密的密码。

然而,当我尝试关于哪个用户实际上 运行 使用脚本并且确实是 "SYSTEM".

时,我成功了

抱歉我的错误解释,已经坐了几个小时试图对最后一点进行排序但无法做到。


编辑 3:

感谢@Ronald Rink 'd-fens' 我是这样解决的:

New-Object System.Management.Automation.PSCredential("<EmailAddressToSendFrom>", (ConvertTo-SecureString -AsPlainText -Force "<PasswordForAboveEmailAccount>")) | Export-CliXml C:\temp\MyCredential.xml

以上使用 API (DPAPI) 将未加密的密码转换为加密密码,仅可用于创建它的 account/machine!

用上面的脚本让服务失败一次,用SERVICE账号生成文件

$PSEmailServer = "<smtp-address>"
$SMTPPort = <port>
$SMTPUsername = "<EmailAddressToSendFrom>"
$credpath = Import-Clixml -Path C:\temp\MyCredential.xml
$MailTo = "<EmailAddressToSendTo>"
$MailFrom = $SMTPUsername
$hostname = Hostname
$service = Get-Service -Name "<Servicename(s)>" | Where-Object {$_.Status -eq "Stopped"} | Select-Object -Property DisplayName | Out-String
$MailSubject = "ALERT: Service on $hostname has stopped and failed to restart after one attempt"
$MailBody = $service
$OtherEmail = "<AnotherEmailAddressToSendTo>"
Send-MailMessage -From $MailFrom -To $MailTo -Bcc $OtherEmail -Subject $MailSubject -Body $MailBody -Port $SMTPPort -Credential $credpath -UseSsl -Priority High

以上是服务失败时运行的实际脚本

服务 > 恢复中的参数是:

程序:C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

命令行参数: -文件 C:\temp\myscriptname.ps1

启用错误停止操作

第一次失败:重启服务

第二次失败:运行一个程序

您输入的脚本 运行 以防万一失败似乎不是 运行 在服务帐户下(也不在您的管理员帐户下)而是在以下帐户下操作系统。您可以通过在服务失败后执行时从脚本中记录用户名来验证这一点(使用 Write-EventLog 或将其保存到文本文件)。

这是一个示例,说明如何验证您的脚本 运行s 在本地系统下:

# C:\src\TEMP\ServiceRecovery.ps1

cd C:\src\TEMP\
$ENV:USERNAME | Out-File C:\src\TEMP\ServiceRecovery.txt -Append -Force

您可以按照以下屏幕截图所示配置您的服务:

服务帐户是这样创建的:

PS > net user ServiceAccount P@ssw0rdP@ssw0rd /ADD
PS > net localgroup Administrators ServiceAccount /ADD

如果我随后通过调用 Stop-Process -Name teamviewer_service -Force 停止进程,我可以在生成的文本文件中看到以下名称:

SYSTEM

这意味着您必须通过 SYSTEM 帐户而不是通过您的个人用户或服务用户帐户来加密安全字符串,或者您必须诉诸其他方式来读取您的加密密码。

通过服务帐户加密您的密码可以通过创建脚本来创建密码并以加密形式存储。将此脚本放入您的服务恢复设置中,并使此服务失败一次。然后删除脚本并插入您的原始脚本,然后将能够导入加密的密码。

在这里你可以找到我测试它的脚本:

(1) 加密凭据的脚本

# Creating a PS Credential from a Clear Text Password in Powershell
# https://blogs.technet.microsoft.com/gary/2009/07/23/creating-a-ps-credential-from-a-clear-text-password-in-powershell/

$password = "P@ssw0rdP@ssw0rd" | ConvertTo-SecureString -asPlainText -Force
$username = ".\ServiceAccount" 
$credential = New-Object System.Management.Automation.PSCredential($username,$password)

$credential | Export-CliXml C:\src\TEMP\credential.xml

(2) 解密凭据的脚本

$credential = Import-CliXml C:\src\TEMP\credential.xml
$decryptedCredential = "{0} - {1}" -f $credential.UserName, $credential.GetNetworkCredential().Password
$decryptedCredential | Out-File C:\src\TEMP\ServiceRecovery.txt -Append -Force

现在生成的文本文件包含

.\ServiceAccount - P@ssw0rdP@ssw0rd

注意:第一个 "encrypt" 脚本包含纯文本密码,仅使用 一次 进行加密。我们必须走这条路,才能运行下SYSTEM帐号。替代方法可能是使用来自 SysInternals 的 RunAs