convert a string collection into a string array in powershell - powershell

as the title says how can I convert a string collection into a string array in powershell don't know where to start with this as I am new to powershell. Would it be anything like String[])$viewFields.toArray(new String[0])

You should try type conversion ([object[]]). Here is an example:
$x = New-Object System.Collections.ArrayList # Definitely not an object array
([object[]]$x).GetType() # Object[]

To create an array out of anything surround with #(...). To create an array of a specific type, System.Array has some factory methods and use [type] to get a Type object. Thus
$theArray = #($viewFields.toArray([array]::CreateInstance([string], 0)))

Related

Returning a List[String] using a comma vs not using a comma

how does putting a comma before a list affect its type?
Have a look at the following code:
function StartProgram
{
$firstList = getListMethodOne
Write-Host "firstList is of type $($firstList.gettype())"
$secondList = getListMethodTwo
Write-Host "secondList is of type $($secondList.gettype())"
}
function getListMethodOne
{
$list = new-object system.collections.generic.list[string]
$list.Add("foo") #If there is one element, $list is of type String
$list.Add("bar") #If there is more than one element, $list is of type System.Object[]
return $list
}
function getListMethodTwo
{
$list = new-object system.collections.generic.list[string]
$list.Add("foo")
$list.Add("bar")
return ,$list #This is always of type List[string]
}
StartProgram
Why is it, if you don't use a comma before returning $list in getListMethodOne it returns as type System.Object[], whereas if you do use a comma as in getListMethodTwo, it is of type List[string] as expected?
PS: I'm using PSVersion 4.0
When you return collection, than PowerShell is kind enough to unravel it for you.
Unary comma creates collection with single element, so "external" collection gets unraveled and collection you want to return is kept.
I blogged about it a while ago.
Two more things:
return is used in PowerShell to leave function early, it's not needed to return something from function (any not captured output is returned)
in PowerShell 4.0 you can use Write-Output -NoEnumerate $collection to prevent unraveling your collection.
I don't have a full answer, but I would bet this relates to PowerShell's 'flattening' behaviour.
By using the unary operator ',' you are creating a new collection wrapper around the $list object. After PowerShell 'flattens' this, you see the object that was inside the wrapper.
A fuller explaination here: http://rkeithhill.wordpress.com/2007/09/24/effective-powershell-item-8-output-cardinality-scalars-collections-and-empty-sets-oh-my/

Powershell Need To Specify Type Of Object

Why do I need to declare the type of a variable when assigning it with a list?
In the below code, I need to specify that $firstList is of type list[string], if I don't do that, then its type is Object[], even though in the function returning that list, the list is of type list[string].
function StartProgram
{
[system.collections.generic.list[string]]$firstList = getList
$secondList = getList
Write-Host "firstList is of type $($firstList.gettype())"
Write-Host "secondList is of type $($secondList.gettype())"
}
function getList
{
$list = new-object system.collections.generic.list[string]
$list.Add("foo")
$list.Add("bar")
return $list
}
StartProgram
<#
Output:
firstList is of type System.Collections.Generic.List[string]
secondList is of type System.Object[]
#>
PowerShell functions write output to the output stream and when a collection is presented as output, the default behavior is to enumerate the collection and output that. What you get on the other side - when you assign the output to a collection - as an array of objects. That is, the List gets lost during the output operation. You can change this behavior by wrapping the list in an array with it as the single element by changing the return statement to;
return ,$list
or more simply just;
,$list

Joining together strings into Powershell variable names

I'm working with treeviews in Powershell - I have a different node for each of our buildings. In my code I'm grabbing variables, Joining them together, and using that as the variable name - but my code is seeing the variable as a string instead of the name of a node that already exists... so I'm getting
You cannot call a method on a null-valued expression.
How can I do this? It would save me from hard-coding in every floor in every building. Here's what my code looks like:
$bldg = "SG1-1" //for example
function refreshPrinterList ( $bldg )
{
$bldg1 = $bldg.substring(0,3)
$floor = $bldg.substring(4,1)
$refreshNode = -join('$TreeNode_',$bldg1,'_',$floor)
$refreshNode.gettype() //Returns System.String`
if($bldg1 -eq "SG1") {
if($floor -eq "1") {
$count = $refreshNode.Nodes.Count
while($refreshNode.Nodes.Count -gt 0)
{
$refreshNode.Nodes.RemoveAt($count)
$count--
}
The -join operator is for strings, and dutifully gives you one back instead of a TreeNode that you want. If you are passing in a string ($bldg looks like a string from your example), then you can do all the string manipulation you want, but there is no TreeNode object in that function to assign a name to. So, we need to make a TreeNode that your function could use. What about something like this?
$newNodeName = -join('$TreeNode_',$bldg1,'_',$floor)
$refreshNode = New-Object System.Windows.Forms.TreeNode($newNodeName )
// do stuff with $refreshNode as it is a TreeNode object like you expect
This $refreshNode will have no Nodes inside of it since we just fabbed it up. Since it looks like you want to modify an existing TreeNode object, pass in the $refreshNode as an argument then modify its friendly description with the $newNodeName.
I was pointed in the right direction over on the Technet Social forum
My question on Technet
The answer was using 'Get-Variable'
I had the two variables $bldg1 and $floor which I joined into a string:
$newNodeName = -join('TreeNode_',$bldg1,'_',$floor)
and then I passed that using 'Get-Variable' - but I had to put the variable name within parantheses, like so:
$refreshNode = (Get-Variable ($newNodeName)).Value
Now, instead of returning a string type it returns my existing string!

How to compare the contents of two string objects in PowerShell

In PowerShell I have an array of string objects, and I have an object that contains string objects. In Java you can do a .equals(aObject) to test if the string values match, whereas doing a == test if the two objects refer to the same location in memory.
How do I run an equivalent .equals(aObject) in powershell?
I'm doing this:
$arrayOfStrings[0].Title -matches $myObject.item(0).Title
These both have the exact same string values, but I get a return value of false. Any suggestions?
You want to do $arrayOfString[0].Title -eq $myPbiject.item(0).Title
-match is for regex matching ( the second argument is a regex )
You can do it in two different ways.
Option 1: The -eq operator
>$a = "is"
>$b = "fission"
>$c = "is"
>$a -eq $c
True
>$a -eq $b
False
Option 2: The .Equals() method of the string object. Because strings in PowerShell are .Net System.String objects, any method of that object can be called directly.
>$a.equals($b)
False
>$a.equals($c)
True
>$a|get-member -membertype method
List of System.String methods follows.

Why does Powershell's "return" keyword cause type errors?

$xml = [xml] '<node>foo</node>'
function foo2 { return "foo2" }
# all of these fail with the message:
# **Cannot set "foo" because only strings can be used as values to set XmlNode properties.**
$xml.node = foo2
$xml.node = foo2 -as [string] # because of this issue[1]
$xml.node = (foo2)
# these work
$xml.node = (foo2).tostring()
$xml.node = (foo2) -as [string]
$xml.node = [string] (foo2)
# yet, these two statements return the same value
(foo2).gettype()
(foo2).tostring().gettype()
1: PowerShell functions return behavior
Got some confirmation from the PowerShell team on this one. This appears to be a bug in the XML adapter. If you look at the object that is spit out by foo2 in a debugger it is a PSObject. If you don't use the return keyword and instead just output the string "foo2" then the function returns a string object.
The bug in the XML adapter is that it is not unwrapping the PSObject to get at the base object. As a result when it tries to assign the PSObject to $xml.node it fails. For now, as a workaround, you can manually unwrap the psobject like so (or just cast to [string]):
$xml = [xml] '<node>foo</node>'
function foo2 { return "foo2" }
$xml.node = (foo2).psobject.baseobject
$xml
node
----
foo2
Depending on the context, functions may return an array (of length 1) where your expected result is at index 0 in the array. To ensure you always get a scalar if a single element is returned wrapped in an array, use the following syntax:
$xml.node = $( myfunc )
Hope this helps,
-Oisin
p.s. I know others cannot repro this, and nor can I, but I suspect your demo code is cut out from some other, larger script.
Based on this article I would assume that the compiler decides it doesn't know the output type of foo2 well enough to accept it despite it being 'obvious' that it will always be a string I assume there is some code route capable of adding something more to the output that is never exercised...
Update: Keith Hill's answer is the correct one not this one