Create an array off objects as a class member in PowerShell - powershell

I keep getting errors when running the code below. I don't understand what I'm doing wrong
ERROR 1: You cannot call a method on a null-valued expression. At
line:25 char:9
ERROR 2: Cannot index into a null array. At line:43 char:1
CODE:
Class Step {
[int]$StepNumber = 0
[string]$Name = ''
[string]$ScriptFile = ''
[int]$status = 0 # 0 = 'InComplete', 1 = 'Complete', 2 = 'Failed', -1 = 'Skipped'
[string]$DependencyStepNumber = -1
Step([string]$Name, [int]$StepNumber, [string]$ScriptFile) {
$this.Name = $Name
$this.StepNumber = $StepNumber
$this.ScriptFile = $ScriptFile
}
}
Class Guide {
[int]$StepNumberCounter = 0
[string]$Name = ''
[Step[]]$Steps
[int]AddStep([string]$Name, [string]$ScriptFile) {
$newStepNumber = $this.GetNewStepNumber()
$newStep = [Step]::new($Name, $newStepNumber, $ScriptFile)
line-25>>> $this.Steps.Add($newStep)
return $newStepNumber
}
[int]GetStepName([int]$StepNumber) {
return $this.Steps[$StepNumber-1]
}
[int]GetNewStepNumber() {
return $this.StepNumberCounter += 1
}
}
$Guide = [Guide]::new()
$Guide.AddStep('Step One','ScriptOne.ps1')
$Guide.AddStep('Step Two','ScriptTwo.ps1')
line-43>>> Write-Host $Guide.Steps[0]
Write-Host $Guide.Steps[1]

Array list has better performance, see below revised code
Class Step {
[int]$StepNumber = 0
[string]$Name = ''
[string]$ScriptFile = ''
[int]$status = 0 # 0 = 'InComplete', 1 = 'Complete', 2 = 'Failed', -1 = 'Skipped'
[string]$DependencyStepNumber = -1
Step([string]$Name, [int]$StepNumber, [string]$ScriptFile) {
$this.Name = $Name
$this.StepNumber = $StepNumber
$this.ScriptFile = $ScriptFile
}
}
Class Guide {
[int]$StepNumberCounter = 0
[string]$Name = ''
[System.Collections.ArrayList]$Steps = #()
[int]AddStep([string]$Name, [string]$ScriptFile) {
$newStepNumber = $this.GetNewStepNumber()
$newStep = [Step]::new($Name, $newStepNumber, $ScriptFile)
$this.Steps.Add($newStep)
return $newStepNumber
}
[int]GetStepName([int]$StepNumber) {
return $this.Steps[$StepNumber-1]
}
[int]GetNewStepNumber() {
return $this.StepNumberCounter += 1
}
}
$Guide = [Guide]::new()
$Guide.AddStep('Step One','ScriptOne.ps1')
$Guide.AddStep('Step Two','ScriptTwo.ps1')
Write-Output $Guide.Steps[0]
Write-Output $Guide.Steps[1]

To add an element to an array, we use the += operator.
$this.Steps += $newStep
Add is reserved for ArrayList:
$al = New-Object System.Collections.ArrayList
$al.Add('Example')

Related

Update/Refesh Listbox after Editing Source Data

I would like to create in PowerShell a Windows form that uses a ListBox that selects data for editing. As an entry in the ListBox is selected, textboxes below are bound to properties in the selected entry, allowing the editing of that entry. Sounds simple, and almost is, if only the ListBox would always show the current state of the data.
A stripped down version of the code produces a form that looks like this image below. The textboxes at the bottom of the form appear to work perfectly, that is, the test I've done show the bound data is changing as you type in them. But the content of the ListBox is never refreshed or updated, and so far all attempts at fixing this seem to either not work, cause other problems.
Initially I was creating a class in PowerShell for holding the data, but switched to a C# class:
Add-Type -ReferencedAssemblies "System.Windows.Forms" -Language CSharp -TypeDefinition #'
using System;
public class VectorData {
double _degrees = 0.0d;
double _distance = 0.0d;
public double Degrees {
get {
return this._degrees;
}
set {
this._degrees = value;
}
}
public double Distance {
get {
return this._distance;
}
set {
this._distance = value;
}
}
public string Display {
get {
return "" + this._degrees + "\u00B0 \u2192 " + this._distance + "\u0027";
}
}
public VectorData(double degrees, double distance){
this._degrees = degrees;
this._distance = distance;
}
}
'#
I've tried all three of these examples for creating the list that can be bound to the ListBox, but none of them update the ListBox's content as the data changes.
#$Vectors = [System.Collections.Generic.List[VectorData]]::new()
$Vectors = [System.ComponentModel.BindingList[VectorData]]::new()
#$Vectors = [System.Collections.ObjectModel.ObservableCollection[VectorData]]::new()
This is the core code, $lbxVectors is the ListBox. $tbxDegrees and $tbxDistance are textboxes.
function SetVectorsDataSource {
$lbxVectors.DataSource = $null
$lbxVectors.DataSource = $Vectors
$lbxVectors.DisplayMember = 'Display'
}
function BindTextBoxes {
$VD = $Vectors[$lbxVectors.SelectedIndex]
$null = $txbDegrees.DataBindings.Clear()
$null = $txbDegrees.DataBindings.Add('Text', $VD, "Degrees")
$null = $txbDistance.DataBindings.Clear()
$null = $txbDistance.DataBindings.Add('Text', $VD, "Distance")
}
$null = $Vectors.Add([VectorData]::new(45, 20))
$null = $Vectors.Add([VectorData]::new(193, 32))
$null = $Vectors.Add([VectorData]::new(155, 18))
SetVectorsDataSource
BindTextBoxes
$lbxVectors.Add_SelectedIndexChanged({
BindTextBoxes
})
Calling the SetVectorsDataSource function from the textboxes' TextChanged event seems to overwrite what you type with the original data, so that doesn't work:
$txbDegrees.Add_TextChanged({
# SetVectorsDataSource
})
$txbDistance.Add_TextChanged({
# SetVectorsDataSource
})
So, does anyone have any idea on how to keep the ListBox up-to-date with the current state of the data?
FYI: Here is the full code if someone wants to try it:
using namespace System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms
Add-Type -ReferencedAssemblies "System.Windows.Forms" -Language CSharp -TypeDefinition #'
using System;
public class VectorData {
double _degrees = 0.0d;
double _distance = 0.0d;
public double Degrees {
get {
return this._degrees;
}
set {
this._degrees = value;
}
}
public double Distance {
get {
return this._distance;
}
set {
this._distance = value;
}
}
public string Display {
get {
return "" + this._degrees + "\u00B0 \u2192 " + this._distance + "\u0027";
}
}
public VectorData(double degrees, double distance){
this._degrees = degrees;
this._distance = distance;
}
}
'#
#$Vectors = [System.Collections.Generic.List[VectorData]]::new()
$Vectors = [System.ComponentModel.BindingList[VectorData]]::new()
#$Vectors = [System.Collections.ObjectModel.ObservableCollection[VectorData]]::new()
#region Build form and controls
function NextCtrlY { param ( [Control]$Control ) return $Control.Location.Y + $Control.Size.Height }
$ClientWidth = 200
$lbxVectors = [ListBox]#{
Location = "12, 12"
Name = "lbxVectors"
Size = "$($ClientWidth - 24), 120"
TabIndex = 0
}
$TextBoxWidth = ($ClientWidth - (12 + 6 + 12))/2
$LeftTxBxX = 12 + $TextBoxWidth + 6
$lblDegrees = [Label]#{
AutoSize = $true
Location = "12, $(NextCtrlY $lbxVectors)"
Name = "lblDegrees"
TabIndex = 1
Text = "Degrees:"
}
$lblDistance = [Label]#{
AutoSize = $true
Location = "$LeftTxBxX, $(NextCtrlY $lbxVectors)"
Name = "lblDistance"
TabIndex = 2
Text = "Distance:"
}
$txbDegrees = [TextBox]#{
Location = "12, $(NextCtrlY $lblDegrees)"
Name = "txbDegrees"
Size = "$TextBoxWidth, 20"
TabIndex = 3
Text = ""
}
$txbDistance = [TextBox]#{
Location = "$LeftTxBxX, $($txbDegrees.Location.Y)"
Name = "txbDistance"
Size = "$TextBoxWidth, 12"
TabIndex = 4
Text = ""
}
$ListBoxTestForm = [Form]#{
ClientSize = "$ClientWidth, $($(NextCtrlY $txbDegrees) + 12)"
FormBorderStyle = 'FixedDialog'
MaximizeBox = $false
MinimizeBox = $true
Name = 'ListBoxTestForm'
StartPosition = 'CenterScreen'
Text = "ListBox Test"
}
$ListBoxTestForm.Controls.Add($lbxVectors)
$ListBoxTestForm.Controls.Add($lblDegrees)
$ListBoxTestForm.Controls.Add($lblDistance)
$ListBoxTestForm.Controls.Add($txbDegrees)
$ListBoxTestForm.Controls.Add($txbDistance)
#endregion
function SetVectorsDataSource {
$lbxVectors.DataSource = $null
$lbxVectors.DataSource = $Vectors
$lbxVectors.DisplayMember = 'Display'
}
function BindTextBoxes {
$VD = $Vectors[$lbxVectors.SelectedIndex]
$null = $txbDegrees.DataBindings.Clear()
$null = $txbDegrees.DataBindings.Add('Text', $VD, "Degrees")
$null = $txbDistance.DataBindings.Clear()
$null = $txbDistance.DataBindings.Add('Text', $VD, "Distance")
}
$null = $Vectors.Add([VectorData]::new(45, 20))
$null = $Vectors.Add([VectorData]::new(193, 32))
$null = $Vectors.Add([VectorData]::new(155, 18))
SetVectorsDataSource
BindTextBoxes
$lbxVectors.Add_SelectedIndexChanged({
BindTextBoxes
})
$txbDegrees.Add_TextChanged({
# SetVectorsDataSource
})
$txbDistance.Add_TextChanged({
# SetVectorsDataSource
})
$null = $ListBoxTestForm.ShowDialog()
As I was about to post this question, I looked at the list of "Similar questions" and found this C# question/answer.
Replaced the core code with the following and it works!:
$VectorBindingSource = [BindingSource]::new()
$VectorBindingSource.DataSource = $Vectors
$lbxVectors.DataSource = $VectorBindingSource
$lbxVectors.DisplayMember = "Display"
$lbxVectors.ValueMember = "Display"
$null = $txbDegrees.DataBindings.Add("Text", $VectorBindingSource, "Degrees", $true, [DataSourceUpdateMode]::OnPropertyChanged)
$null = $txbDistance.DataBindings.Add("Text", $VectorBindingSource, "Distance", $true, [DataSourceUpdateMode]::OnPropertyChanged)
$null = $Vectors.Add([VectorData]::new(45, 20))
$null = $Vectors.Add([VectorData]::new(193, 32))
$null = $Vectors.Add([VectorData]::new(155, 18))
NOTE: Requires BindingList, doesn't work with generic list or ObservableCollection:
$Vectors = [System.ComponentModel.BindingList[VectorData]]::new()

How to debug a script that will kill by system when await multi Promise?

Answer "the script used too much memory".
I start a few start to read text file line by line, and convert the text to blob, then send it to socket:
use experimental :pack;
sub heart-msg(Str $msg, Str $device-id --> Blob) {
my $heart-msg = $msg.substr(0, $msg.chars - 8);
my $header-buf = pack("H*", $heart-msg);
my $device-id-buf = pack("L*", $device-id);
$header-buf ~ $device-id-buf
}
sub deal-message(Str $msg, Str $device-id --> Blob) {
my $now = DateTime.now();
my $year = $now.year;
my $month = $now.month;
my $day = $now.day;
my $hour = $now.hour;
my $minute = $now.minute;
my $second = $now.second.Int;
my $check-number = 0;
my $head-msg = $msg.substr(0,4);
my $device-id-length = $msg.substr(4,2);
my $pf-code = $msg.substr(14, 2);
my $msg-length = $msg.substr(16, 4);
my $rel-time = $msg.substr(20, 4);
my $end-msg = $msg.substr(38, $msg.chars - 38 - 2);
my $head-msg-buf = pack("H*", $head-msg);
my $device-id-len-buf = pack("H*", $device-id-length);
my $device-id-buf = pack("L*", $device-id);
my $pf-code-buf = pack("H*", $pf-code);
my $msg-length-buf = pack("H*", $msg-length);
my $rel-time-buf = pack("H*", $rel-time);
my $year-buf = pack("S*", $year);
my $month-buf = pack("C*", $month);
my $day-buf = pack("C*", $day);
my $hour-buf = pack("C*", $hour);
my $minute-buf = pack("C*", $minute);
my $second-buf = pack("C*", $second);
my $end-msg-buf = pack("H*", $end-msg);
my #bufs = [$device-id-len-buf, $device-id-buf, $pf-code-buf, $msg-length-buf,
$rel-time-buf, $year-buf, $month-buf, $day-buf, $hour-buf, $minute-buf, $second-buf,
$end-msg-buf];
for #bufs -> $byte {
my $byte_sum = [+] $byte.contents;
$check-number += $byte_sum;
}
$check-number = $check-number % 256;
my $checked-msg-buf = pack("C*", $check-number);
[~] $head-msg-buf, |#bufs, $checked-msg-buf
}
sub deal-data(Str $msg, Str $device-id --> Blob) {
my $header = $msg.substr(0, 4);
given $header {
when '6868' {
return deal-message($msg, $device-id);
}
when '7468' {
return heart-msg($msg, $device-id);
}
default { return Buf.new }
}
}
sub MAIN(
:$host = '10.0.0.77',
Int() :$port = 4444,
Rat() :$interval = 0.001,
:$file = 'data.txt',
Int() :$device-num = 169) {
my $conn = IO::Socket::INET.new(:$host, :$port);
my #devices = "modelId.txt".IO.lines;
my #promises = gather for #devices[159..$device-num] -> $device-id {
take start {
my $f = lazy $file.IO.lines;
my $iterator = $f.iterator;
react {
whenever Supply.interval($interval) {
try {
my $line := $iterator.pull-one;
if $line =:= IterationEnd {
done;
} else {
my $blob = deal-data($line.chomp.split(/\s+/).tail, $device-id.Str);
#say $blob;
$conn.write($blob);
}
}
QUIT {
$conn.close;
say 'connecting closed';
default {
say .^name, '→ ', .Str;
say "handled in line $?LINE";
}
}
LAST {
say "Connection closed";
done;
}
}
}
}
}
await #promises;
}
When running on CentOS 7.4(12 core, 32G RAM), after a few seconds, my script was killed by system. When running on Win11(12 core, 16G RAM), it's OK.
So how to debug this script?

Hash password with salt in powershell (CBC, PKCS7, AES)

I'm trying to replicate the following JS-function into Powershell. It must match the exact same properties as I'm not able to change the other end where those values will be used.
// Function to encrypt values with Salt
function encryptMetadata(encryptStr, saltValue) {
var encrypted = CryptoJS.AES.encrypt(encryptStr.toString(), saltValue,
{
keySize: 256 / 8,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
};
I tried to work with AesManaged and the following code, however, I'm failing to build the key.
function Create-AesManagedObject($key, $IV) {
$aesManaged = New-Object "System.Security.Cryptography.AesManaged"
$aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aesManaged.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$aesManaged.BlockSize = 128
$aesManaged.KeySize = 256
if ($IV) {
if ($IV.getType().Name -eq "String") {
$aesManaged.IV = [System.Convert]::FromBase64String($IV)
}
else {
$aesManaged.IV = $IV
}
}
if ($key) {
if ($key.getType().Name -eq "String") {
$aesManaged.Key = [System.Convert]::FromBase64String($key)
}
else {
$aesManaged.Key = $key
}
}
$aesManaged
}
function Encrypt-String($key, $unencryptedString) {
$bytes = [System.Text.Encoding]::UTF8.GetBytes($unencryptedString)
$aesManaged = Create-AesManagedObject $key
$encryptor = $aesManaged.CreateEncryptor()
$encryptedData = $encryptor.TransformFinalBlock($bytes, 0, $bytes.Length);
[byte[]] $fullData = $aesManaged.IV + $encryptedData
$aesManaged.Dispose()
[System.Convert]::ToBase64String($fullData)
}
$hashedUsername = Encrypt-String $salt $inputUsername
Could anyone help me out on how to replicate this CryptoJS functionality in PS?
Thanks in advance!

Why I'm getting the error: "Parameter 1 to Credis_Client::scan() expected to be a reference"?

I'm trying to call this class function:
public function scan(&$Iterator, $pattern = null, $count = null)
{
return $this->__call('scan', array(&$Iterator, $pattern, $count));
}
From my class:
$itScan = NULL;
while($arr_keys = $this->redisClient->scan($itScan, '', 10000)) {
foreach($arr_keys as $str_key) {
echo "Here is a key: $str_key\n";
}
}
I understand this is something related to the & pointer but I can't figure who to call it from inside my class.
Thank you!
This is the proper way to iterate over your results :
$i = null;
$allResults = [];
do {
$someResults = $redis->scan($i, "*", 10000);
if (!empty($someResults)) {
$allKeys = array_merge($allKeys, $someResults);
}
}
while ($i);

perl using a hash to filter another hashes contents [duplicate]

This question already has an answer here:
Why does my file content/user input not match? (missing chomp canonical) [duplicate]
(1 answer)
Closed 8 years ago.
I have a symbol download from a database that produces this populates the symbol hash just fine. WHen I sort the keys I get this
foreach $symbol ( sort keys %symbol_hash ) {
print "$symbol\n ";
}
A AA AAL AAPL ABBV ABT ABT_SPIN ABX ACI ACN ACT ADBE ADI ADM ADSK AEIS AEO AES AET AFAM AGN AGU AIG AKAM AKS ALL ALNY ALR ALU AMAT AMGN AMP AMZN ANF ANN ANR APA APC ARCC
I have a unix config file which contains alot of information for many processes.
This is the config file
# Tick Size
# tr -d \ | sort -u
TickSizePostOpen = 1.00
TickSize = {
penny1 = {
TickSize = 0.00
members = {
IWM
QQQ
SPY
SPY_TEST
}
}
penny = {
TickSize = </0.000/0.00/0.00
members = {
A
AA
AAL
AAPL
ABT
ABT_SPIN
ZNGA
}
}
notpenny = {
TickSize = </9/9.99/9.99
}
}
BIPP.QuoterOx = {
Cup1and2 = {
BIPP.QuoterOx = BIPP-ox-1
members = {
Cup_1
Cup_2
}
}
TRAP.PxByGroup = 1
TRAP.Px = {
group1 = {
TRAP.Px = OPTxxxxxx
members = {
px.TRAP.1
}
}
group2 = {
TRAP.Px = OPTxxxxxx
members = {
px.TRAP.2
}
}
TRAP.QuoterOx = {
Cup0 = {
TRAP.QuoterOx = QESxxxxx
members = {
Cup_0
Cup_99
}
}
Cup1and4and10 = {
TRAP.QuoterOx = ise-ox-1-4-10-dti
members = {
Cup_1
Cup_4
Cup_10
}
}
Cup56 = {
TRAP.AuctionOx = ise-ox-56-ecl
members = {
Cup_56
}
}
}
TRAP.RotateQuote = {
rotatenames = {
TRAP.RotateQuote = 1
members = {
AAPL
ADY
AEIS
AFAM
AGP
ALNY
ZINC
}
}
}
Underlying = {
Cup0 = {
Underlying = MHR
members = {
Cup_0
}
}
g1 = {
Underlying = CEL
members = {
Cup_1
}
}
}
BIPP.Px = {
group1 = {
BIPP.Px = BOXPXMHR1
members = {
px.BIPP.1
}
}
group2 = {
BIPP.Px = BOXPXMHR2
members = {
px.BIPP.2
}
}
}
TWIG.Px = {
AB = {
TWIG.Px = TWIGPXMHR1
members = {
A
B
}
}
CD = {
TWIG.Px = TWIGPXMHR2
members = {
C
D
}
}
NOPQR = {
TWIG.Px = TWIGPXMHR6
members = {
N
O
P
Q
R
}
}
STUV = {
TWIG.Px = TWIGPXMHR7
members = {
S
T
U
V
}
}
WXYZ = {
TWIG.Px = TWIGPXMHR8
members = {
W
X
Y
Z
}
}
}
What I am trying to do is download symbols from a database, populate a symbol hash(which works), then load in the config file file, parse it down to its barest elements and using the symbol hash as a filter, populate the penny hash. So if an element from the stripped down config file is in the symbol hash, put it in the penny hash.
#!/perl/bin/perl
use strict;
use warnings;
use DBI;
use Data::Dumper;
my $dbUser = 'yeah';
my $dbPass = 'boy'; # <--- was missing closing single quote
my $dbSid = 'yeah.boy';
my $dbh = DBI->connect( "dbi:Oracle:$dbSid", "$dbUser", "$dbPass" ) or die("Couldn't connect: $!");
my $penny_file = "/data/wowmom.cfg";
my %penny_hash = ();
my %symbol_hash = ();
my $query = "select alotof stuff from yeah.boy ";
if ( !$dbh ) {
print "Error connecting to Database: $DBI::errstr\n";
}
my $cur_msg = $dbh->prepare($query) or die "\n\nCould not prepare statement: " . dbh->errstr;
$cur_msg->execute();
while ( my #row = $cur_msg->fetchrow_array ) {
$symbol_hash{ $row[0] } = 1;
}
open( my $penny_fh, '<', "$penny_file" ) or die "Can't open $penny_file for reading: $!";
while (<$penny_fh>) {
next unless /\S/;
#print unless /[#{}=]/ ; # try this - the parse works!
if ( !/[#{}=]/ ) {
if ( $symbol_hash{$_} ) {
$penny_hash{$_} = 1; # does not populate
}
}
}
#foreach my $symbol ( sort keys %symbol_hash ) {
# print "$symbol\n ";
#} # works
print Dumper( \%penny_hash ); #does not work
#print Dumper(\%symbol_hash) ; # works
#foreach my $penny ( sort keys %penny_hash ) {
# print "$penny\n ";
#}
the Dumper(\%penny_hash) prints nothing.
Don't forget to chomp your input:
while (<$penny_fh>) {
chomp; # <-- remove line endings before string comparison