Powershell script to Check and keep program running - powershell

Making a short script to keep a program that crashes every now and then running,
Here is what I am trying and been editing
$date = Get-Date -Format G
Function Loop {
{ if(Get-Process -Name notepad -ErrorAction SilentlyContinue) -eq $null
write-host -ForegroundColor red "Server Is Not Running"
.\eldorado.exe -launcher -dedicated -headless -window -height 300 -width 300
echo "Guardian Started Headless Eldorito Server $($date)" | Add-Content .\dedicatedServer.log }
else {write-host -ForegroundColor green "Server Is Running"
sleep 10
Loop
}
Loop
}
What am I doing wrong? / New to scripting / programming

Writing a mash of code, or not copy and pasting properly?
$date = Get-Date -Format G # OK
Function Loop { # OK
# no, your function now starts with a scriptblock
# no, your if () {} pattern is broken.
{if(Get-Process -Name notepad -ErrorAction SilentlyContinue) -eq $null
# ok, but formatting makes it hard to read
write-host -ForegroundColor red "Server Is Not Running"
.\eldorado.exe -launcher -dedicated -headless -window -height 300 -width 300
echo "Guardian Started Headless Eldorito Server $($date)" | Add-Content .\dedicatedServer.log }
#ok
else {write-host -ForegroundColor green "Server Is Running"
sleep 10
# not ok, your loop is now a recursive function call which will consumer more resources forever until it crashes
Loop
}
# what's this doing?
Loop
}
It doesn't seem like you need a function at all, just a loop..
->
$date = Get-Date -Format G
while ($true)
{
if ((Get-Process -Name notepad -ErrorAction SilentlyContinue) -eq $null)
{
Write-Host -ForegroundColor Red "Server Is Not Running"
.\eldorado.exe -launcher -dedicated -headless -window -height 300 -width 300
"Guardian Started Headless Eldorito Server $($date)" | Add-Content .\dedicatedServer.log
}
else
{
write-host -ForegroundColor Green "Server Is Running"
}
Start-Sleep -Seconds 10
}

Related

Script that prompts users to restart PC with option to delay, then forces a restart after the delay

I have the following script that is successful in prompting users to restart their computers. The script prompts users to restart their computers every 10 minutes for an hour. Users can delay the restart each time. However, the script doesn't force the restart once the 60 minutes has expired. Also, the PS session window is open throughout the 60 minutes that the script is running - is there a way to hide the PS window from view? Thank you for your help!
I've added code that I'd hoped would display a notification and proceed with a forced restart, but am receiving the following error in PS:
"Get-Date : Cannot bind parameter 'Date'. Cannot convert value "if" to type "System.DateTime". Error: "The string was
not recognized as a valid DateTime. There is an unknown word starting at index 0."
At C:\scripts\Reboot_Toast.ps1:47 char:21
$TimeNow = Get-Date if ($TimeNow -ge $TimeEnd) { shutdown -r -f -t 60 ...
The entire script is as follows:
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | out-null
$TimeStart = Get-Date
$TimeEnd = $timeStart.addminutes(60)
Do
{
$TimeNow = Get-Date
if ($TimeNow -ge $TimeEnd)
{
Unregister-Event -SourceIdentifier click_event -ErrorAction SilentlyContinue
Remove-Event click_event -ErrorAction SilentlyContinue
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
Exit
}
else
{
$Balloon = new-object System.Windows.Forms.NotifyIcon
$Balloon.Icon = [System.Drawing.SystemIcons]::Information
$Balloon.BalloonTipText = "IT is requiring a reboot in order to maintain system stability supporting IT security measures. Please reboot at your earliest convenience."
$Balloon.BalloonTipTitle = "Reboot Required"
$Balloon.BalloonTipIcon = "Warning"
$Balloon.Visible = $true;
$Balloon.ShowBalloonTip(20000);
$Balloon_MouseOver = [System.Windows.Forms.MouseEventHandler]{ $Balloon.ShowBalloonTip(20000) }
$Balloon.add_MouseClick($Balloon_MouseOver)
Unregister-Event -SourceIdentifier click_event -ErrorAction SilentlyContinue
Register-ObjectEvent $Balloon BalloonTipClicked -sourceIdentifier click_event -Action {
Add-Type -AssemblyName Microsoft.VisualBasic
If ([Microsoft.VisualBasic.Interaction]::MsgBox('Would you like to reboot your machine now?', 'YesNo,MsgBoxSetForeground,Question', 'System Maintenance') -eq "NO")
{ }
else
{
shutdown -r -f
}
} | Out-Null
Wait-Event -timeout 600 -sourceIdentifier click_event > $null
Unregister-Event -SourceIdentifier click_event -ErrorAction SilentlyContinue
$Balloon.Dispose()
$TimeNow = Get-Date if ($TimeNow -ge $TimeEnd) { shutdown -r -f -t 600 -c "You have reached the allotted time for reboot delay. Please save your work and reboot or your computer will automatically reboot in 10 minutes." }
}
}
Until ($TimeNow -ge $TimeEnd)
This should be two lines, not one:
$TimeNow = Get-Date if ($TimeNow -ge $TimeEnd) { shutdown -r -f -t 600 -c "You have reached the allotted time for reboot delay. Please save your work and reboot or your computer will automatically reboot in 10 minutes."
Put a line break after Get-Date i.e.
$TimeStart = Get-Date
$TimeEnd = $TimeStart.addseconds(10)
Write-Host "Waiting" -NoNewline
Do {
$TimeNow = Get-Date
Write-Host "." -NoNewline
If ($TimeNow -ge $TimeEnd) {
Write-Host "Time's up"
# shutdown -r -f -t 600 -c "You have reached the allotted time for reboot delay. Please save your work and reboot or your computer will automatically reboot in 10 minutes."
}
Sleep 1
}
Until ($TimeNow -ge $TimeEnd)
If you launch your script as follows, it should hide the PS console window:
powershell.exe -Windowstyle Hidden -File PathToScript.ps1

How to restart process if it crashes using powershell?

I'm trying to run Core Keeper Dedicated Server, everything seems fine, but from time to time CoreKeeperServer.exe crashes. So main Powershell script what launches it not tracking is it crashed or not. How do i need to modify this script, so it constantly (every 1-5 seconds or so) monitored if process still running or not, and start it again if it is? Also i want to keep "press q to exit" functionality what already included in stock script.
Stock script:
# Feel free to change these (see README), but keep in mind that changes to this file might be overwritten on update
$CoreKeeperArguments = #("-batchmode", "-logfile", "CoreKeeperServerLog.txt") + $args
$script:ckpid = $null
function Quit-CoreKeeperServer {
if ($script:ckpid -ne $null) {
taskkill /pid $ckpid.Id
Wait-Process -InputObject $ckpid
Write-Host "Stopped CoreKeeperServer.exe"
}
}
try {
if (Test-Path -Path "GameID.txt") {
Remove-Item -Path "GameID.txt"
}
$script:ckpid = Start-Process -PassThru -FilePath %0\..\CoreKeeperServer.exe -ArgumentList $CoreKeeperArguments
Write-Host "Started CoreKeeperServer.exe"
# Wait for GameID
while (!(Test-Path -Path "GameID.txt")) {
Start-Sleep -Milliseconds 100
}
Write-Host -NoNewline "Game ID: "
Get-Content "GameID.txt"
Write-Host "Press q to quit, DON'T close the window or the server process will just keep running"
While ($KeyInfo.VirtualKeyCode -eq $Null -or $KeyInfo.VirtualKeyCode -ne 81) {
$KeyInfo = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown")
}
}
finally {
Quit-CoreKeeperServer
pause
}
Solved problem like this:
# Feel free to change these (see README), but keep in mind that changes to this file might be overwritten on update
$CoreKeeperArguments = #("-batchmode", "-logfile", "CoreKeeperServerLog.txt") + $args
$script:ckpid = $null
function Quit-CoreKeeperServer {
if ($script:ckpid -ne $null) {
taskkill /pid $ckpid.Id
Wait-Process -InputObject $ckpid
Write-Host "Stopped CoreKeeperServer.exe"
}
}
try {
if (Test-Path -Path "GameID.txt") {
Remove-Item -Path "GameID.txt"
}
$script:ckpid = Start-Process -PassThru -FilePath %0\..\CoreKeeperServer.exe -ArgumentList $CoreKeeperArguments
Write-Host "Started CoreKeeperServer.exe"
# Wait for GameID
while (!(Test-Path -Path "GameID.txt")) {
Start-Sleep -Milliseconds 100
}
Write-Host -NoNewline "Game ID: "
Get-Content "GameID.txt"
Write-Host "Server is runnig. Press CTRL + C to stop."
While ($true) {
if (-not (Get-Process -Id $ckpid.Id -ErrorAction SilentlyContinue)) {
Write-Host “Server is died restarting...”
Get-Date
$script:ckpid = Start-Process -PassThru -FilePath %0\..\CoreKeeperServer.exe -ArgumentList $CoreKeeperArguments
Write-Host "Started CoreKeeperServer.exe"
Write-Host -NoNewline "Game ID: "
Get-Content "GameID.txt"
Write-Host "Server is runnig. Press CTRL + C to stop."
sleep 1
}
}
}
finally {
Quit-CoreKeeperServer
pause
}

how to automate Wusa with remoting and overcoming the lack of wait cmd

Scenario: Taking a list of kb files and executing them remotely with WUSA install of target machines across network.
The flow is like this:
enter a powershell session W/ target computer
for each loop $KB in $List
wusa.exe $kb
wait 'til installed
back to the wusa.exe for next device in $list
Code:
# SET UP ERROR-HANDLING FOR THE PS SESSION
$ErrorActionPreference = "continue"
# DECLARE VARIABLE THAT CONTAINS LIST OF PATCHES AVAILABLE FOR INSTALL
$PatchList = (Get-ChildItem -Path C:\WinPatch -recurse | Where-Object {$_.Extension -eq '.msu'})
# ESTABLISH LOOP TO ITERATE THRU PATCHES
foreach ($Patch in $PatchList)
{
Try
{
Write-Host ("`n Preparing to install: " + $Patch) -ForegroundColor Yellow
Write-Host ("`n Installing...") -ForegroundColor Magenta
$SB = {
$arglist = "$Patch", "/quiet", "/norestart"
Start-Process -FilePath "C:\windows\system32\wusa.exe" -ArgumentList $arglist -Wait}
Invoke-Command -ScriptBlock $SB
Write-Host "`n Installation complete`n" -ForegroundColor Green
}
Catch
{
[System.Exception]
Write-Host "Installation failed with Error -- $Error()" -ForegroundColor Red
$Error.Clear()
}
}
# RESTART OPTIONS
$Ans1 = Read-Host "`n Would you like to restart this computer now (Type Y for yes or N for no)"
if ($Ans1 -eq 'Y' -or $Ans1 -eq 'y')
{
Remove-Item -Path C:\WinPatch\*.msu -Force
Write-Host "`n This computer will restart in 5 seconds..." -ForegroundColor Yellow
Start-Sleep -Seconds 5
Restart-Computer -Force
}
else
{
# TEST COMPUTER FOR PS VERSION
$Tester = test-wsman -computername localhost | Select-Object -Property ProductVersion
if ($Tester.ProductVersion.EndsWith("1.0"))
{
Write-Host "`n This computer has PS v1.0 installed and you will have to open Task Scheduler to schedule restart" -ForegroundColor Red
Read-Host "`n Press ENTER to continue..."
}
elseif ($Tester.ProductVersion.EndsWith("2.0"))
{
Write-Host "`n This computer has PS v2.0 installed and you will have to open Task Scheduler to schedule restart" -ForegroundColor Red
Read-Host "`n Press ENTER to continue..."
}
else
{
# SCHEDULE RESTART
Import-Module PSScheduledJob
$RST = Read-Host -Prompt "`n Enter date/time to restart computer...format is --> mm/dd/yyyy hh:mmAM/PM"
$Ans2 = Read-Host -Prompt "`n You entered: $RST... if this is correct, enter Y for yes"
if ($Ans2 -eq 'Y' -or $Ans2 -eq 'y')
{
$Nomen = Read-Host -Prompt "`n Enter name for scheduled restart "
$Trig = New-JobTrigger -Once -At $RST
Register-ScheduledJob -Name $Nomen -Trigger $Trig -ScriptBlock { Restart-Computer -force } -RunAs32
}
else
{
Write-Host "`n Please restart the script and try again" -ForegroundColor Red
}
}
}
Break
PsExec.exe -u $domain\$username -p $password -h -s -accepteula \\$computer wusa.exe /quiet 'C:\Program Files\WindowsPowershell\Modules\windows10.0-kb5005112-x64.msu' /wait /forcerestart
This works for me. If you wrap this in an Invoke-Command block you can run this remotely. :-)
Thanks,

Speed up Test-Connection before Foreach

I made a script to check if users desktop folder are under the cuota limitation, if they're under the cuota limitation the backup to the server will be done correctly.
each user have his computer, so source CSV looks like:
pc1,user1
pc2,user2
pc800,user800
Some computers are Windows Xp and some W7, and the paths can be different 'cause of that I'm using Test-Path
W7 = C:\users\$user\desktop
XP = C:\document and settings\$user\desktop
But Test-Path is SUPER SLOW and I started to use a Test-Connection -count 1 before each Test-path
Anyway, the script still SLOW, in each "bad ping test" I lose lot of time.
CODE:
$csvLocation = '~\desktop\soourceReport.csv'
$csv = import-csv $csvLocation -Header PCName, User
$OuputReport = '~\desktop\newReport.csv'
# info:
# "209715200" Bytes = 200 MB
$cuota = "209715200"
$cuotaTranslate = "$($cuota / 1MB) MB"
Write-Host "Cuota is set to $cuotaTranslate"
$count=1
foreach($item in $csv)
{
write-host "$count# Revisando" $item.User "en" $item.PCName "..." #For debug
if (Test-Connection -Quiet -count 1 -computer $($item.PCname)){
$w7path = "\\$($item.PCname)\c$\users\$($item.User)\desktop"
#echo $w7path #debug
$xpPath = "\\$($item.PCname)\c$\Documents and Settings\$($item.User)\Escritorio"
#echo $xp #debug
if(Test-Path $W7path){
$desktopSize = (Get-ChildItem -Recurse -force $w7path | Measure-Object -ErrorAction "SilentlyContinue" -property length -sum)
write-host -ForegroundColor Green "access succeed"
if($($desktopSize.sum) -gt $cuota){
$newLine = "{0},{1},{2}" -f $($item.PCname),$($item.User),"$("{0:N0}" -f $($desktopSize.sum / 1MB)) MB"
$newLine | add-content $outputReport
Write-Host -ForegroundColor Yellow "cuota exceeded! -- added"
}
else{
Write-Host -ForegroundColor DarkYellow "cuota OK"
}
}
elseif(Test-Path $xpPath){
$desktopSize = (Get-ChildItem -Recurse -force $xpPath | Measure-Object -ErrorAction "SilentlyContinue" -property length -sum)
write-host -ForegroundColor Green "access succeed"
if($($desktopSize.sum) -gt $cuota){
$newLine = "{0},{1},{2}" -f $($item.PCname),$($item.User),"$("{0:N0}" -f $($desktopSize.sum / 1MB)) MB"
$newLine | add-content $outputReport
Write-Host -ForegroundColor Yellow "cuota exceeded! -- added"
}
else{
Write-Host -ForegroundColor DarkYellow "cuota OK"
}
else{
write-host -ForegroundColor Red "Error! - bad path"
}
}
else{
write-host -ForegroundColor Red "Error! - no ping"
}
$count++
}
Write-Host -ForegroundColor green -BackgroundColor DarkGray "All done! new report stored in $report"
To improve it I stored all computers in a $list using another Foreach, before the firstly mentioned SLOW-Foreach loop.
foreach($pcs in $csv){
$alivelist += #( $pcs.PCName )
}
Test-Connection -quiet -count 2 -computer $alivelist
Now, I don't now how to UPDATE or remove the rows ("dead" pc,user) from the SOURCE CSV before to enter into the second Foreach.
I need some of your "magic", or at least some ideas!
thanks
To speed up your script you need to run the checks in parallel (as others have already mentioned). Put your checks and the worker code in a scriptblock:
$sb = {
Param($computer, $username)
if (Test-Connection -Quiet -Count 2 $computer) { return }
$w7path = "\\$computer\c$\users\$username\desktop"
$xpPath = "\\$computer\c$\Documents and Settings\$username.TUITRA..."
if (Test-Path $W7path) {
#...
} elseif (Test-Path $xpPath) {
#...
} else {
#...
}
}
Then run the scriptblock as parallel jobs:
$csv | ForEach-Object {
Start-Job -ScriptBlock $sb -ArgumentList $_.PCName, $_.User
}
# wait for completion
do {
Start-Sleep -Milliseconds 100
} while (Get-Job -State 'Running')
# cleanup
Get-Job | ForEach-Object {
Receive-Job -Id $_.Id
Remove-Job -Id $_.Id
} | Out-File $outputReport
Use a queue if you need to limit the number of parallel jobs.
test-connection is weirdly fast with the -asjob parameter, pinging about 200 computers in 4 seconds:
$list = cat hp.txt
test-connection $list -AsJob ; job | receive-job -wait -AutoRemoveJob

Code stuck in while loop and not exiting in powershell

I am this weird problem while working with powershell.When I run a while loop to check if the VM tools status, it gets stuck inside only. Here's the code:
Connect-VIServer $vmserver -User $vmuser -Password $vmpass
$status1 = (Get-VM -Name $vmname).Extensiondata.Summary.Guest.ToolsStatus
Write-Host $status1
while(!($status1 -eq 'toolsOK')){
Write-Host "tool status is:" $status1
Start-Sleep -Seconds 5
}
Write-Host "success"
I ran this code when that machine was off and in b/w started that machine($vmname).While it was swtiched off it's understood that "tool status is:"toolsNotRunning.But even after getting switched on and getting the remote of machine it shows same status,whereas I checked in ESXI status was running.I tried the above mentioned thing like it might get stuck so pressed ENTER,Mouse click etc,but no USE..I am using powershell ISE-host,version3.0..
You're only running the update-code once. The while loop only runs the sleep command and write-host (which will never change).. try this:
Connect-VIServer $vmserver -User $vmuser -Password $vmpass
do {
#This will min. once, until $status is 'toolsOK'
$status1 = (Get-VM -Name $vmname).Extensiondata.Summary.Guest.ToolsStatus
if($status1 -ne 'toolsOK') {
Write-Host "tool status is:" $status
Start-Sleep -Seconds 5
}
}
until($status1 -eq 'toolsOK')
Write-Host "success"
or
Connect-VIServer $vmserver -User $vmuser -Password $vmpass
$status1 = (Get-VM -Name $vmname).Extensiondata.Summary.Guest.ToolsStatus
while ($status1 -ne 'toolsOK') {
Write-Host "tool status is:" $status
Start-Sleep -Seconds 5
$status1 = (Get-VM -Name $vmname).Extensiondata.Summary.Guest.ToolsStatus
}
Write-Host "success"