简体   繁体   中英

Compare values with previous loop

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 technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM