Hello all, first post. I am fairly new to powershell, though I have been coding one way or another since I was young. I am working on a windows profile data migrator (my company needs some special things done, and I need practice with powershell), and I am looking to grab 2 pieces of information. The profile location paths and the profile sids. No problem there. but I need to store them after a bit of formating. I would prefer to store them in a 2D array, so that I can reference the row when I need specific data.
So I went on line and looked at a few tutorials on arrays. all seems to work well, until I go multi-D. for instance, this:
$array = @(1, 2, 30, 50)
will allow me to run $array[2] and get 30. if I add another level to it like so:
$array = @(1,2,3), @(10,20,30)
Some odd things start to happen. First off I would think that $array[0][1] would return the 2nd element of the first row, but it actually returns a blank. To get it to return 2, I have to use $array[0][2]. Also, the double digits are stored singly. When running $array I get:
1 2 3
10 20 30
It appears that the array stores the separators as well as each individual digit (or letters in the string in my practical work) in the array. To me this seems to be less that preferred behavior. Can someone explain this to me or point me in the right direction on documentation on this (Powershell on win10)
So, arrays do work a bit differently. I’ve honestly not run across someone using multidimensional arrays like this in PowerShell; it offers so many more-robust ways of managing data, I think, that this just hasn’t come up for me :).
For example, I’d probably create an object, which had properties for whatever I wanted to store:
$array = @() $props = @{Username='whatever' ProfilePath='this' ProfileSID='12334'} $obj = New-Object -Type PSObject -Prop $props $array += $obj
You can then reference $array[0] to get the first one, and the advantage is you can reference $array[0].ProfileSID to get that property. Your code becomes a lot easier to read and maintain, because nobody has to document or guess what the array structure is meant to look like.
It also means the entire rest of PowerShell will “understand” your data structure. You could easily…
$array | Export-CSV file.csv $array | ConvertTo-HTML | Out-File report.html $array | Format-Table $array | Where Name -like '*Don*' | Sort ProfileSID | Format-List
And so on. Whereas, by kind of rolling your own thing via arrays, PowerShell won’t have a clue what you’re up to, and you’ll end up doing a lot more work on your own.
Ok. I’m good with doing that. It seems odd that you could not just may your object itself a container then and reference the various ‘cells’. Just a thought. I will use this method for now, it does what I want and like you said, it reduces the need for some documentation. Thanks for the info. My view of arrays may be a bit old school…
Try this:
$array = @(@(1,2,3), @(10,20,30))
im a bit puzzled, on win7 all goes like you expect…
Have a look at Back to Basics: Arrays – PwrShell.net
With that array, try running these lines:
$array
$array[0][0]
$array[0][1]
for those lines I get these results:
1 2 3
10 20 30
1
The last line will return a blank space (that is between cells [0][0] and [0][2]
the first return counts every char (spaces and all) as a cell each. In any case, Don Jones has given me the details and solution I need.
Thanks also Simon B. Though this too works, the method put forward by Don allows easier use and management. Also viewing the object I can see rows and columns with headers (easier when trouble shooting).
seems there something in your profile
try to launch “powershell -noprofile” and repeat you tests
$array should display its contents one-on-a-line
and you see output like “write-host $array”
Max, I would think so too. Could it be a change at the newer versions of PowerShell? I am using win10.
@Don Jones:
found a bit of a kink in the armor on your solution. If I add the $obj to the array, I would have to create a new object each time I wanted to add a value. That seems a bit inefficient, especially if this is done in a for loop. I am also getting an error that the array is of a fixed size.
Maybe I need to go over the scenario in a bit more detail… Maybe I’m not doing it the best way.
Here are the Steps I am going through at this point of the code:
- my function is passed 2 computer names. Using Get-WmiObject I grab the list of user paths and sids:
$users1 = Get-WmiObject win32_UserProfile -ComputerName $cName1 -Filter "sid like '%1234567890%'" | select localPath,SidI do this for each computer (filling $users1 and $users2) then I do a compare to grab the users that are the same on both machines:
$sameUsers = Compare-Object -ReferenceObject $users1 -DifferenceObject $users2 -Property localPath -PassThru -IncludeEqual -ExcludeDifferent
- so I have these lists. Initially I would just parse out the path info to get the user’s name to populate a dropdown box, so the operator can select a user that has a profile on both machines. Usually, this should only be person, but there will be times when there are more, so I need to track the selected username, and the SID for that user.
so here I am trying to populate a list of data into an array, so that I can reference it later when needed. I really don’t need the fields to be named, I just need to be able to get back at the data, and was hoping to use the IndexOf to get the row, then retrieve the column of data I need.
Sorry if I multi-posted, but I’m new here and did not notice the ‘Due to an uptick in spam posts…’ message at first.
In any case, I guess I was asking for the wrong ‘stuff’. I was poking around a bit more and found this page on hashtables:
My solution was to create a nested hashtable. Though they did not show it on the page, I found that you can also define keys with variables, which works out perfect for me. Once I have the data from the win32 output in $sameUsers, I for $i looped through it to grab what I wanted :
(after defining the hashtable as $profileData = @{} )
if ($sameUsers.count -gt 0) { for($i=0;$i -le $sameUsers.count -1; $i++) { #parse data to get what we need from it and store it in the $profileData array $aPath = $sameUsers[$i].localPath $someStrings = $aPath.Split("\") $aUser = $someStrings[$someStrings.GetUpperBound(0)].ToUpper() $aSid = $sameUsers[$i].Sid $profileData.$aUser = @{path = $aPath; SID = $aSid} $aList.Items.Add($aUser) } }
I could then easily access the key value ($aList is a combo box) when the combobox value is changed:
$tempUser = $profileCombobox.SelectedItem $pSIDLabel.Text = $profileData.$tempUser.SID
I’m sure I could have done this without the tempUser var, but this is easier to read. In anycase, this does exactly what I want. Sorry if my description of the problem was off… To be honest, I have never used hashtables before.