I'm writing a PowerShell script that is constantly checking the status of a game server that I'm running and, depending on the states of certain exe's and variables, certain things will happen. The way I have this constructed is, first I have a timer start and I have a while loop that runs up until the timer hits 280 seconds. Within this while loop there are a series of if than else statements that look at all of the aforementioned variable and states of exe's and then they execute different things. What I'd like is that when it gets to the end of a condition (if the exe is not found and the server status is 0), then email me about that and then go back to the beginning of the entire while loop and keep looping and checking the status of the server.
Here is the script right now in:
//$serverStatus = 1 means servers up, 0 means down, 3 means crashed
$timeout = new-timespan -Seconds 280
$sw = [diagnostics.stopwatch]::StartNew()
while ($sw.elapsed -lt $timeout){
Start-Sleep -Seconds 10
if (((get-process $process -ea SilentlyContinue) -eq $Null) -And ($serverStatus -eq "1")) {
#Server is down and email
"0" > "D:\Ark Scripts\serverStatus.txt"
Write-Host "it's down - email"
sendMail -sendTo "my email" -emailBody "Ark Server is down."
} elseif (((get-process $process -ea SilentlyContinue) -eq $Null) -And ($serverStatus -eq "0")) {
#Server is down and we are aware
Write-Host "it's down - we know"
} elseIf (((get-process $process -ea SilentlyContinue) -ne $Null) -And ($serverStatus -eq "0")) {
#Server is up and email
"1" > "D:\Ark Scripts\serverStatus.txt"
Write-Host "it's up - email"
sendMail -sendTo "my email" -emailBody "Ark Server is back up."
} elseif ($serverStatus -eq "3") {
Send-RCON "listplayers" > "D:\Ark Scripts\RCONlog.txt"
$log = Get-Content "D:\Ark Scripts\RCONlog.txt"
if ($log -eq "Authentication failed!") {
Write-Host "crashed and we know"
} else {
"1" > "D:\Ark Scripts\serverStatus.txt"
Write-Host "Back up"
}
} else {
#Checks RCON connection for crashes and sends crash email if connection fails.
Send-RCON "listplayers" > "D:\Ark Scripts\RCONlog.txt"
$log = Get-Content "D:\Ark Scripts\RCONlog.txt"
if ($log -eq "Authentication failed!") {
Write-Host "crashed"
"3" > "D:\Ark Scripts\serverStatus.txt"
sendMail -sendTo "my email" -emailBody "Ark Server has crashed."
return
} else {
"1" > "D:\Ark Scripts\serverStatus.txt"
Write-Host "it's up"
}
}
}
Exit-PSSession
I just want this while loop to keep running every 10 seconds to check the state of the variables and whether the exe is found and constantly cycle.
This wont work, script will never go into the section "#Server is up and email will never"
} elseif (((get-process $process -ea SilentlyContinue) -eq $Null) -And ($serverStatus -eq "0")) {
#Server is down and we are aware
Write-Host "it's down - we know"
} elseIf (((get-process $process -ea SilentlyContinue) -ne $Null) -And ($serverStatus -eq "0")) {
#Server is up and email
You should nest your if statements to get a clear picture of what your doing
Related
For a group of computers, I want to connect to each one, enumerate each NIC that has a real IP, and for each NIC I want to loop through each DNS server (first, second, third, fourth, fifth etc) and if it contains a specific IP (e.g. 8.8.8.8) I want to replace it (with 7.7.7.7) without affecting any other DNS Servers. How do I do this for X number of DNS Servers without doing each server entry one at a time (like I have done below for the first 3) and change it at the same time.
$computer ='wrk-01'
$NICs = Get-WMIObject Win32_NetworkAdapterConfiguration -computername $computer |
where{$_.IPEnabled -eq "TRUE"}
Foreach($NIC in $NICs) {
# $DNSServerCount = $Nic.DNSServerSearchOrder.Count
# $DNSServerArray = #($nic.DNSServerSearchOrder[$DNSServerCount - $DNSServerCount,$DNSServerCount - $DNSServerCount + 1,$DNSServerCount - $DNSServerCount + 2])
# write-host $nic.description
# write-host $nic.PSComputerName $DNSServerArray
if($nic.dnsserversearchorder[0] -like "8.8.8.8"){
write-host "matched 8.8.8.8 at position 0"
$NIC.SetDNSServerSearchOrder(#("7.7.7.7", $nic.dnsserversearchorder[1], $nic.dnsserversearchorder[2]))
}
if($nic.dnsserversearchorder[1] -like "8.8.8.8"){
write-host "matched 8.8.8.8 at position 1"
$NIC.SetDNSServerSearchOrder(#($nic.dnsserversearchorder[0],"7.7.7.7", $nic.dnsserversearchorder[2]))
}
if($nic.dnsserversearchorder[2] -like "8.8.8.8"){
write-host "matched 8.8.8.8 at position 2"
$NIC.SetDNSServerSearchOrder(#($nic.dnsserversearchorder[0], $nic.dnsserversearchorder[1],"7.7.7.7"))
}
}
Here's one way to check and update if there is a match. Once a match is found, it will replace any matching line with the desired replacement otherwise output, the collected list is then set as the new DNS servers. If none match, it will just continue to the next nic.
$computer ='wrk-01'
$NICs = Get-WMIObject Win32_NetworkAdapterConfiguration -computername $computer |
where{$_.IPEnabled -eq "TRUE"}
Foreach($NIC in $NICs)
{
$DNSIPs = $nics.DNSServerSearchOrder
if($DNSIPs -contains '8.8.8.8')
{
Write-Host "Match found... updating" -ForegroundColor Green
$NewDNS = $DNSIPs | foreach {
$_ -replace '8.8.8.8','7.7.7.7'
}
$null = $NICs.SetDNSServerSearchOrder($NewDNS)
}
}
One recommendation that may save you some headache is to not use plural variable names, but instead use a descriptive name like this.
$computer ='wrk-01'
$NICList = Get-WMIObject Win32_NetworkAdapterConfiguration -computername $computer |
where{$_.IPEnabled -eq "TRUE"}
Foreach($NIC in $NICList)
{
$DNSIPList = $nics.DNSServerSearchOrder
if($DNSIPList -contains '8.8.8.8')
{
Write-Host "Match found... updating" -ForegroundColor Green
$NewDNS = $DNSIPList | foreach {
$_ -replace '8.8.8.8','7.7.7.7'
}
$null = $NICs.SetDNSServerSearchOrder($NewDNS)
}
}
I made this script to monitor free space of server partitions. Now I'm trying to compare latest loop with previous one with storing free space values to arrays, but I've never done anything like this.
I don't know how exactly to work with arrays - one has to be erased at the beginning of the loop and second has to store the previous values, then they have to be compared.
Could you please give me at least a hint?
#play star-wars imperial march
function play-alarm {
Start-Job {
[Console]::Beep(440,500)
}
}
$cred = Get-Credential domain\username
$hostname = "server1"
#if free space lower, then play alarm
$low_level = "10"
#get drives letters
$partitions = Get-WmiObject Win32_LogicalDisk -Computername $hostname -Credential $cred | foreach DeviceID
#create arrays
$old_values = New-Object System.Collections.ArrayList
$new_values = New-Object System.Collections.ArrayList
#noob loop
$repeat = "2"
while ($i -lt $repeat) {
Write-Host " *** " -ForegroundColor Yellow
Write-Host " *** " -ForegroundColor Yellow
Write-Host " *** " -ForegroundColor Yellow
Write-Host "Free space at server:" -BackgroundColor Black
#backup previouse values and clear array for new ones
$old_values = $new_values
$new_values.Clear()
foreach ($partition in $partitions) {
$device = "DeviceID='" + $partition + "'"
$size = Get-WmiObject Win32_LogicalDisk -Credential $cred -ComputerName $hostname -Filter $device |
ForEach-Object {$_.Size}
$size = [Math]::Round($size/1GB)
$free = Get-WmiObject Win32_LogicalDisk -Credential $cred -ComputerName $hostname -Filter $device |
ForEach-Object {$_.FreeSpace}
$free = [Math]::Round($free/1GB)
Write-Host $free
#add value rounded to GB
$new_values.Add($free)
#if device is CD-ROM, the size or space is zero - this cause error when calculating percentage of free space
if ($size -eq "0") {
Write-Host "disk " $partition "is CD-ROM" -ForegroundColor Yellow
} else {
$perc = ($free/$size)*100
$perc = [Math]::Round($perc, 3)
if ($perc -le $low_level) {
Write-Host "Not enough free space at partition " $partition "!!!" $perc "%" -BackgroundColor Red #| play-alarm
Start-Sleep -s 15
} else {
Write-Host "disk " $partition "is OK - " $perc "%" -ForegroundColor Green
}
}
}
if ($old_values -eq $new_values) {
Write-Host "no change..."
} else {
Write-Host "Attention - change!!!" -BackgroundColor Red
}
$time = $((Get-Date).ToString())
Write-Host "Loop finished..." $time -BackgroundColor Black
Write-Host " *** " -ForegroundColor Yellow
Write-Host " *** " -ForegroundColor Yellow
Write-Host " *** " -ForegroundColor Yellow
Start-Sleep -s 300
}
Copy previous values
$old_values = $new_values
$new_values.Clear()
The problem with this is $old_values is now referring to the same array as $new_values. Use
$old_values = $new_values.Clone()
to create a copy.
Compare
You don't want to use -eq to compare the contents of container objects. You can loop through the arrays and compare each element
for ($index=0;$index -lt $old_values.count;$index+=1) {
if ($old_values[$index] -ne $new_values[$index]) {
write-host "Changed!"
break
}
}
Or you can use Compare-Object
if (Compare-Object $old_values $new_values) {
write-host "No Change!"
} else {
write-host "Changed!"
}
Compare-Object returns a list of differences. If the contents you compare are the same, then it returns an empty (and boolean false) value.
If you want to compare current values to those of a previous run you need to store the current values somewhere at the end of the script (in a CSV file for instance), and read that file (if it exists) at the beginning of the script.
$csv = 'C:\path\to\data.csv'
if (Test-Path -LiteralPath $csv) {
$old_values = Import-Csv $csv
} else {
# initialize $old_values as an empty array if the file doesn't exist (yet)
$old_values = #()
}
...
$new_values | Export-Csv $csv -NoType
Build $new_values as a list of custom objects by selecting the relevant properties of the WMI data. Avoid formatting the diskspace data unless it's for output to the user.
$new_values = Get-WmiObject Win32_LogicalDisk -Computer $hostname -Credential $cred |
Select-Object DeviceID, Size, FreeSpace
You can use calculated properties for adding derived information (like the free disk space ratio):
... | Select-Object DeviceID, Size, FreeSpace, #{n='Ratio';e={$_.FreeSpace/$_.Size}}
Use Compare-Object for comparing old and new data:
Compare-Object -ReferenceObject $old_values -DifferenceObject $new_values -Property DeviceID, Size, FreeSpace
The below code is designed to check two hard-coded service names (these will never change) and if they are not found to then state the services are not present. It does this but it outputs two lines as there are two services to check.
Is there a way to alter this so that only one output is given after checking both services?
$servicenames = ("Service 1", "Service 2")
Write-Host 'Checking for Services'
function servicevalidation {
foreach ($sn in $servicenames) {
if ((Get-Service "$servicenames*" -Include $servicenames) -eq $null) {
Write-Host 'Young jedi you are mistaken, this server is not a collector!'
} else {
Write-Host "$servicenames present"
}
}
}
Get-Service accepts a list of services, so you can simply do the following without a loop. I would recommend passing the services as an argument, though, if you're encapsulating the check in a function anyway.
function servicevalidation($svc) {
if (Get-Service $svc -ErrorAction SilentlyContinue) {
Write-Host 'Young jedi you are mistaken, this server is not a collector!'
} else {
Write-Host "$svc present."
}
}
servicevalidation $servicenames
The -ErrorAction SilentlyContinue suppresses error output in case a service is not present.
If you want to know which service exactly is missing you could do so with a Where-Object filter:
function servicevalidation($svc) {
$missing = $svc | Where-Object {
-not (Get-Service $_ -ErrorAction SilentlyContinue)
}
if ($missing) {
Write-Host "missing service: $missing"
} else {
Write-Host "$svc present."
}
}
I have written a Do..Until statement to check whether a file exists. If the file is not there, it waits a couple seconds and checks again.
It is supposed to end when the file appears. I have tested by running the script without the file and then adding it in the folder as the script is running.
Instead of ending, it continues to loop endlessly. Can anyone see what I have missed?
$path = test-path "C:\Temp\test.txt"
do {
if (!($path)) {
Write-Host "Not here yet..."
Start-Sleep -s 3
}
} until($path)
Write-Host "Files here now"
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
The Test-Path statement is evaluated in the line
$path = Test-Path "C:\Temp\test.txt"
After that the variable $path contains the boolean result of the evaluation. Put the actual check in your conditions:
$path = "C:\Temp\test.txt"
do {
if (-not (Test-Path $path)) {
Write-Host "Not here yet..."
Start-Sleep -s 3
}
} until (Test-Path $path)
or define it as a function that you call in your conditions:
function Test-File {
Test-Path "C:\Temp\test.txt"
}
do {
if (-not (Test-File)) {
Write-Host "Not here yet..."
Start-Sleep -s 3
}
} until (Test-File)
OK, figured it out 3 minutes after posting this (and an hour before that of frustration!).
I needed to put the variable INSIDE the Do..Until statement. Like so:
do{
$path = test-path "C:\Temp\test.txt"
if (!($path))
{Write-Host "Not here yet..."
start-sleep -s 3}
}
until($path)
Write-Host "Files here now"
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
I am trying to call a powershell script using psexec which connects to remote system
So from "Computer A" I call the batch file Aot.bat which is on "Computer B"
Aot.bat has a line which calls the powershell
powershell.exe %SystemRoot%\system32\aot.ps1 -ComputerName AotServ01 >>\Aot01\AOtShared\Yuma.txt;exit
I can see that the connection is made and powershell runs, but then it does not exit
So please advise what can be done or added
Aot.ps1 reads the Memory and CPU at the present Moment
[cmdletbinding()]
[cmdletbinding()]
param(
[parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[string[]]$ComputerName = $env:computername)
begin {
Get-Module –ListAvailable | import-module
Add-PSSnapin Citrix*
Set-executionpolicy -scope currentuser -executionpolicy unrestricted
$date = Get-Date -Format yyyMMdd
$Zip = "\\na02\KCRC\IRD_KFLOWRPT\Citrix_" + $date + "\Citrix_" + $date + ".txt"
$time = Get-Date -format F
}
process
{
foreach($Computer in $Computername)
{
$free = ( Get-WMIObject Win32_OperatingSystem -ComputerName $computer ).FreePhysicalMemory
$phys = ( Get-WMIObject Win32_OperatingSystem -ComputerName $computer ).TotalVisibleMemorySize
$Percentage = (($phys-$free)/$Phys) * 100
$proc =get-counter -Counter "\Processor(_Total)\% Processor Time" -SampleInterval 2
$cpu=($proc.readings -split ":")[-1]
write-host "`r`n*********************************************************************************"
write-host "`r`nComputer: " $computer
write-host "`r`n_________________________________________________________________________________"
write-host "`r`nPercentage Memory user Used: " $Percentage
write-host "`r`n"
write-host "`r`nPercentage CPU Used: " $cpu
write-host "`r`n_________________________________________________________________________________"
write-host "`r`n"
write-host $time
}
}
end
{
write-host "`r`n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
write-host "`r`n END OF FILE "
write-host "`r`n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
}
===============================================================================