I am trying to run a perl script whenever there is a service crash. The perl script intends to restart the service and send a mail to all the developers.
I have used windows recovery options for that, where it has an option to run a program . I have filled the required details in the command line option but the script doesn't seem to get executed. Can you please help me by sharing your knowledge on this?
Recovery tab configuration
I have tried with Restart service option and that is working fine but the run a program isn't executing the script. Am I missing something?
Any comment on this will be helpful.
I recently implemented a recovery option to run a powershell script that attempts to restart the service a defined number of times and sends an email notification at the conclusion, it also attaches a txt file with recent relevant logs.
After several attempts (and despite all the other things I have seen) The configuration of fields on the recovery tab in services is as follows:
Program: Powershell.exe
**Not C:\Windows\System32\WindowsPowerShell\v1.0\Powershell.exe
Command line parameters: -command "& {SomePath\YourScript.ps1 '$args[0]' '$args[1]' '$args[n]'}"
eg: -command "& {C:\PowershellScripts\ServicesRecovery.ps1 'Service Name'}"
**The $args are parameters that will be passed to your script. These are not required.
here is the powershell script:
cd $PSScriptRoot
$n = $args[0]
function CreateLogFile {
$events = Get-EventLog -LogName Application -Source SomeSource -Newest 40
if (!(Test-Path "c:\temp")) {
New-Item -Path "c:\temp" -Type directory}
if (!(Test-Path "c:\temp\ServicesLogs.txt")) {
New-Item -Path "c:\temp" -Type File -Name "ServicesLogs.txt"}
$events | Out-File -width 600 c:\temp\ServicesLogs.txt
}
function SendEmail {
$EmailServer = "SMTP Server"
$ToAddress = "Name#domain.com"
$FromAddress = "Name#domain.com"
CreateLogFile
$Retrycount = $Retrycount + 1
send-mailmessage -SmtpServer $EmailServer -Priority High -To $ToAddress -From $FromAddress -Subject "$n Service failure" `
-Body "The $n service on server $env:COMPUTERNAME has stopped and was unable to be restarted after $Retrycount attempts." -Attachments c:\temp\ServicesLogs.txt
Remove-Item "c:\temp\ServicesLogs.txt"
}
function SendEmailFail {
$EmailServer = "SMTP Server"
$ToAddress = "Name#domain.com"
$FromAddress = "Name#domain.com"
CreateLogFile
$Retrycount = $Retrycount + 1
send-mailmessage -SmtpServer $EmailServer -Priority High -To $ToAddress -From $FromAddress -Subject "$n Service Restarted" `
-Body "The $n service on server $env:COMPUTERNAME stopped and was successfully restarted after $Retrycount attempts. The relevant system logs are attached." -Attachments c:\temp\ServicesLogs.txt
Remove-Item "c:\temp\ServicesLogs.txt"
}
function StartService {
$Stoploop = $false
do {
if ($Retrycount -gt 3){
$Stoploop = $true
SendEmail
Break
}
$i = Get-WmiObject win32_service | ?{$_.Name -imatch $n} | select Name, State, StartMode
if ($i.State -ne "Running" -and $i.StartMode -ne "Disabled") {
sc.exe start $n
Start-Sleep -Seconds 35
$i = Get-WmiObject win32_service | ?{$_.Name -imatch $n} | select State
if ($i.state -eq "Running"){
$Stoploop = $true
SendEmailFail}
else {$Retrycount = $Retrycount + 1}
}
}
While ($Stoploop -eq $false)
}
[int]$Retrycount = "0"
StartService
Related
What i'm trying to do ?
Create four files in local disk in the following order.
Note : In my local machine and not in any server remotely.
Three files to be created
Restart the system
On system startup create another file
Script i have used.
get-job | remove-job -Force
function create-file {
Param ([string] $a)
$p = "D:\" + $a
Write-Host $p
if (!(Test-Path $p))
{
New-Item -path D:\$a -type "file" -value "my new text"
Write-Host "Created new file and text content added"
}
else
{
Add-Content -path D:\$a -value "new text content"
Write-Host "File already exists and new text content added"
}
}
Workflow New-ServerSetup
{
create-file "one.txt"
create-file "two.txt"
create-file "three.txt"
Restart-Computer -ComputerName $env:COMPUTERNAME -Wait
Start-Sleep -Seconds 7
create-file "four.txt"
Unregister-ScheduledJob -Name NewServerSetupResume
}
$adm = "####"
$pwd = ConvertTo-SecureString -String "####" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($adm, $pwd)
$AtStartup = New-JobTrigger -AtStartup
Register-ScheduledJob -Name NewServerSetupResume -Credential $cred -Trigger $AtStartup -ScriptBlock {Import-Module PSWorkflow; Get-Job -Name NewSrvSetup -State Suspended | Resume-Job}
New-ServerSetup -JobName NewSrvSetup
Issues i'm facing
The execution returns Cannot wait for local computer to restart
i'm new to powershell things if any mistakes burden me.
Thanks in advance.
Schedule a job first, then reboot without waiting.
I've created a powershell script to list all domain controllers under current trusted forest, and than check each individual server for specific services if it's running or not and send an email with report.
I found 2 issues so far.
Get-Service -name "MyService" -ComputerName $myComputer "will say no service is found with that name, but if I list all the services : Get-Service -ComputerName $myComputer it will say "This operation might require other privileges." This is a problem because I'm reporting that the service doesn't exist but it is actually there.
For some reason if I just run the powershell script from command line manually it lists way more servers and most of the info is correct. But I schedule the powershell script from windows task manager with that same account the information is all wrong and it reports way less servers.
Script:
#$domain = [system.directoryservices.activedirectory.domain]::GetCurrentDomain().Name
#$numerOfDomainControlers= nslookup $domain
Clear-Content .\log.txt
$startTime = Get-Date
$allDCs = ((Get-ADForest).Domains | %{ Get-ADDomainController -Filter * -Server $_ } | Where-Object { $_.hostname -notlike '*root*' }).hostname
foreach( $allDC in $allDCs){
$testConnection = Test-Connection $allDC -Quiet -Count 1 -ErrorAction SilentlyContinue
Write-Host
if($testConnection -like "true") {
$SyncStatus = Get-Service -name "MyServicesName" -ComputerName $allDC -ErrorAction SilentlyContinue
if($SyncStatus.length -eq 0) {
Write-Host "MyServicesName doesn't exists on:"$allDC
$SyncStatus = "MyServicesName doesn't exists on:" + $allDC
$logs = $SyncStatus |Out-File .\log.txt -Append
}
else{
write-host "MyServicesName on "$allDC "is: " $SyncStatus.status
$SyncStatus = "MyServicesName on " + $allDC + "is: " + $SyncStatus.status
$logs = $SyncStatus |Out-File .\log.txt -Append
}
}
else
{
Write-Host "Test Connection to Server failed:"$allDC
$SyncStatus = "Test Connection to Server failed:" + $allDC
$logs = $SyncStatus |Out-File .\log.txt -Append
}
}
$endTime = Get-Date
$totalTime = New-TimeSpan -start $startTime -end $endTime
Write-Host $totalTime
$logs = "Total Time in Seconds:" + $totalTime |Out-File .\log.txt -Append
#send Email
$logs = Get-Content .\log.txt
$serverName = $env:computername
$LogTime = Get-Date -Format "MM/dd/yyyy hh:mm:ss"
$FromAddress = "email.com"
$ToAddress = "email.com"
foreach($log in $logs)
{
$Messagebody = $messagebody + $log + "`r`n" |Out-String
}
[string] $MessageSubject ="Status Report runing on " + $serverName +" " + $endTime
$SendingServer = "server"
Send-MailMessage -to $ToAddress -from $FromAddress -subject $MessageSubject -smtpServer $SendingServer -body $Messagebody -Attachments .\log.txt
I am building a deployment script to install software on a new device using a ppkg file.
The script looks at which drive is the USB drive and copies the software over to the local temp folder and runs them according to a set of variables as shown below.
What I am struggling to do is simplify the script so I am not repeating code 7 times down the page, I want to just run a loop 7 times to pull in the needed software. I tried an array but I think I am not quite understanding it completely.
This is my script so far with the repeating code:
#SOE application Variables
#applcation1 CM_client
$app1name = "Config Manager Client 1706"
$app1skip = "no"
$app1path = "$env:SystemDrive\temp\soe\application_installs\app1\CM_client_inst_1706\"
$app1runcommand = "clientx64.bat"
$app1arguments = ""
#applcation2
$app2name = "Office 2016 Pro Plus"
$app2skip = "no"
$app2path = "$env:SystemDrive\temp\soe\application_installs\app2\O2016\"
$app2runcommand = "setup.exe"
$app2arguments = "/configure configuration.xml"
#log Folder
$datetime = Get-Date -format "yyyy.MM.dd-HH.mm.ss"
$logpath = "$env:ALLUSERSPROFILE\SOEInst_ppkg\$datetime"
New-Item -Path $logpath -ItemType Directory -ErrorAction SilentlyContinue
#Transcript Start
Start-Transcript -Path $logpath\SOE-app-installer-ppkg-$datetime.log
#Timer Function
$pkgremovetime = Get-Date -format "HH:mm:ss"
write-host "Script Start Time - $pkgremovetime"
#Find USB Drive
Write-host Discovering USB Drive
$drives = (GET-WMIOBJECT –query “SELECT * from win32_logicaldisk").DeviceID
foreach ($drive in $drives) {
$usbdrive = (dir $drive USBIMG.FILE | Select-Object -Unique "USBIMG.FILE")
if ($usbdrive -match "USBIMG.FILE*") {
$datadrive = $drive
}
}
Write-host Found $datadrive is the USB drive
#Copy Applications to Local Drive
Write-Host Creating Installer Folder
New-Item -Path $env:SystemDrive\temp\SOE -ItemType Directory
Copy-Item $datadrive\application_installs $env:SystemDrive\temp\soe -Recurse -Verbose
#Install Applications
#Application 1
if ($app1skip -eq "no") {
if ($app1arguments) { #Arguments Variable Populated
Write-Host Installing Applcation 1 `($app1name`)
$app1 = Start-Process -Wait -FilePath $app1path$app1runcommand -ErrorAction Continue -ArgumentList $app1arguments -WindowStyle Normal
if ($app1.ExitCode -eq "0") {
Write-Host $app1name Installed ok
} Else {
Write-host $app1name install exited with code $app1.ExitCode
}
}
}Else { #Argurments Variable Empty
Write-Host Installing Applcation 1 `($app1name`)
$app1 = Start-Process -Wait -FilePath $app1path$app1runcommand -ErrorAction Continue -WindowStyle Normal
if ($app1.ExitCode -eq "0") {
Write-Host $app1name Installed ok
} Else {
Write-host $app1name install exited with code $app1.ExitCode
}
}
#Application 2
if ($app2skip -eq "no") {
if ($app2arguments) { #Arguments Variable Populated
Write-Host Installing Applcation 2 `($app2name`)
$app2 = Start-Process -Wait -FilePath $app2path$app2runcommand -ErrorAction Continue -ArgumentList $app2arguments -WindowStyle Normal
if ($app2.ExitCode -eq "0") {
Write-Host $app2name Installed ok
} Else {
Write-host $app2name install exited with code $app2.ExitCode
}
}
}Else { #Argurments Variable Empty
Write-Host Installing Applcation 2 `($app2name`)
$app2 = Start-Process -Wait -FilePath $app2path$app2runcommand -ErrorAction Continue -WindowStyle Normal
if ($app2.ExitCode -eq "0") {
Write-Host $app2name Installed ok
} Else {
Write-host $app2name install exited with code $app2.ExitCode
}
}
#cleanup
Remove-Item $env:SystemDrive\temp\soe -Recurse -Force -Verbose
#get end time
$pkgremovetime_end = Get-Date -format "HH:mm:ss"
#calculate time difference
$timetaken = New-TimeSpan $pkgremovetime $pkgremovetime_end
if ($timetaken.Seconds -lt 0) {
$Hrs = ($timetaken.Hours) + 23
$Mins = ($timetaken.Minutes) + 59
$Secs = ($timetaken.Seconds) + 59 }
else {
$Hrs = $timetaken.Hours
$Mins = $timetaken.Minutes
$Secs = $timetaken.Seconds }
$Difference = '{0:00}:{1:00}:{2:00}' -f $Hrs,$Mins,$Secs
#log time difference
write-host "Script End Time - $pkgremovetime_end"
Write-Host "Total time taken $difference"
#Transcript End
Stop-Transcript
I suggest you make a function which takes in the variables. I did a quick comparison of your installation codes and something like this should work
function installApplication{
Param($skip, $arguments, $name, $path, $runcommand)
if ($skip -eq "no"){
if ($arguments){
write-host "Installing Application $appname"
$app = Start-Process -Wait -FilePath $path$runcommand -ErrorAction....
if($app.ExitCode -eq "0"){
....
....
}
and so on, You can then call the function using
installApplication $app1skip $app1arguments $app1name $app1path $app1runcommand
installApplication $app2skip $app2arguments $app2name $app2path $app1runcommand
Your input arguments will replace the function parameters in the order you pass them in, or you can use -skip $app1skip to assign the parameters.
If your repeating the same code too many times, I suggest throwing it into something like diffchecker, put the code into a function and replace all the differences with variables.
You can see your code here https://www.diffchecker.com/FxAIdD6g (1 Day only)
Change a value in a winlogbeat.yml as it is passed to serveral remote servers. Here is the value to change > hosts: localhost:5044 and when script kicks off on remote server it is to change to >lp-index-QA.QA.com:9999
Here is the script I wrote.. no failures but does not pass the new value to remote server>>
#ExecutionPolicy
Set-ExecutionPolicy -Force Unrestricted
#DC = (facter datacenter) | Out-String
$DC = 'parpr1'
$QAhost = #("hosts: lp-index-QA.QA.com:9999", "`r`nhosts: localhost:5044")
$PRODhost = #("hosts: lp-index-PROD.PROD.com:9999", "`r`nhosts: localhost:5044")
$file = 'C:\winlogbeat-1.2.3-windows\winlogbeat.yml'
if ($DC -eq "QA")
{
Write-Host "Datacenter is $DC"
Add-Content -PassThru -Path "$file" -Value "hosts: lp-index-QA.QA.com:9999"
}
if ($DC -eq "PROD")
{
Write-Host "Datacenter is $DC"
Add-Content -PassThru -Path "$file" -Value "hosts: lp-index- PROD.PROD.com:9999"
}
# delete service if it already exists
if (Get-Service winlogbeat -ErrorAction SilentlyContinue) {
$service = Get-WmiObject -Class Win32_Service -Filter "name='winlogbeat'"
$service.StopService()
Start-Sleep -s 1
$service.delete()
}
$workdir = Split-Path $MyInvocation.MyCommand.Path
# create new service
New-Service -name winlogbeat `
-displayName winlogbeat `
-binaryPathName "`"$workdir\\winlogbeat.exe`" -c `"$workdir\\winlogbeat.yml`""
#pause 5s
Start-Sleep -s 10
#Startingserver
Start-service winlogbeat
Currently I have this code -
Set-ExecutionPolicy Unrestricted
$name = (Get-WmiObject win32_bios).SerialNumber.Trim()
$oldname = (Get-WmiObject win32_computersystem).Name.Trim()
IF ($oldname -eq $name){Exit}
Else{ Rename-computer -ComputerName $oldname -NewName "$name" -force
Start-Sleep -s 5
Restart-Computer}
And I have it set to run as a scheduled task at logon and without the If Else it works perfectly however I don't want it to run every time a user logs in because it will just be a cycle of rebooting. Any help would be greatly appreciated.
I would suggest some changes:
Set-ExecutionPolicy is unnecessary, because if the machine has started processing the script, then the executionpolicy isn't a problem. So remove that, and specify it in the powershell.exe-call instead, like: powershell.exe -executionpolicy unrestricted
Use if($oldname -ne $name) { rename-computer .... } so you can remove the else part. Much cleaner
Try running the modified script below, and report back with the output in the scriptlog.txt-file.
$logpath = "c:\scriptlog.txt"
$name = (Get-WmiObject win32_bios).SerialNumber.Trim()
$oldname = (Get-WmiObject win32_computersystem).Name.Trim()
"NewName is '$name'" | Out-File $logpath -Append
"OldName is '$oldname'" | Out-File $logpath -Append
IF ($oldname -ne $name){
"If-test TRUE" | Out-File $logpath -Append
Rename-computer -ComputerName $oldname -NewName $name -Force
Start-Sleep -s 5
Restart-Computer
} else { #I've added the else-part just because of logging.
"IF-test FALSE" | Out-File $logpath -Append
}