Case Else in PowerShell - powershell

I'm converting VBScript to PowerShell and I have an issue with Select Case. I'm trying to find a way to do a Case Else.
switch($IncomingText.SubString(0,1)) {
"1" {
switch($IncomingText.SubString(12,3)) {
"601" {
$TempString = ($IncomingText.SubString(0,75))
if (RemoveSpaces($IncomingText.SubString(75,10)) = True) {
$TempString = $TempString + (StrReverse($IncomingText.SubString(75,10))) + ($IncomingText.SubString(85,10))
} else {
$TempString = $TempString + ($IncomingText.SubString(75,20))
}
return $TempString
Case Else
if (RemoveSpaces($IncomingText.SubString(155,10)) = True) {
$TempString = $TempString + (StrReverse($IncomingText.SubString(155,10))) + ($IncomingText.SubString(165))
} else {
$TempString = $TempString + ($IncomingText.SubString(155))
}
return $TempString
}
}
}
}
In VBScript there's this Case Else. I want to stay in the "601" and proceed with the next section. How do I do it in PowerShell? Since Case Else doesn't seems to be working for me.

Taken from Windows Powershell site
https://technet.microsoft.com/en-us/library/ff730937.aspx
So use default instead of case else.
$a = 5
switch ($a)
{
1 {"The color is red."}
2 {"The color is blue."}
3 {"The color is green."}
4 {"The color is yellow."}
5 {"The color is orange."}
6 {"The color is purple."}
7 {"The color is pink."}
8 {"The color is brown."}
default {"The color could not be determined."}
}

You're looking for default:
Switch ($something) {
1 { .. }
2 { .. }
default { .. }
}

I'd like to point out that the Switch command will evaluate scriptblocks similar to an If statement, so you could just create more complex cases:
switch($IncomingText) {
{$_.SubString(0,1) -eq '1' -and $IncomingText.SubString(12,3) -eq '601'}
{
$TempString = $IncomingText.SubString(0,75)
if (![string]::IsNullOrWhiteSpace($IncomingText.SubString(75,10))) {
$TempString = $TempString + (StrReverse($IncomingText.SubString(75,10))) + ($IncomingText.SubString(85,10))
} else {
$TempString = $TempString + ($IncomingText.SubString(75,20))
}
}
default
{
if (RemoveSpaces($IncomingText.SubString(155,10)) = True) {
$TempString = $TempString + (StrReverse($IncomingText.SubString(155,10))) + ($IncomingText.SubString(165))
} else {
$TempString = $TempString + ($IncomingText.SubString(155))
}
return $TempString
}
}
I would also like to note that it looks like you are removing spaces from a 10 character string, and testing to see if anything is left. If there is you reverse those 10 characters, then add the next 10 characters, if not you simply add all 20 characters as they are. My point is that if the first 10 characters are all spaces then reversing them is harmless, so you may as well just always reverse them. With that in mind your code gets a lot simpler:
Function StrReverse ($MyString){
$arrMyString = $MyString.ToCharArray()
[array]::Reverse($arrMyString)
$arrMyString -join ''
}
switch($IncomingText) {
{$_.SubString(0,1) -eq '1' -and $IncomingText.SubString(12,3) -eq '601'}
{
$TempString = $IncomingText.SubString(0,75) + (StrReverse $IncomingText.SubString(75,10)) + $IncomingText.SubString(85,10)
}
default
{
$TempString + (StrReverse $IncomingText.SubString(155,10)) + $IncomingText.SubString(165)
}
}

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()

Can I pipe into a switch statement stored in a variable?

I have a variable that stores a switch statement
$com = '
switch ($_)
{
1 {"It is one."}
2 {"It is two."}
3 {"It is three."}
4 {"It is four."}
}
'
I am trying to pipe in the number to run the switch statement
something like:
1 | iex($com)
Your options are:
A scriptblock or function with a process block:
$com = {
process {
switch ($_) {
1 { "one." }
2 { "two." }
3 { "three." }
}
}
}
function thing {
process {
switch ($_) {
1 { "one." }
2 { "two." }
3 { "three." }
}
}
}
1..3 | & $com
1..3 | thing
A filter, exactly the same functionality:
filter thing {
switch ($_) {
1 { "one." }
2 { "two." }
3 { "three." }
}
}
1..3 | thing
Using ScriptBlock.Create method (this would require a process block in the string expression):
$com = '
process {
switch ($_) {
1 { "one." }
2 { "two." }
3 { "three." }
}
}
'
1..3 | & ([scriptblock]::Create($com))
Using ScriptBlock.InvokeWithContext method and the automatic variable $input, this technique does not stream and also requires an outer scriptblock to work, it's just to showcase and should be discarded as an option:
$com = '
switch ($_) {
1 { "one." }
2 { "two." }
3 { "three." }
}
'
1..3 | & { [scriptblock]::Create($com).InvokeWithContext($null, [psvariable]::new('_', $input)) }
Using Invoke-Expression, also requires an outer scriptblock with a process block (should be discarded - from all techniques displayed above this is the worst one, the string expression is being evaluated per item passed through the pipeline):
$com = '
switch ($_) {
1 { "one." }
2 { "two." }
3 { "three." }
}
'
1..3 | & { process { Invoke-Expression $com } }

Create an array off objects as a class member in 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')

Can somebody shorten this code?

I just finished creating a program (I am a beginner at this programming stuff) Now I might be doing this the total wrong way or my logic might not be the greatest at programming but any help would be amazing I will post my code so far below
This code is used when a button is clicked, the button will send a text then the textbox will get the text.
if (txt1.Text == "")
{
txt1.Text = "J";
btn1.Visible = false;
}
else if (txt1.Text != "")
{
if (txt2.Text == "")
{
txt2.Text = "J";
btn1.Visible = false;
}
else if (txt2.Text != "")
{
if (txt3.Text == "")
{
txt3.Text = "J";
btn1.Visible = false;
}
else if (txt3.Text != "")
{
if (txt4.Text == "")
{
txt4.Text = "J";
btn1.Visible = false;
}
else if (txt4.Text != "")
{
if (txt5.Text == "")
{
txt5.Text = "J";
btn1.Visible = false;
}
else if (txt5.Text != "")
{
if (txt6.Text == "")
{
txt6.Text = "J";
btn1.Visible = false;
}
else if (txt6.Text != "")
{
if (txt7.Text == "")
{
txt7.Text = "J";
btn1.Visible = false;
}
else if (txt7.Text != "")
{
if (txt8.Text == "")
{
txt8.Text = "J";
btn1.Visible = false;
}
else if (txt8.Text != "")
{
}
}
}
}
}
}
}
}
You need to get all of these text cases into an array for the following loop to work (I have called the array 'txt' here). Based on what you have written this loop should do the same thing as your code but I'm not sure if that's what you really want to do. Your code is setting a single text box to "J" and then hiding your button only if every preceding text field is not an empty string (This will include any of the fields set to null, for example). The conditional then exits.
`for (int i = 0; i < txt.Length; i++) {
if(txt[i] != "") {
continue;
}
else if(txt[i] == "") {
txt[i] = "J";
btn1.Visible = false;
break;
}
}
Note: I don't know whether this works for C# 3 or not (it should). Try it.
First, you should put all of your text fields into an array:
TextField[] textFields = { txt1, txt2, txt3, txt4, txt5, txt6, txt7, txt8, };
Then, loop through the text fields to find a text field that has no text in it:
foreach (TextField tf in textFields) {
if (tf.Text == "") {
}
}
After we find it, we want to set its text to "J" and make btn1 invisible. Since we already found the text field, we don't need to continue the loop anymore, so we break:
tf.Text = "J";
btn1.Visible = false;
break;
If this doesn't work in C# 3, just update to C# 5 or 6 alright?

How do you append text in CodeMirror

I know you use
editor.setValue("");
to set one value but how do you append in CodeMirror?
IE:
editor.appendText();?
Use replaceRange. For example editor.replaceRange(myString, CodeMirror.Pos(editor.lastLine())). Re-setting the entire editor is needlessly expensive.
Here is a little script I wrote to add code to any editor (in Joomla):
function addCodeToEditor(code_string, editor_id, merge, merge_target){
if (Joomla.editors.instances.hasOwnProperty(editor_id)) {
var old_code_string = Joomla.editors.instances[editor_id].getValue();
if (merge && old_code_string.length > 0) {
// make sure not to load the same string twice
if (old_code_string.indexOf(code_string) == -1) {
if ('prepend' === merge_target) {
var _string = code_string + "\n\n" + old_code_string;
} else if (merge_target && 'append' !== merge_target) {
var old_code_array = old_code_string.split(merge_target);
if (old_code_array.length > 1) {
var _string = old_code_array.shift() + "\n\n" + code_string + "\n\n" + merge_target + old_code_array.join(merge_target);
} else {
var _string = code_string + "\n\n" + merge_target + old_code_array.join('');
}
} else {
var _string = old_code_string + "\n\n" + code_string;
}
Joomla.editors.instances[editor_id].setValue(_string.trim());
return true;
}
} else {
Joomla.editors.instances[editor_id].setValue(code_string.trim());
return true;
}
} else {
var old_code_string = jQuery('textarea#'+editor_id).val();
if (merge && old_code_string.length > 0) {
// make sure not to load the same string twice
if (old_code_string.indexOf(code_string) == -1) {
if ('prepend' === merge_target) {
var _string = code_string + "\n\n" + old_code_string;
} else if (merge_target && 'append' !== merge_target) {
var old_code_array = old_code_string.split(merge_target);
if (old_code_array.length > 1) {
var _string = old_code_array.shift() + "\n\n" + code_string + "\n\n" + merge_target + old_code_array.join(merge_target);
} else {
var _string = code_string + "\n\n" + merge_target + old_code_array.join('');
}
} else {
var _string = old_code_string + "\n\n" + code_string;
}
jQuery('textarea#'+editor_id).val(_string.trim());
return true;
}
} else {
jQuery('textarea#'+editor_id).val(code_string.trim());
return true;
}
}
return false;
}
The advantage it this script is you can work with multiple editors on the page.