Search code examples
arrayspowershelltype-conversionmeasure

How do i convert my values in an array/object to measure them?


i am new to stackoverflow and i'm not really a powershell crack. Maybe you can help me with my problem. For monitoring reasons i want to get a ssh result from "vmstat 1 10" on an Linux-Server. I need to get the Avarage Values of the 10 Values i have. A Usual "vmstat 1 10" result looks like this:

procs -----------memory---------- ---swap-- -----io---- -system-- -----cpu------
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0  42352 599980 315860 2488096    0    0  2606   794    5    2  3  0 94  2  0
 0  0  42352 600044 315860 2488096    0    0    64    84 1107 2107  0  1 99  1  0
 0  0  42352 596820 315860 2488096    0    0   280     4 1218 2179  7  1 91  2  0
 0  0  42352 589240 315860 2488096    0    0    32     7 1322 2366  1  1 95  3  0
 0  0  42352 588620 315860 2488096    0    0   144    37 1161 2181  1  0 96  3  0
 0  0  42352 588620 315860 2488096    0    0     0    24 1074 2075  0  0 100  0  0
 0  0  42352 588620 315860 2488096    0    0     0     0 1081 2081  0  1 100  0  0
 0  0  42352 588628 315860 2488096    0    0   128    32 1133 2091  1  0 96  3  0
 0  0  42352 588652 315860 2488100    0    0     0     0 1077 2058  0  0 100  0  0
 0  0  42352 588528 315860 2488100    0    0     0     5 1137 2147  0  0 99  0  0

So to get the AVG of the Values like swpd, free, buff, etc. my plan was to get the whole values in an Object an then make something like $tab.swpd | Measure-Object -avg but i get an error.

Here is my Script to get the values in the Object. (I know that this is not very nice - sorry for that. I'm still learning...):

$runs = 10
#Get the Values via plink (putty)
$vmstat = .\plink.exe -ssh USER@SERVER -batch -pw "PASSWORD-YES-I-KNOW-THIS-IS-BAD" vmstat 1 $runs
$vmstat
##########################
#Get the Values in somthing like a csv
$vmstat = $vmstat.replace(" ", ";")
#replace alle double ";;" with single ";"
while ($vmstat -match ";;"){
    $vmstat = $vmstat.replace(";;", ";")
    }

#Delete ";" at the beginning (and at the end. Just to be sure. normally there arent ";" 's)
$vmstat = $vmstat.Trim(";")
#Save Columnames
$tabhead = $vmstat[1].split(";")
#Delete first and second row
$vmstat = $vmstat[2..($runs+1)]

##########################
#Split Values and Store it in an two-dimensional array
$values = New-Object system.Array[][] $tabhead.Length, $runs

for ($i=0;$i -lt ($vmstat.Length); $i++){
    $tmp = $vmstat[$i].split(";")

    for ($j=0;$j -lt ($tmp.Length); $j++){
        $values[$j][$i] = $tmp[$j]
        }
}

##########################
# Make an Object for Measurement!
$tab = New-Object System.Object

for ($i=0;$i -lt $tabhead.Length; $i++){
    $tab | Add-Member -type NoteProperty -name $tabhead[$i] -Value $values[$i]
}

so after that all my Values are like i want in the Array or in the Object. I am Able to do select Values i want to see:

PS C:\> $tab

r     : {1, 0, 0, 0...}
b     : {0, 0, 0, 0...}
swpd  : {42352, 42352, 42352, 42352...}
free  : {599980, 600044, 596820, 589240...}
buff  : {315860, 315860, 315860, 315860...}
cache : {2488096, 2488096, 2488096, 2488096...}
si    : {0, 0, 0, 0...}
so    : {0, 0, 0, 0...}
bi    : {2606, 64, 280, 32...}
bo    : {794, 84, 4, 7...}
in    : {5, 1107, 1218, 1322...}
cs    : {2, 2107, 2179, 2366...}
us    : {3, 0, 7, 1...}
sy    : {0, 1, 1, 1...}
id    : {94, 99, 91, 95...}
wa    : {2, 1, 2, 3...}
st    : {0, 0, 0, 0...}

PS C:\> $tab.in
5
1107
1218
1322
1161
1074
1081
1133
1077
1137

But when i try somthing like: $tab.swpd | Measure-Object -Average i get the following error:

Measure-Object : Das Eingabeobjekt "System.Object[]" ist nicht numerisch.
In Zeile:1 Zeichen:13
+ $tab.swpd | Measure-Object -Average
+             ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidType: (System.Object[]:Object[]) [Measure-Object], PSInvalidOperationException
    + FullyQualifiedErrorId : NonNumericInputObject,Microsoft.PowerShell.Commands.MeasureObjectCommand

i think i even would not need the Object, i think it must also be posible to do something like $values[0] | Measure-Object -Average but there is the same error. I know the Problem is that the values arent int values. But i dont know how to convert them so i can make my measurements.


Solution

  • I dont have access to the same resources so I was not able to perfectly recreate the problem. You are right. Measure-Object is trying to tell you that it cannot work with non-numerical values. I think newer versions of powershell handle this better but a cast might do you just fine.

    [int[]]($tab.swpd) | Measure-Object -Average
    

    That should cast the System.Object[] array to System.Int32[]

    For efficiency

    You are splitting the empty space with semicolons and cosolidating those until you have one. Regex might save that whole loop. This will take groups of whitespace and convert them to a semicolon. That might save your issue towards the end. This might address the issue with you Measure-Object since that should remove all whitespace assuming you are not adding any somewhere else along the way. You would still have to address the leading and trailing semi colons created by this like you already do.

    $vmstat = $vmstat.replace("\s+", ";")
    

    Edit from comments

    So I see the cast failed. You have whitespace in your array values i didnt notice at first. Perhaps that is why you are having and issue. You have an array of strings it seems. I will look at your code again and find out where these are coming from. There are other ways to address this but a simple one might be to update this line at the bottom of your code

    $tab | Add-Member -type NoteProperty -name $tabhead[$i] -Value $values[$i].Trim()