Question

I have a Powershell script that, when firing, grabs data from a couple of flat files, parses it, puts it into a comma-delimited fashion then places it in memory. This data is then passed to a Windows Chart Object (downloaded from here) and a chart is generated.

But how do I refresh it automatically?

I've looked at PoshBoard, but I would like to just grab new data on a time interval and update the existing control.

Here's my proposed logic:

  1. Get data (coded successfully)
  2. Parse Data (coded successfully)
  3. Create and display form (coded successfully)
  4. Update said form without interrupting display --- Run steps 1-2 again on a 30 minute timer and pass it to the chart.

Please note: I create/display the form on a background job, thus it is on a separate thread, otherwise the ".Show()" and ".ShowDialog()" form calls lock up the script. This is being used to monitor important memory usage statistics on gajillion-dollar systems and I can't have scripts locking up.

Please excuse the dirtiness of it. Here's the script:

New-Item -ItemType f -Path c:/batch/lcontents.txt -Force
New-Item -ItemType f -Path c:/batch/gajilliondollarsystem.txt -Force
$form = $null
$zid = Read-Host "What is your ZID?"
$PW = read-host "What is your password?"
""
"If this hangs for more than 20 seconds, your credentials are wrong."
""
# Get contents of /import/sftw/vmstat_***.txt

c:\batch\plink.exe ***-admin -l $zid -pw $PW "cat /import/sftw/vmstat_***.txt" > c:\batch\lcontents.txt

""
"Credentials accepted."
""

# Select specific information from cat file for last 36 hours (Every half hour (72), 3 entries per (72x3 = 216)

Select-String -Path C:\batch\lcontents.txt -SimpleMatch "CDT", "Free memory", "Inactive memory" | select -last 216 > c:\batch\lcontentsnew.txt

# Extract contents of lcontentsnew into memory

$loglist = gc c:\batch\lcontentsnew.txt | ?{$_.trim() -ne ""} | %{ $_ -replace ".*txt:\d+:"}

# rewrite in comma-delimited fashion

$count1 = 0
$count2 = 1
$count3 = 2
$gajilliondollarsystemlist = @()

do {
$gajilliondollarsystemlist += "$($loglist[$count1].trim()),$($loglist[$count2].trim()),$($loglist[$count3].trim())" 
$count1+=3 
$count2+=3 
$count3+=3
} 
until ($count1 -gt $loglist.count-3)

add-content c:\batch\gajilliondollarsystem.txt $gajilliondollarsystemlist

#Import-CSV for grouping purposes

$list = import-csv c:\batch\gajilliondollarsystem.txt -Delimiter "," -Header "Date","Inactive","Free"
$list | export-csv C:\Batch\gajilliondollarsystem.csv -Delimiter "," -NoTypeInformation


$ldate = $list.date
$linactive = ($list.inactive -replace " M inactive memory").trim()
$lfree = ($list.free -replace " M free memory").trim()

# Convert free and inactive to integers
$linactiveint = @()
$lfreeint = @()

foreach ($l in $linactive) {
$linactiveint += [int]$l
}

foreach ($l in $lfree) {
$lfreeint += [int]$l
}

#Combine free and inactive quantities into $lcombined
$count = 0
$lcombined = @()

do
{
$lcombined += ($linactiveint[$count] + $lfreeint[$count])
$count++
} 
until ($count -eq $lfreeint.count)

function GraphData {
# load the appropriate assemblies for charting
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms.DataVisualization")

# create chart object 
$Chart = New-object System.Windows.Forms.DataVisualization.Charting.Chart 
$Chart.Width = 900
$Chart.Height = 300
$Chart.Left = 0 
$Chart.Top = 0

# create a chartarea to draw on and add to chart 
$ChartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea 
$Chart.ChartAreas.Add($ChartArea)

# add data to chart 
[void]$Chart.Series.Add("Inactive") 
[void]$Chart.Series.Add("Free")
[void]$Chart.Series.Add("Combined")
$Chart.Series[0].Points.DataBindXY($args[0], $args[2])
$Chart.Series[1].Points.DataBindXY($args[0], $args[1])
$Chart.Series[2].Points.DataBindXY($args[0], $args[3])

# set chart type 
$Chart.Series[0].ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Line
$Chart.Series[1].ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Line
$Chart.Series[2].ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Line

#format the lines
$chart.series[0].BorderWidth = 3
$chart.series[0].Color = "Blue"

$chart.series[1].BorderWidth = 3
$chart.series[1].Color = "Red"

$chart.series[2].BorderWidth = 3
$chart.series[2].Color = "Green"

# add title and axes labels 
[void]$Chart.Titles.Add("gajilliondollarsystem Memory Monitoring Trend (36 Hrs.)") 


# change chart area colour 
$Chart.BackColor = [System.Drawing.Color]::Transparent

# Legend Properties
$chart.legends.add("Inactive")
$chart.legends.add("Free")
$chart.legends.add("Combined")

#axis titles
$chart.chartareas.axisx.title = "Date"
$chart.chartareas.axisy.title = "Memory in MB"



# save chart to file 
$Chart.SaveImage($Env:USERPROFILE + "\Desktop\Chart.png", "PNG")

# display the chart on a form 
$Chart.Anchor = [System.Windows.Forms.AnchorStyles]::Bottom -bor [System.Windows.Forms.AnchorStyles]::Right -bor 
                [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left 

$Form = New-Object Windows.Forms.Form 
$Form.Text = "PowerShell Chart $(get-date)" 
$Form.Width = 950 
$Form.Height = 325
$Form.controls.add($Chart) 
# $Form.Add_Shown({$Form.Activate()}) 
$form.startposition = "CenterScreen"
$Form.ShowDialog()
} 

#clear-host

Start-Job $function:GraphData -argumentlist @($ldate, $lfreeint, $linactiveint, $lcombined)

clear-host
Read-Host "Press ENTER to continue." 

get-job | %{remove-job $_ -Force}
Was it helpful?

Solution 2

After involving another resource in trying to fix the problem, I found it to be a much simpler fix: run a perpetual do-loop with recursive function call on a timer. Works like a charm! Thanks, @sqlchow for the clear points as well. It was instrumental in making sense of some issues that occurred once I actually got it to refresh.

$foo = $false

$form = $null
$zid = Read-Host "What is your ZID?"
$PW = Get-Credential -UserName $zid -Message "Please supply your password."

""
"If this hangs for more than 20 seconds, your credentials are wrong."
""

Do {
 # Do lots of stuff here to collect the data and parse it

function GraphData {
# Do the stuff here to graph the data, apply it to a form and display it
} 

#clear-host

Start-Job $function:GraphData -argumentlist @($ldate, $lfreeint, $linactiveint, $lcombined)

#Wait 30 minutes
start-sleep -s 1800

"Checking processes."

#grab process for window based on defined window title in GraphData
$proc = Get-Process | Where-Object {$_.MainWindowTitle -like "<TITLE>"}

#kill the process, closing the window
kill $proc.id

#clear background jobs
get-job | %{remove-job $_ -Force}

}
While ($foo -eq $false)

OTHER TIPS

As far as I know, to refresh data on a chart; you need to clear the existing points first.

$Chart.Series[2].Points.Clear()
$Chart.Series[2].Points.DataBindXY($args[0], $args[3])

Also, remember to auto-scale the Y-axis

#auto-scale Y-axis
$Chart.ChartAreas.AxisY.Minimum = [Double].NaN
$Chart.ChartAreas.AxisY.Maximum = [Double].NaN
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top