How to output a whole array at once - arrays

I'm coding with PowerShell and want to output a whole array at once. Is that possible?
I need to output a SQL table and don't wanna say $reader[1..20]
Write-Host $reader[0,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]
I don't wanna say a number like $reader[2..3] I wanna output the whole array at once like $reader[*]

You could use StringBuilder:
$sb= [System.Text.StringBuilder]::new()
$reader | % { $sb.Append($_) }
Write-Host ($sb.ToString())
Or use the join operator. For example, join an array and dump every entry on a separate line:
$text = #("a", "b", "c")
Write-Host ($text -join "`n")

How are you populating $reader?
If you are just outputting to the screen, that is the PowerShell default, so no real need for the Write-*.
[array]$reader = 0,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
# Or
$reader = #(0,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31)
$reader
# Result
0
1
2
3
4
5
...
$reader[3]
# Result
3
$reader[0..3]
# Result
0
1
2
3

Related

Expand array so user can select best option and input into variable

I am trying to figure out how to do the following.
Read a text file with phone numbers in a list that are available each number on a separate line.
Output the available list to the script user to be able to select the best one.
Input the $number into another command to add it to the new user.
I have the following so far
$numbers = gc 'C:\temp\file.txt'
I can output the data by using $numbers[1], $numbers[2], etc., but how can I output this to look good and allow the user to select the best number with all options in the text file? I can do it manually obviously, but if I do 3 x $numbers[1], $numbers[2], $numbers[3] it will miss the numbers 4, 5, 6 etc.
try Something like this :
$selected=Get-Content "c:\temp\phone.txt" | Out-Gridview -Title "Select your choice" -OutputMode Single
if ($selected)
{
Write-Host "your choice is $selected"
}
Something like this:
$numbers = Get-Content 'C:\temp\file.txt'
$i = 1
foreach($n in $numbers){
Write-host "Number $i - $n"
$i++
}
$n = Read-host "Choose a number"
$chosenNumber = $number[$n-1]

Unique Combos from powershell array - No duplicate combos

I'm trying to figure out the best way to get unique combinations from a powershell array. For instance, my array might be
#(B,C,D,E)
I would be hoping for an output like this :
B
C
D
E
B,C
B,D
B,E
C,D
C,E
D,E
B,C,D
C,D,E
B,C,D,E
I do not want re-arranged combos. If combo C,D exists already then I do not want combo D,C. It's redundant for my purposes.
I looked into the functions here : Get all combinations of an array
But they aren't what I want. I've been working on figuring this out myself, but have spent quite a bit of time without success. I thought I'd ask the question here so that if someone else already know I'm not wasting my time.
Thanks!
This is an adaptation from a solution for a C# class I took that asked this same question. For any set find all subsets, including the empty set.
function Get-Subsets ($a){
#uncomment following to ensure only unique inputs are parsed
#e.g. 'B','C','D','E','E' would become 'B','C','D','E'
#$a = $a | Select-Object -Unique
#create an array to store output
$l = #()
#for any set of length n the maximum number of subsets is 2^n
for ($i = 0; $i -lt [Math]::Pow(2,$a.Length); $i++)
{
#temporary array to hold output
[string[]]$out = New-Object string[] $a.length
#iterate through each element
for ($j = 0; $j -lt $a.Length; $j++)
{
#start at the end of the array take elements, work your way towards the front
if (($i -band (1 -shl ($a.Length - $j - 1))) -ne 0)
{
#store the subset in a temp array
$out[$j] = $a[$j]
}
}
#stick subset into an array
$l += -join $out
}
#group the subsets by length, iterate through them and sort
$l | Group-Object -Property Length | %{$_.Group | sort}
}
Use like so:
PS C:>Get-Subsets #('b','c','d','e')
b
c
d
e
bc
bd
be
cd
ce
de
bcd
bce
bde
cde
bcde
Note that computational costs go up exponentially with the length of the input array.
Elements SecondstoComplete
15 46.3488228
14 13.4836299
13 3.6316713
12 1.2542701
11 0.4472637
10 0.1942997
9 0.0867832
My tired attempt at this. I did manage to get it to produce the expected results but how it does it is not as elegant. Uses a recursive functionality.
Function Get-Permutations{
Param(
$theInput
)
$theInput | ForEach-Object{
$element = $_
$sansElement = ($theInput | Where-Object{$_ -ne $element})
If($sansElement.Count -gt 1){
# Build a collection of permutations using the remaining elements that were not isolated in this pass.
# Use the single element since it is a valid permutation
$perms = ,$element
For($elementIndex = 0;$elementIndex -le ($sansElement.Count - 1);$elementIndex++){
$perms += ,#(,$element + $sansElement[0..$elementIndex] | sort-object)
}
# For loop does not send to output properly so that is the purpose of collecting the results of this pass in $perms
$perms
# If there are more than 2 elements in $sansElement then we need to be sure they are accounted for
If($sansElement -gt 2){Get-Permutations $sansElement}
}
}
}
Get-Permutations B,C,D,E | %{$_ -join ","} | Sort-Object -Unique
I hope I can explain myself clearly....So each pass of the function will take an array. Each individual element of that array will be isolated from the rest of the array which is represented by the variables $element and $sansElement.
Using those variables we build individual and progressively larger arrays composing of those elements. Let this example show using the array 1,2,3,4
1
1,2
1,2,3
1,2,3,4
The above is done for each "number"
2
2,1
2,1,3
2,1,3,4
and so forth. If the returned array contains more that two elements (1,2 would be the same as 2,1 in your example so we don't care about pairs beyond one match) we would take that array and run it through the same function.
The real issue is that the logic here (I know this might be hard to swallow) creates several duplicates. I suppose you could create a hashtable instead which I will explore but it does not remove the logic flaw.
Regardless of me beating myself up as long as you don't have thousands of elements the process would still produce results.
Get-Permutations would return and array of arrays. PowerShell would display that one element per line. You asked for comma delimited output which is where -join comes in. Sort-Object -Unique takes those sorted string an discards the duplicates.
Sample Output
B
B,C
B,C,D
B,C,D,E
B,C,E #< Missing from your example output.
B,D
B,D,E #< Missing from your example output.
B,E
C
C,D
C,D,E
C,E
D
E

How to store outlook email body in array - Powershell?

the script below reads my outlook emails but how do I access the output. I'm new too Powershell and I'm still getting used to certain things. I just want to get the body of 10 unread outlook emails and store them in an Array called $Body.
$olFolderInbox = 6
$outlook = new-object -com outlook.application;
$ns = $outlook.GetNameSpace("MAPI");
$inbox = $ns.GetDefaultFolder($olFolderInbox)
#checks 10 newest messages
$inbox.items | select -first 10 | foreach {
if($_.unread -eq $True) {
$mBody = $_.body
#Splits the line before any previous replies are loaded
$mBodySplit = $mBody -split "From:"
#Assigns only the first message in the chain
$mBodyLeft = $mbodySplit[0]
#build a string using the –f operator
$q = "From: " + $_.SenderName + ("`n") + " Message: " + $mBodyLeft
#create the COM object and invoke the Speak() method
(New-Object -ComObject SAPI.SPVoice).Speak($q) | Out-Null
}
}
This may not be a factor here, since you're looping through only ten elements, but using += to add elements to an array is very slow.
Another approach would be to output each element within the loop, and assign the results of the loop to $body. Here's a simplified example, assuming that you want $_.body:
$body = $inbox.items | select -first 10 | foreach {
if($_.unread -eq $True) {
$_.body
}
}
This works because anything that is output during the loop will be assigned to $body. And it can be much faster than using +=. You can verify this for yourself. Compare the two methods of creating an array with 10,000 elements:
Measure-Command {
$arr = #()
1..10000 | % {
$arr += $_
}
}
On my system, this takes just over 14 seconds.
Measure-Command {
$arr = 1..10000 | % {
$_
}
}
On my system, this takes 0.97 seconds, which makes it over 14 times faster. Again, probably not a factor if you are just looping through 10 items, but something to keep in mind if you ever need to create larger arrays.
define $body = #(); before your loop
Then just use += to add the elements
Here's another way:
$body = $inbox.Items.Restrict('[Unread]=true') | Select-Object -First 10 -ExpandProperty Body

Powershell array ignorance

'scuse my ignorance...
I use #($var).Count so I can get a count even if $var contains 1 "item".
When my search returns nothing why does my array contain one item?
i.e.
PS C:\Windows\system32> $Groups = $null
Import-Module -Name "activedirectory"
$search = "aaaarggg"
$searchPat = `"*"` + $search + `"*"`
$Groups = Get-ADGroup -Filter {(name -like $searchPat)}
if ($Groups -eq $null) {
"No matches"
#($Groups).Count
}
else {
"Matches"
#($Groups).Count
}
No matches
1
As Lee said you create array which contains one item and the item is null. It may seem illogical, but it is done this way to give you consistent results when decrementing or incrementing the amount of items in the array. Look at the example below. If the #($null).count returned 0 you would jump from 2 to 0.
#($null,$null,$null).Count #output 3
#($null,$null).Count #output 2
#($null).Count #output 1
#().Count #output 0
Ingoring $null values inside the #() operator would also render such situations impossible to handle:
$("a",$null,"c").count #output 3
$("a","b","c").count #output 3
From the Powershell doc
You create an empty array as $a = #()
To count the elements you can simply do
$a.Count
$x = #()
$x.Count
0
As for processing the results of Get-ADGroup, that depends on what it returns. I think you'll find that simply doing
if ($Groups.Count -eq 0 ) {
# process
}
will work for you.

Powershell. Increase value in CSV file or Array

I have a CSV file that looks like:
Initials,Size excl. Backup/Pst,Number of warnings
USER1,100,1
USER2,100,1
USER4,400,2
I would like to increase the value "Number of warnings" by 1 so I will end up with:
Initials,Size excl. Backup/Pst,Number of warnings
USER1,100,2
USER2,100,2
USER4,400,3
I have tried, but not succeeded.
I have also tried putting it in array, but can't get it working.
$Temp = Import-Csv $Database | foreach {$_.'Number of warnings' +1}
But this does 2 things:
only adds 1 to the end of the number so 1 becomes 11 and 2 becomes 21 (as it was a string)
The output is only the "Number of warnings" column - the rest of my information seems to be gone
This works :
$myreport = Import-Csv .\testing.csv
$myreport | %{$_.'Number of warnings' = 1 + $_.'Number of warnings'}

Resources