We help IT Professionals succeed at work.

Adding member to an array

TeekayShipping
on
Hello,

Hoping someone can help as i cant find an answer to this. In PowerShell i'm trying to add a new proprty to an array i have imported:

To confirm it looks like this when its imported:

PS C:\Windows\system32> $ImportedForAppend

ConnectionName : AlexanderSpirit 10.13.126.0 (vessel) (Not being upgraded)
ID             : 9c503373-a37f-4f08-9cce-748721b0238e
Status         : DOWN   :-(  25-02:1224
IP             : 10.13.126.250
PingNumber     : 0
TimeStamp      : 25-02-2020:1224

ConnectionName : BahrainSpirit 10.12.24.0 (vessel)
ID             : 8d2ce4a0-bacc-477d-89ca-a02f8d1014fd
Status         : FAST 174ms 25-02:1224
IP             : 10.12.24.250
PingNumber     : 174
TimeStamp      : 25-02-2020:1224

ConnectionName : BarcelonaSpirit 10.12.18.0 (vessel)
ID             : c7a783b5-e650-4023-a58b-2739038b1b8b
Status         : FAST 737ms 25-02:1224
IP             : 10.12.18.250
PingNumber     : 737
TimeStamp      : 25-02-2020:1224


PS C:\Windows\system32> $ImportedForAppend.GetType();

IsPublic IsSerial Name                                     BaseType                                                                                                                                                                                              
-------- -------- ----                                     --------                                                                                                                                                                                              
True     True     Object[]                                 System.Array        
             


Now i'm trying to add a new property to the array with an updated time stamp and a new ping number, so it looks like this:

ConnectionName : AlexanderSpirit 10.13.126.0 (vessel) (Not being upgraded)
ID             : 9c503373-a37f-4f08-9cce-748721b0238e
Status         : DOWN   :-(  25-02:1224
IP             : 10.13.126.250
PingNumber     : 0
TimeStamp      : 25-02-2020:1224
25-02-2020:1250:    677

ConnectionName : BahrainSpirit 10.12.24.0 (vessel)
ID             : 8d2ce4a0-bacc-477d-89ca-a02f8d1014fd
Status         : FAST 174ms 25-02:1224
IP             : 10.12.24.250
PingNumber     : 174
TimeStamp      : 25-02-2020:1224
25-02-2020:1250:   1344

ConnectionName : BarcelonaSpirit 10.12.18.0 (vessel)
ID             : c7a783b5-e650-4023-a58b-2739038b1b8b
Status         : FAST 737ms 25-02:1224
IP             : 10.12.18.250
PingNumber     : 737
TimeStamp      : 25-02-2020:1224
25-02-2020:1250:     566


Question is how to target a specific "ConnectionName" and add a new property with the name/value so the layout stays the same?

I know i can use the below to add a new member but its adding a property to each group and i want to only target certain ones:

$ImportedForAppend | Add-Member -MemberType NoteProperty -Name $Vessel.TimeStamp -Value $CurrentStatusList.PingNumber


ConnectionName  : AlexanderSpirit 10.13.126.0 (vessel) (Not being upgraded)
ID              : 9c503373-a37f-4f08-9cce-748721b0238e
Status          : DOWN   :-(  25-02:1253
IP              : 10.13.126.250
PingNumber      : 0
TimeStamp       : 25-02-2020:1253
Test            : 455

ConnectionName  : BahrainSpirit 10.12.24.0 (vessel)
ID              : 8d2ce4a0-bacc-477d-89ca-a02f8d1014fd
Status          : FAST 221ms 25-02:1253
IP              : 10.12.24.250
PingNumber      : 221
TimeStamp       : 25-02-2020:1253
Test            : 455

ConnectionName  : BarcelonaSpirit 10.12.18.0 (vessel)
ID              : c7a783b5-e650-4023-a58b-2739038b1b8b
Status          : FAST 674ms 25-02:1253
IP              : 10.12.18.250
PingNumber      : 674
TimeStamp       : 25-02-2020:1253
Test            : 455

                                                                                                                                                                   
How to add only one extra property as below to say the "ConnectionName" "BarcelonaSpirit 10.12.18.0 (vessel)"

ConnectionName  : AlexanderSpirit 10.13.126.0 (vessel) (Not being upgraded)
ID              : 9c503373-a37f-4f08-9cce-748721b0238e
Status          : DOWN   :-(  25-02:1253
IP              : 10.13.126.250
PingNumber      : 0
TimeStamp       : 25-02-2020:1253

ConnectionName  : BahrainSpirit 10.12.24.0 (vessel)
ID              : 8d2ce4a0-bacc-477d-89ca-a02f8d1014fd
Status          : FAST 221ms 25-02:1253
IP              : 10.12.24.250
PingNumber      : 221
TimeStamp       : 25-02-2020:1253
Test            : 455

ConnectionName  : BarcelonaSpirit 10.12.18.0 (vessel)
ID              : c7a783b5-e650-4023-a58b-2739038b1b8b
Status          : FAST 674ms 25-02:1253
IP              : 10.12.18.250
PingNumber      : 674
TimeStamp       : 25-02-2020:1253
Comment
Watch Question

CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018

Commented:
That's not a way to treat object properties, and you will lose the layout, because you'll have all kinds of different objects.
If you're processing an array with objects, you should make sure every object has the same properties.
So depending on how you want to process this further, I'd suggest to ...

a. either add one string property to each object with the concatenated values, like
Prop = "$Vessel.TimeStamp = $CurrentStatusList.PingNumber"

or b. add two properties to each object, like
Prop1 = $Vessel.TimeStamp
Prop2 = $CurrentStatusList.PingNumber

In both cases, the objects in this array you don't want to process can be left empty.
Which one do you need?

Author

Commented:
Hello,

Thanks for the help!

I have added a new property with the time stamp so now every time i run the script its adding the date which is what i want.

How do i then update the value of each property individually?

ConnectionName  : AlexanderSpirit 10.13.126.0 (vessel) (Not being upgraded)
ID              : 9c503373-a37f-4f08-9cce-748721b0238e
Status          : DOWN   :-(  25-02:1418
IP              : 10.13.126.250
PingNumber      : 0
TimeStamp       : 25-02-2020:1418
25-02-2020:1418 :
25-02-2020:1419 :

ConnectionName  : BahrainSpirit 10.12.24.0 (vessel)
ID              : 8d2ce4a0-bacc-477d-89ca-a02f8d1014fd
Status          : FAST 225ms 25-02:1418
IP              : 10.12.24.250
PingNumber      : 225
TimeStamp       : 25-02-2020:1418
25-02-2020:1418 :
25-02-2020:1419 :

ConnectionName  : BarcelonaSpirit 10.12.18.0 (vessel)
ID              : c7a783b5-e650-4023-a58b-2739038b1b8b
Status          : FAST 679ms 25-02:1418
IP              : 10.12.18.250
PingNumber      : 679
TimeStamp       : 25-02-2020:1418
25-02-2020:1418 :
25-02-2020:1419 :

Maybe it will help to explain a bit more. I would like to export the results to a text file each time (the same results that get imported to start with) so that i have a history of results. I would like the script to append the ping results to the CSV each time and i thought the best way to do that would be to import it into an array and then work with the array and then export again.

When i export to a CSV it looks like the attached when i open it, i just need to update the date/time stamp column with the ping number which i thought would be easiest to do before the export.

Thanks
Capture.JPG
David Johnson, CDSimple Geek from the '70s
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:

where is ping number coming from? For timestamp what do you want? Time Tested? 

If Png is UP update timestamp otherwise don't update timestamp? 


do you have any code that we could work from? 



Author

Commented:
Hello,

Thanks for the reply, here is the script that is working just now. It basically tests the connection of a list of vessels. The list is pulled from another script. I have attached the current IP list its using.

Basically i'm trying to make it so that when it tests a connection that it saves that data to a growing CSV file so we can track the connection quality.

Import-Module "${env:ProgramFiles(x86)}\Devolutions\Remote Desktop Manager\RemoteDesktopManager.PowerShellModule.psd1"

$IPListImport = @()
$CompleteStatusList = @()
#PUll the session ID and IP from all the connections in the database so that the workflow can use this

$ExportCSVPath = "C:\RDM_Scripts\IPList.csv"

$IPListImport = Import-CSV $ExportCSVPath

Remove-Item "C:\RDM_Scripts\ConnectionStatus\*.txt" | Where { ! $_.PSIsContainer }

#Workflow to test the conenction on 20 vessels at a time

Workflow CheckConnections
{
Param ($IPListImport)

ForEach -Parallel -Throttle 20 ($Connection in $IPListImport){

$VesselIPworkflow = $null
$CurrentSessionIDworkflow = $null
$ConnectionNameworkflow = $null

$VesselIPworkflow = $Connection.VesselIP
$CurrentSessionIDworkflow = $Connection.CurrentSessionID
$ConnectionNameworkflow = $Connection.ConnectionName


#Test the connection and get the average

$ConnectionStatus = Test-Connection -ComputerName $VesselIPworkflow -Count 6 -ErrorAction SilentlyContinue

$ConnectionStatusRaw = $ConnectionStatus.ResponseTime

$ConnectionStatusAvg = $ConnectionStatusRaw | Measure-Object -Average

$ConnectionStatusNumber = [math]::Round($ConnectionStatusAvg.Average)


#Test for ping degradation

$ConnectionSuccess = $ConnectionStatusRaw | Measure-Object -Line

$ConnectionSuccessLines = $ConnectionSuccess.Lines

$ConnectionDrops = 6 - $ConnectionSuccessLines

$ConnectionStatusDegraded = $null

#Set the status

if ($ConnectionStatus) {

If ($ConnectionStatusNumber -lt 1000) {$ConnectionStatusSimple = "FAST "}
Else {Write-Output "Connection Status Set To" + $ConnectionStatusSimple}

If (($ConnectionStatusNumber -gt 1000) -AND ($ConnectionStatusNumber -lt 2000)) {$ConnectionStatusSimple = "MED "}
Else {Write-Output "Connection Status Set To" + $ConnectionStatusSimple}

If ($ConnectionStatusNumber -gt 2000) {$ConnectionStatusSimple = "SLOW "}
Else {Write-Output "Connection Status Set To" + $ConnectionStatusSimple}

If ($ConnectionDrops -gt 1) {$ConnectionStatusDegraded = " D"}
Else {$ConnectionStatusDegraded =$null}                                                                                                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                           
}

#Write the connection Status to text files for each vessel test

  if ($ConnectionStatus) {
     $UPorDOWN = "" + $ConnectionStatusSimple + $ConnectionStatusNumber + "ms " + (GET-DATE -format dd-MM:HHmm) + $ConnectionStatusDegraded
  }
  else{
   $UPorDOWN = "DOWN   :-(  " + (GET-DATE -format dd-MM:HHmm)
  }
 
  $CurrentTime = GET-DATE -format dd-MM-yyyy:HHmm

  New-Item -ItemType Directory -Force -Path "C:\RDM_Scripts\ConnectionStatus"
  Set-Content -Path "C:\RDM_Scripts\ConnectionStatus\$ConnectionNameworkflow.txt" -Value "$CurrentSessionIDworkflow, $UPorDOWN, $VesselIPworkflow"
  Write-Output $ConnectionNameworkflow $VesselIPworkflow $UPorDOWN "ConnectionChecked" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

}

#Run the workflow and pass it the conenction list

CheckConnections $IPListImport

####WRITE TEXT FILES TO DATABASE

Get-ChildItem "C:\RDM_Scripts\ConnectionStatus" -Filter *.txt |
Foreach-Object {
   $content = import-csv "C:\RDM_Scripts\ConnectionStatus\$_" –header ID, Status, IP –delimiter ','
   $CompleteStatusList += $content
 
}



Foreach ($LastStatus in $CompleteStatusList){

$DatabaseSessionID = $LastStatus.ID
$DatabaseStatus = $LastStatus.Status
$DatabaseIP = $LastStatus.IP

Set-RDMSessionProperty -Id $DatabaseSessionID -Path MetaInformation -Property CustomField1Value -Value $DatabaseStatus

}


I believe the best time to save the data to the CSV is at the point where i have captured the current tests within the array $CompleteStatusList. I have been trying for some time to work out how best to do that.

Any help appreciated  on what the best approach is.

Thanks
Capture2.JPG
IPList.csv
CERTIFIED EXPERT
Most Valuable Expert 2019
Most Valuable Expert 2018
Commented:
If you want to watch this over time, you should add rows instead of columns. - no database engine adds incoming data to a table by adding columns with dynamically generated names.
Use the TimeStamp property you already have, just change the format to yyyy-MM-dd HH:mm:ss for better sorting.
For evaluation in Excel, you can add a filter so that you can select the ConnectionName you want to check.
For a quick look at a certain connection in PowerShell, you just filter and send the output to Out-GridView or whatever else you want to process this further.
Import-Csv .\Whatever.csv | Where-Object {$_.ConnectionName -like "BarcelonaSpirit*" | Out-GridView

Open in new window

Author

Commented:
Thanks, i added the below to the script:

$CompleteStatusList | Select ConnectionName, Status, IP, PingNumber | Export-Csv C:\RDM_Scripts\ConnectionStatus\ConnectionHistory.csv -append -NoTypeInformation

Also had to tell it to collect the connection name and full date/time stamp in the text files as well and add that to the array:  $CompleteStatusList

I will test it out and see how it looks as its added to the CSV.

Here is the completed script now:

Import-Module "${env:ProgramFiles(x86)}\Devolutions\Remote Desktop Manager\RemoteDesktopManager.PowerShellModule.psd1"

$IPListImport = @()
$CompleteStatusList = @()
#PUll the session ID and IP from all the connections in the database so that the workflow can use this

$ExportCSVPath = "C:\RDM_Scripts\IPList.csv"

$IPListImport = Import-CSV $ExportCSVPath

Remove-Item "C:\RDM_Scripts\ConnectionStatus\*.txt" | Where { ! $_.PSIsContainer }

#Workflow to test the conenction on 20 vessels at a time

Workflow CheckConnections
{
Param ($IPListImport)

ForEach -Parallel -Throttle 20 ($Connection in $IPListImport){

$VesselIPworkflow = $null
$CurrentSessionIDworkflow = $null
$ConnectionNameworkflow = $null

$VesselIPworkflow = $Connection.VesselIP
$CurrentSessionIDworkflow = $Connection.CurrentSessionID
$ConnectionNameworkflow = $Connection.ConnectionName


#Test the connection and get the average

$ConnectionStatus = Test-Connection -ComputerName $VesselIPworkflow -Count 6 -ErrorAction SilentlyContinue

$ConnectionStatusRaw = $ConnectionStatus.ResponseTime

$ConnectionStatusAvg = $ConnectionStatusRaw | Measure-Object -Average

$ConnectionStatusNumber = [math]::Round($ConnectionStatusAvg.Average)


#Test for ping degradation

$ConnectionSuccess = $ConnectionStatusRaw | Measure-Object -Line

$ConnectionSuccessLines = $ConnectionSuccess.Lines

$ConnectionDrops = 6 - $ConnectionSuccessLines

$ConnectionStatusDegraded = $null

#Set the status

if ($ConnectionStatus) {

If ($ConnectionStatusNumber -lt 1000) {$ConnectionStatusSimple = "FAST "}
Else {Write-Output "Connection Status Set To" + $ConnectionStatusSimple}

If (($ConnectionStatusNumber -gt 1000) -AND ($ConnectionStatusNumber -lt 2000)) {$ConnectionStatusSimple = "MED "}
Else {Write-Output "Connection Status Set To" + $ConnectionStatusSimple}

If ($ConnectionStatusNumber -gt 2000) {$ConnectionStatusSimple = "SLOW "}
Else {Write-Output "Connection Status Set To" + $ConnectionStatusSimple}

If ($ConnectionDrops -gt 1) {$ConnectionStatusDegraded = " D"}
Else {$ConnectionStatusDegraded =$null}                                                                                                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                           
}

#Write the connection Status to text files

  if ($ConnectionStatus) {
     $UPorDOWN = "" + $ConnectionStatusSimple + $ConnectionStatusNumber + "ms " + (GET-DATE -format dd-MM:HHmm) + $ConnectionStatusDegraded
  }
  else{
   $UPorDOWN = "DOWN   :-(  " + (GET-DATE -format dd-MM:HHmm)
  }
 
  $CurrentTime = GET-DATE -format dd-MM-yyyy:HHmm

  New-Item -ItemType Directory -Force -Path "C:\RDM_Scripts\ConnectionStatus"
  Set-Content -Path "C:\RDM_Scripts\ConnectionStatus\$ConnectionNameworkflow.txt" -Value "$ConnectionNameworkflow, $CurrentSessionIDworkflow, $UPorDOWN, $VesselIPworkflow, $CurrentTime, $ConnectionStatusNumber"
  Write-Output $ConnectionNameworkflow $VesselIPworkflow $UPorDOWN "ConnectionChecked" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

}

#Run the workflow and pass it the conenction list

CheckConnections $IPListImport

####WRITE TEXT FILES TO DATABASE

Get-ChildItem "C:\RDM_Scripts\ConnectionStatus" -Filter *.txt |
Foreach-Object {
   $content = import-csv "C:\RDM_Scripts\ConnectionStatus\$_" –header ConnectionName, ID, Status, IP, DateTime, PingNumber –delimiter ','
   $CompleteStatusList += $content
 
}


Foreach ($LastStatus in $CompleteStatusList){

$DatabaseSessionID = $LastStatus.ID
$DatabaseStatus = $LastStatus.Status
$DatabaseIP = $LastStatus.IP

Set-RDMSessionProperty -Id $DatabaseSessionID -Path MetaInformation -Property CustomField1Value -Value $DatabaseStatus

}

$CompleteStatusList | Select ConnectionName, Status, IP, DateTime, PingNumber | Export-Csv C:\RDM_Scripts\ConnectionStatus\ConnectionHistory.csv -append -NoTypeInformation