Store return value to variable - powershell

I have the below code to convert assign GB/TB value based on size
$datastoreCapacity = $store.CapacityGB
$postfixes = #("GB", "TB", "PB" )
for ($i=0; $datastoreCapacity -ge 1024 -and $i -lt $postfixes.Length; $i++) { $datastoreCapacity = $datastoreCapacity / 1024; }
return "" + [System.Math]::Round($datastoreCapacity,2) + " " + $postfixes[$i];
$datastoreFree = $store.FreeSpaceGB
$postfixes = #("GB", "TB", "PB" )
for ($i=0; $datastoreFree -ge 1024 -and $i -lt $postfixes.Length; $i++) { $datastoreFree = $datastoreFree / 1024; }
return "" + [System.Math]::Round($datastoreFree,2) + " " + $postfixes[$i];
But when I am trying to assign the return value to variable like below i am getting error
$datastoreCapacity = return "" + [System.Math]::Round($datastoreCapacity,2) + " " +
Please let me know how can i store the value in variable

Why not make a small helper utility function for this:
function Format-Capacity ([double]$SizeInGB) {
$units = 'GB', 'TB', 'PB'
for ($i = 0; $SizeInGB -ge 1024 -and $i -lt $units.Count; $i++) {
$SizeInGB /= 1024
}
'{0:N2} {1}' -f $SizeInGB, $units[$i]
}
Then getting the formatted sized is as easy as:
$datastoreCapacity = Format-Capacity $store.CapacityGB
$datastoreFree = Format-Capacity $store.FreeSpaceGB

Related

How to prevent random output?

When I run my script it adds an output I haven't requested.
$input = Read-Host -p "Message?";
$morseFile = Get-Content C:\Users\lukas.downes\Documents\Script\morse.csv
$letter;
$code;
$outputAsString = "";
for ($j = 0; $j -lt $input.Length; $j++)
{
for ($i = 1; $i -lt $morseFile.Length; $i++)
{
$letter = ([string]$morseFile[$i]).Split(',')[0];
$code = ([string]$morseFile[$i]).Split(',')[1];
if ($input[$j] -eq $letter)
{
$outputAsString += $code;
write-host ("" + $letter + ": " + $code)
}
}
}
Write-Host $outputAsString
and this outputs:
> Message?: sos
> Z
> --..
> S: ...
> O: ---
> S: ...
> ...---...
which is rather weird, as I don't even use a "Z" in my script.
If your input csv morse.csv looks anything like this:
Letter,Code
O,---
P,.--.
Q,--.-
R,.-.
S,...
Then this should work for you:
# import the csv as array of objects
$codes = Import-Csv -Path 'C:\Users\lukas.downes\Documents\Script\morse.csv'
# for more speed, change this array of objects into a lookup Hashtable
$morse = #{}
foreach ($item in $codes) {
$morse[$item.Letter] = $item.Code
}
$inputString = Read-Host -p "Message?"
if (![string]::IsNullOrWhiteSpace($inputString)) {
$inputString.ToUpper().ToCharArray() | ForEach-Object {
'{0}: {1}' -f $_, $morse[$_.ToString()] # or: $morse["$_"]
}
}
When entering 'sos', the output is:
S: ...
O: ---
S: ...
P.S. Don't use $input as self-defined variable, because it is an Automatic variable

Are nested loops and if statements allowed in PowerShell?

I could use some help with nested loops in PowerShell. I have a document which has item names. I have a folder full of images. I'm looping through the item names and testing if there are any images for that item. An item will only be listed in the document once, but it may have multiple images. For example, ItemXYZ in the doc could have ItemXYZ, ItemXYZ_1, and ItemXYZ_2 in the images folder. This code works for what I'm attempting to do:
for ($i=2; $i -le $rowCount; $i++) {
Write-Host -NoNewline ("Checking line $i of $rowCount`n")
$item = $worksheet.Cells.Item($i,1).Text #Item(row,column)
foreach ($image in $images) {
if ($item -eq $image.BaseName) {
$worksheet.Cells.Item($i,21).Value = $hyperlinkchunk1 + $image.FullName + $hyperlinkchunk2 + $image.Name + $hyperlinkchunk3
Write-Host ("** MATCH **")
}
for ($x=1; $x -le 12; $x++) {
if ($item+'_'+$x -eq $image.BaseName) {
$z = $x+21
$worksheet.Cells.Item($i,$z).Value = $hyperlinkchunk1 + $image.FullName + $hyperlinkchunk2 + $image.Name + $hyperlinkchunk3
Write-Host ("** MATCH **")
}
}
}
}
The first image for an item will always be just the base name so there is no need to check for the 12 underscore images if the first doesn't exist. Because of this, I want to put the nested for statement within the first if statement (updated code block below). This leads me to the issue. When I make this adjustment I do not get all the matches found by using the first block of code. Any idea why?
for ($i=2; $i -le $rowCount; $i++) {
Write-Host -NoNewline ("Checking line $i of $rowCount`n")
$item = $worksheet.Cells.Item($i,1).Text #Item(row,column)
foreach ($image in $images) {
if ($item -eq $image.BaseName) {
$worksheet.Cells.Item($i,21).Value = $hyperlinkchunk1 + $image.FullName + $hyperlinkchunk2 + $image.Name + $hyperlinkchunk3
Write-Host ("** MATCH **")
for ($x=1; $x -le 12; $x++) {
if ($item+'_'+$x -eq $image.BaseName) {
$z = $x+21
$worksheet.Cells.Item($i,$z).Value = $hyperlinkchunk1 + $image.FullName + $hyperlinkchunk2 + $image.Name + $hyperlinkchunk3
Write-Host ("** MATCH **")
}
}
}
}
}
I don't see anything in your code itself that would prevent it from working the way you're expecting it to. Andrew Davis is probably on the right track with his comment that some of your original matches were from the loop and not the If statement and the information you're loading into the script is a bit off. I'd say check those first.
If you're still running into issues, perhaps try putting a check variable in the If statement and use that to control the loop.
foreach ($image in $images) {
$match = $false
if ($item -eq $image.BaseName) {
$worksheet.Cells.Item($i, 21).Value = $hyperlinkchunk1 + $image.FullName + $hyperlinkchunk2 + $image.Name + $hyperlinkchunk3
Write-Host ("** MATCH **")
$match = $true
}
if ($match = $true) {
for ($x = 1; $x -le 12; $x++) {
if ($item + '_' + $x -eq $image.BaseName) {
$z = $x + 21
$worksheet.Cells.Item($i, $z).Value = $hyperlinkchunk1 + $image.FullName + $hyperlinkchunk2 + $image.Name + $hyperlinkchunk3
Write-Host ("** MATCH **")
}
}
}
}
Obviously, having the loop inside the first If statement is preferable, but this option will work too.

Powershell - .csv split strings

I am trying to use powershell for extracting email addresses from a .csv file.
Each row in the .csv may have none or more emails separated by ",".
f.e.
Email
info#domain.com, email#domain.com, person#contonso.com
something#domain.com
My goal is to write it that way so I can get the "info#" from the row if it is present + 1 extra email from the row if it is present. If there is no "info#" get at least 1 or 2 emails from that row.
Here is the fracture of the code, where I am manually able to say on what position is what email, but I am not able to get this part to work in the for cycle which I could use to enumerate the number of occurences as it appears I cannot convert it to int at all.
$Occurrences = $email.Split(",").GetUpperBound(0);
[int]$Occurrences
$data = Import-Csv -path $path
foreach($contact in $data)
{
$email = $contact.Email
if($email.Contains("info"))
{
$emailSplit = $contact.Email.Split(",")
$Occurrences = $email.Split(",").GetUpperBound(0);
[int]$Occurrences
$name = $domainSplit[0]
for([int]$i = 0;-lt $Occurrences.ToInt32(); $i++)
{
}
}
}
Any help is appreciated.
This is not a valid CSV Format. Cant you export the data via JSON from the datasource?
You need to split the single lines and then do your operations
$data = Get-Content -path $path
for($i=1; $i -lt $data.Length; $i++)
{
$emailSplit = [array]$data[$i].Split(",")
for($j = 0; $j -lt $emailSplit.Length; $j++) {
<#do your operation here...
loop once through the elements, check for info#, and then assign them accoringly...
#>
}
}
V2:
$data = Get-Content -path $path
for($i=1; $i -lt $data.Length; $i++)
{
$emailSplit = [array]$data[$i].Split(",")
Write-Host ('Results for line: ' + $i)
$infoFound = $false
for($j = 0; $j -lt $emailSplit.Length; $j++) {
if($emailSplit[$j] -match 'Info#*') {
$infoFound = $true
$infoPos = $j
}
}
[array]$results = $emailSplit[0]
$results += $emailSplit[-1]
if($infoFound) {
if($infoPos = 0) {$results[1] = $emailSplit[$infoPos]}
else {$results[0] = $emailSplit[$infoPos]}
}
Write-Host ('Element1: ' + $results[0] + ' Element2: ' + $results[1])
}

Convert Array of Numbers into a String of Ranges

I was asking myself how easily you could convert an Array of Numbers Like = 1,2,3,6,7,8,9,12,13,15 into 1 String that "Minimizes" the numbers, so Like = "1-3,6-9,12-13,15".
I am probably overthinking it because right now I don't know how I could achieve this easily.
My Attempt:
$newArray = ""
$array = 1,2,3,6,7,8,9,12,13,15
$before
Foreach($num in $array){
If(($num-1) -eq $before){
# Here Im probably overthinking it because I don't know how I should continue
}else{
$before = $num
$newArray += $num
}
}
This should working, Code is self explaining, hopefully:
$array = #( 1,2,3,6,7,8,9,12,13,15 )
$result = "$($array[0])"
$last = $array[0]
for( $i = 1; $i -lt $array.Length; $i++ ) {
$current = $array[$i]
if( $current -eq $last + 1 ) {
if( !$result.EndsWith('-') ) {
$result += '-'
}
}
elseif( $result.EndsWith('-') ) {
$result += "$last,$current"
}
else {
$result += ",$current"
}
$last = $current
}
if( $result.EndsWith('-') ) {
$result += "$last"
}
$result = $result.Trim(',')
$result = '"' + $result.Replace(',', '","') +'"'
$result
I have a slightly different approach, but was a little too slow to answer. Here it is:
$newArray = ""
$array = 1,2,3,6,7,8,9,12,13,15
$i = 0
while($i -lt $array.Length)
{
$first = $array[$i]
$last = $array[$i]
# while the next number is the successor increment last
while ($array[$i]+1 -eq $array[$i+1] -and ($i -lt $array.Length))
{
$last = $array[++$i]
}
# if only one in the interval, output that
if ($first -eq $last)
{
$newArray += $first
}
else
{
# else output first and last
$newArray += "$first-$last"
}
# don't add the final comma
if ($i -ne $array.Length-1)
{
$newArray += ","
}
$i++
}
$newArray
Here is another approach to the problem. Firstly, you can group elements by index into a hashtable, using index - element as the key. Secondly, you need to sort the dictionary by key then collect the range strings split by "-" in an array. Finally, you can simply join this array by "," and output the result.
$array = 1, 2, 3, 6, 7, 8, 9, 12, 13, 15
$ranges = #{ }
for ($i = 0; $i -lt $array.Length; $i++) {
$key = $i - $array[$i]
if (-not ($ranges.ContainsKey($key))) {
$ranges[$key] = #()
}
$ranges[$key] += $array[$i]
}
$sequences = #()
$ranges.GetEnumerator() | Sort-Object -Property Key -Descending | ForEach-Object {
$sequence = $_.Value
$start = $sequence[0]
if ($sequence.Length -gt 1) {
$end = $sequence[-1]
$sequences += "$start-$end"
}
else {
$sequences += $start
}
}
Write-Output ($sequences -join ",")
Output:
1-3,6-9,12-13,15

How to get range between 0 and a number with Powershell?

From a number (163 - 1 ) and a scope (20), I try to get ranges (0..19, 20..39, ..., 160..162)
I can get all exept 160..162
$Counter = 163 -1
$Scope = "20"
$Modulo = $Counter % $Scope
$NbrLoop = [Math]::Ceiling($Counter / $Scope)
$j = 0
For($i=0; $i -le $Counter;$i++)
{
If($i % $Scope -eq 0 -and $i -ne 0)
{
$k = $i
$j..--$k
$j = $i
""
}
}
Could you please let me know how to proceed to get last range (160,161,162) ?
modify condition in if to accept last iteration
If($i % $Scope -eq 0 -and $i -ne 0 -or $i -eq $Counter)
however --$k must not be done int that case
$k = If ( $i -eq $Counter ) { $i } else { $i-1 }
$j..$k
Otherwise the number of iterations can be reduced
For($i=0; $i -lt $NbrLoop;$i++)
{
$j = $i * $scope;
$k = If( $i -eq $NbrLoop -1 ) { $Counter } else { ($i+1)*$scope -1 };
$j..$k
""
}