Add elements to arry in powershell - powershell

I want to simply add some numbers to an array and then sort them via powershell, however, the following code seems to be wrong
$myArray = New-Object System.Collections.ArrayList
Foreach ($Name in $VMName) {
$Tokens = $Name.Split(".")
$myArray.Add($Tokens[$Tokens.Count-1])
}
Write-Host($myArray | Sort-Object)
The error is
+ $myArray.Add($Tokens[$Tokens.Count-1])
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : NotSupportedException
How can I fix that?
The variable $Name is something like 101.u18.uab.14 or 103.win10.template or 102.win7.pink.18 and so on. Each $Name has some . symbols and I want to tokenize them and get the last element for each of them. So, in this example, I want to see a sorted 14 18 template.
UPDATE:
The provided methods seems to be incorrect.
1- This method by Steven
$myArray = New-Object System.Collections.ArrayList
Foreach ($Name in $VMName) {
$Tokens = $Name.Split(".")
[Void]$myArray.Add($Tokens[-1])
}
shows this error
Exception calling "Add" with "1" argument(s): "Collection was of a fixed size."
At C:\Users\user\Desktop\get_ip_list.ps1:20 char:5
+ [Void]$myArray.Add($Tokens[-1])
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : NotSupportedException
2- This method by Santiago
$myArray = [Collections.Generic.List[string]]::new()
Foreach ($Name in $VMName) {
[Void]$myArray.Add($Name.Split(".")[-1])
}
Shows the following error
Exception calling "Add" with "1" argument(s): "Collection was of a fixed size."
At C:\Users\user\Desktop\get_ip_list.ps1:19 char:5
+ [Void]$myArray.Add($Name.Split(".")[-1])
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : NotSupportedException
If I have missed your point in the above codes, please let me know.

I think you are missing the first line from the error. However it looks like you are simply trying to add the last elements from the $Tokens array. In that case you don't need to reference the index like that, below should work:
$myArray = New-Object System.Collections.ArrayList
Foreach ($Name in $VMName) {
$Tokens = $Name.Split(".")
[Void]$myArray.Add($Tokens[-1])
}
Notice the addition of [Void] this will stop the .Add() method from returning the index number it just added to.
Also note you can create array list objects using casting like:
$myArray = [Collections.ArrayList]#()
Update to Address Continued Errors:
The only thing I can think of to cause the error "Collection was of a fixed size." is if you've previously type constrained the variable.
Example:
[String[]]$myArray = #()
# Posibly a whole bunch of other things happening maybe in the console or IDE.
$myArray = [Collections.ArrayList]#()
$myArray.Add('something')
Results:
Exception calling "Add" with "1" argument(s): "Collection was of a fixed size."
At line:1 char:1
+ $myArray.Add('something')...
In this case they type of the $myArray will not change to [Collections.ArrayList]. The problem will be transparent up until you try to use the .Add() method that won't work. This is because an array list is easily and therefore silently cast back to a [String[]] or [Object[]].
Note: If you were to run $myArray.IsFixedSize it would return "True".
My guess as to what's happening; at some point while developing your code or perhaps in the larger script, $myArray got type constrained, and stuck in the scope. This can definitely happen especially given the scope overlap in IDE's like PowerShell's ISE, and I think it happens in VSCode as well. If this is part of a larger script look for instances of $myArray to see if it's indeed type constrained and make corrections as needed. Otherwise a simply restarting your session might do the trick.

Honestly, not sure how could you be getting that error unless the array we're looping through is actually something different. Steven's answer should work fine, I'll put this code below just to show that the results we get are the ones you expect:
$col = [Collections.Generic.List[String]]::new()
$vmName = #(
'101.u18.uab.14'
'103.win10.template'
'102.win7.pink.18'
)
ForEach($name in $vmName)
{
$col.Add($name.Split('.')[-1])
}

if you want absolutly use array you can simply do it :
$Array=#()
$VMName | %{
$Value=($_.Split('.'))[-1]
$Array+= $Value
}
$Array| sort
Otherwise you can simply do it :
$VMName | %{($_.Split('.'))[-1]} | sort

Related

Weird PowerShell problem: [ref] cannot be applied to a variable that does not exist

My Powershell script exited with "[ref] cannot be applied to a variable that does not exist" after running a while (it actually worked for a while)
The code snippet is something like
function outputData(...) {
$data = $null
if ($outputQueue.TryTake([ref] $data, 1000) -eq $false) {
continue
}
Write-Host $data
}
The detail errors thrown at the end are as below:
[ref] cannot be applied to a variable that does not exist.
At C:\Program Files\mfile.ps1:1213 char:13
+ if ($outputQueue.TryTake([ref] $data, 1000) -eq $ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (data:VariablePath) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : NonExistingVariableReference
May i ask if any thoughts about the cause ?
Thanks !
While error messages aren't always helpful, this one is:
It tells you that the $data variable you're trying to use with [ref] must already exist, i.e., must have been created explicitly, which in PowerShell means:
creating it by assigning a value to it - even if that value is $null,
or using New-Variable to create it.
A simplified example:
$data = $null # create variable $data
# OK to use $data with [ref], now that it exists.
# $data receives [int] value 10 in the process.
[int]::TryParse('10', [ref] $data)

Not able to call out array headers in a foreach loop

Okay - this is a really weird issue - and it probably has a really stupid solution.
But i import a csv
$csv = import-csv c:\users\hello.csv
Then i have an array of words, for which i am wanting to use to search through the csv - and if there's a match in the csv - populate an adjacent column in the csv.
here's the array:
$newhandles
hi
hello
now - if i run a foreach loop with an if statement inside of it - it doesn't recognize one of the headers.
foreach ($newhandle in $newhandles)
{if ($csv.name -eq $newhandle) {$csv.redundant = $newhandle}}
however it gives me this error:
The property 'redundant' cannot be found on this object. Verify that the property exists
and can be set.
At line:1 char:69
+ ... andles) {if ($csv.name -eq $newhandle) {$csv.redundant = $newhandle}}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException
I know the property exists - because if i call it directly - it shows three empty slots - and if i call something to it directly - the element will populate. such as
> $csv[0].redundant = 'hi'
> $csv[0]
name : hi
description : don't settle
system : sight
redundant : hi
tags :
Any ideas?
try using this foreach loop :
foreach ($rec in $csv){
if($newhandles -contains $rec.name){
$rec.redundant = $rec.name
}
}
if you check ($csv.redundant).GetType(),you can see that it returns an array instead of the property you want but when you are assigning value to $csv[0].redundant you are accessing the exact property and that's why it works when you tested manually
try this
import-csv "c:\users\hello.csv" | select * , #{N="redundant";E={if ($newhandles -contains $_.Name) {$_.Name} else {$null}}} -ExcludeProperty redundant

Need to add and find element index value in arraylist in powershell?

add string element in arraylist and find it's index value?
[code...]
$eventList = New-Object System.Collections.ArrayList
$eventList.Add("Hello")
$eventList.Add("test")
$eventList.Add("hi")
Not working throwing error:-
Method invocation failed because [System.String[]] doesn't contain a method named 'Add'.
At C:\Users\Administrator\Desktop\qwedqwe.ps1:9 char:15
+ $eventList.Add <<<< ("Hello")
+ CategoryInfo : InvalidOperation: (Add:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
As mentioned in the comments, if you've developing this in ISE (or another IDE) and previously assigned $eventList with a type cast, like so:
[string[]]$eventList = #()
or similar, commenting out previous lines won't help you - the variable already exists and will have that type bound to it for the remainder of its lifetime.
You can remove any previous assignments with Remove-Variable eventList
Once you've got that sorted, we can move on to actually locating the index. If you're interested in the index of an exact match, use IndexOf():
PS> $eventList.IndexOf('hi')
2
If that isn't flexible enough, use the a generic List<T>, which implements FindIndex().
FindIndex() takes a predicate - a function that returns $true or $false based on input (the items in the list):
$eventList = New-Object System.Collections.Generic.List[string]
$eventList.Add("Hello")
$eventList.Add("test")
$eventList.Add("hi")
$predicate = {
param([string]$s)
return $s -like 'h*'
}
And then call FindIndex() with the $predicate function as the only argument:
PS> $eventList.FindIndex($predicate)
0
(it matches Hello at index 0 because it starts with an h)

Weird PowerShell Exec Output Capture Behavior

I'm writing a simple PowerShell script that handles the output of mkvinfo. It captures the output of mkvinfo, stores in a variable $s and does some post-processing on $s. The strange part is while $s has content, I can't extract a substring from it.
The error message I'm getting was:
Exception calling "Substring" with "1" argument(s): "startIndex cannot be larger than length of string.
Parameter name: startIndex"
This is a sample code:
$filePath = $folder + $file.name
$mkvinfoExe = "C:\mkvinfo.exe"
$s = & $mkvinfoExe $filePath
$s | out-host
$s.Substring($s.Length-1) | out-host
Are you sure $s is a string and not an array? If it is an array, $s.Length will be the number of elements in the array and you could get the error that you are getting.
For example:
PS > $str = #("this", "is", "a")
PS > $str.SubString($str.Length - 1)
Exception calling "Substring" with "1" argument(s): "startIndex cannot be larger than length of string.
Parameter name: startIndex"
At line:1 char:1
+ $str.SubString($str.Length - 1)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentOutOfRangeException
Just found out because mkvinfo outputs multiple lines, $s is actually a String array (or List?). Switching to $s[0].Substring($s[0].Length-1) solves it.

Calling [ADSI] with external parameter

I am not very familiar with powershell scripting and I'm stuck on this problem -
I need to make some operations on object retrieved like this:
$object = [ADSI]'LDAP://CN=Test User,OU=Dept,OU=Users,DC=example,DC=org'
...
$object.Commit()
this works fine, but I have to use distinguished name stored in variable - my test script looks like this, but its not working:
$object = [ADSI]'LDAP://$variable'
...
$object.Commit()
the first call to [ADSI] itself doesn't cause error, but any following operation crashes with message:
The following exception occurred while retrieving member "commit": "The server is not operational.
"
At line:1 char:10
+ $object.commit <<<< ()
+ CategoryInfo : NotSpecified: (:) [], ExtendedTypeSystemException
+ FullyQualifiedErrorId : CatchFromBaseGetMember
I'm pretty sure, that the parameter is sent in some wrong way, but I don't know, how to fix it, can anybody help?
tahnks
Try:
$object = [ADSI]"LDAP://$variable"
Single quotes don't expand variables.