I try to remove empty lines or values in an array, for example if the output of $DBLevel is empty, the hole line should be removed. Is there a easy way to to this?
thanks
$vmname= "srvsql009"
$DBType = "sql"
$DBLevel = ""
$style = "blue"
$myCol = #()
$x = "" | Select 'Name','DB-Type','DB-Level','Style'
$x.Name = $vmname
$x.'DB-Type' = $DBType
$x.'DB-Level' = $DBLevel
$x.'Style' = $style
$myCol += $x
$myCol
IsPublic IsSerial Name BaseType
True True Object[] System.Array
Imagine you had results like this in your $myCol variable.
PS> $myCol
Name DB-Type DB-Level Style
---- ------- -------- -----
srvsql009 sql blue
SQLSRV200 cosmos ALPHA RED
You can filter items in an array using the Where-Object command, like this:
PS> $myCol | Where DB-Level -ne ""
Name DB-Type DB-Level Style
---- ------- -------- -----
SQLSRV200 cosmos ALPHA RED
PowerShell comparison operators are different from most every other programming language, meaning you can't use == to compare equals, or <= for less than or equal to operations.
To learn more about the comparison operators, check out this link.
Continuing from my comment,
Removing elements from a simple array (Object[]) is both time and memory consuming because an array is of fixed length and when you remove an element, the whole array needs to be rebuilt in memory.
If you have a collection you need to be able to remove items from, better make use of a [System.Collections.Generic.List[object]]
Example collection (following your syntax)
$vmname = "srvsql009"
$DBType = "sql"
$DBLevel = 120
$style = "blue"
$list = [System.Collections.Generic.List[object]]::new()
for ($i = 0; $i -lt 5; $i++) {
$x = "" | Select 'Name','DB-Type','DB-Level','Style'
$x.Name = 'srvsql{0:D3}' -f ([int]$vmname.Substring(6) + $i) # for demo, increment the number
$x.'DB-Type' = $DBType
$x.'DB-Level' = if ($i -eq 3) {$null} else {$DBLevel + $i} # for demo add an object with empty 'DB-Level'
$x.'Style' = $style
# add this object to the list
$list.Add($x)
}
$list now contains
Name DB-Type DB-Level Style
---- ------- -------- -----
srvsql009 sql 120 blue
srvsql010 sql 121 blue
srvsql011 sql 122 blue
srvsql012 sql 123 blue
srvsql013 sql 124 blue
Now, if you want to remove one of the items in this list, you can do that using its index:
$list.RemoveAt(2) # removes item 'srvsql011'
Result:
Name DB-Type DB-Level Style
---- ------- -------- -----
srvsql009 sql 120 blue
srvsql010 sql 121 blue
srvsql012 sql blue
srvsql013 sql 124 blue
Or remove by determining the object to delete:
$x = $list | Where-Object { !$_.'DB-Level' }
$list.Remove($x)
Result:
Name DB-Type DB-Level Style
---- ------- -------- -----
srvsql009 sql 120 blue
srvsql010 sql 121 blue
srvsql011 sql 122 blue
srvsql013 sql 124 blue
Related
In many cases an object in Powershell 5.1 can have a property that is an array. And the main issue is that it is not in the end (for example we have 2 such properties, so anyway one of them will be not in the end).
For example
(Get-Process)[0] | Format-Table Name,Threads,Handles
Name Threads Handles
---- ------- -------
Code {6212, 10164, 10804, 5260...} 238
I tried to make a normal table from that output:
(Get-Process)[0] |
Select-Object Name, #{ l = 'Threads'; e = { $_.Threads.ID -join "`n" } }, Handles |
Format-Table -Wrap
Name Threads Handles
---- ------- -------
Code 6212 238
10164
10804
5260
716
9120
6336
But as you can see it adds "additional" spaces at the array column. As I understand these spaces are the length of the array
((Get-Process)[0].Threads.ID -join "").Length
Can I eliminate these exessive spaces in the output?
Because if I have dozens of elements in array, I can't see last columns.
By the way "Out-String -Width" doesn't help either:
(Get-Process)[0] |
Select-Object Name, #{ l='Threads';e={$_.Threads.ID | Out-String -Width 12 }}, Handles |
Format-Table -Wrap
-Autosize make no difference.
And Width parameter make the situation worse:
(Get-Process)[0] |
Select-Object Name, #{ l = 'Threads'; e = { $_.threads.ID -join "`n" } }, Handles |
Format-Table -Wrap #{ e='Name'; width = 4} ,#{ e='Threads';width = 12}, Handles
Name Threads Handles
---- ------- -------
Code 6212 238
10164
10804
5260
716
9120
6336
I want to remove an array element from json array (PSObject) if value matches as follows:
$code = 12345
$myObject = #{ ArrayPair= #(#{ code = 12345; perm = "RW" }, #{ code = 23456; perm = "RW" })}
if ($true) { # $revoke
$myObject.ArrayPair = $myObject.ArrayPair | Where-Object -FilterScript {$_.code -ne $code}
}
At the start ArrayPair has 2 array elements, after executing the filter, ArrayPair is no longer an array but rather an object with two elements. How can I keep it as an array so I can continue to add new pairs to the array?
json Values before and After removal:
Before value:
{"ArrayPair": [{"perm": "RW","code": 12345},{"perm": "RW","code": 23456}]}
After Value removal
{"ArrayPair": { "perm": "RW", "code": 23456 }}
You can force the object to stay an array like this:
$code = 12345
$myObject = #{ ArrayPair= #(#{ code = 12345; perm = "RW" }, #{ code = 23456; perm = "RW" })}
[array]$myObject.ArrayPair = $myObject.ArrayPair | Where-Object -FilterScript {$_.code -ne $code}
$myObject.ArrayPair.GetType()
#Returns
#IsPublic IsSerial Name BaseType
#-------- -------- ---- --------
#True True Object[] System.Array
To add additional entries to your array you have to try it like this:
$myObject.ArrayPair += #{code = 2134; perm= "RR"}
This way you can add entries to the array and the result looks like this:
PS C:\> $myObject.ArrayPair
Name Value
---- -----
code 23456
perm RW
code 2134
perm RR
Please be aware that += doens't really add objects to the array, but instead recreates the array with new values.
If you try to add the objects via $myObject.ArrayPair.Add(#{code = 2134; perm= "RR"}) you get an error.
Please take a look at this answer for further explanations:
PowerShell Array.Add vs +=
I while deleting elements if there was just one left, I found that I had to double force the object to make sure that it remained an array type:
[array]$temp = $result.data.app.roles.admin | Where-Object -FilterScript {$_.club -ne $ClubNo}
$result.data.app.roles.admin = [array]($temp)
If you would like a complete breakdown of the script and the results I have obtained so far, you can reference my previous post.
Import the items from the pipeline in to an array
I am trying to figure out how to get only the two fields I need from the array, so I can manipulate the data. Right now the array shows the entire line as the first element in the array.
$Date = (Get-Date -format "MM-dd-yyyy")
$DateTime = (Get-Date)
$Projects = Import-Csv c:\temp\pm_project.csv
#Show me the entire list of Projects
$Projects
$TS_Entries = Get-Content "c:\temp\timesheet\$Date.txt"
#Show me all the chosen entries in the text file
$TS_Entries
#Show me only the lines in the text file that match the regex statement
$TS_Entries = Select-String -Path "C:\temp\TimeSheet\$Date.txt" -Pattern '(?>FOAH|PRJ)\d{1,10}' -allmatches | Select-Object -expand matches | Select-Object -expand Value
$TS_Entries
$TS_Entries | group -NoElement
I cannot seem to utilize the count element in the array. I need to get a value of each value in Count and multiply them by 15. The only thing I can reference in the list below is Name
Count Name
----- ----
2 FOAH278
1 FOAH519
1 FOAH704
3 FOAH718
2 FOAH780
So i'm not sure i fully understand what you are asking but here goes:
So say you have a txtfile :
C:\temp\TimeSheet\11-06-2017.txt:1:11/06/2017 18:45:56 - This 15 minutes is dedicated to PROJECT 100 FOAH18
C:\temp\TimeSheet\11-06-2017.txt:2:11/06/2017 18:45:58 - This 15 minutes is dedicated to PROJECT 90 FOAH278
C:\temp\TimeSheet\11-06-2017.txt:3:11/06/2017 18:45:59 - This 15 minutes is dedicated to PROJECT 80 FOAH313
C:\temp\TimeSheet\11-06-2017.txt:4:11/06/2017 18:46:00 - This 15 minutes is dedicated to PROJECT 70 PRJ0031905
C:\temp\TimeSheet\11-06-2017.txt:5:11/06/2017 18:46:02 - This 15 minutes is dedicated to PROJECT 60 PRJ0031909
C:\temp\TimeSheet\11-06-2017.txt:6:11/06/2017 18:46:03 - This 15 minutes is dedicated to PROJECT 50 PRJ0032045
The following script uses .NET regex class
$test = gc "C:\temp\stack.txt"
$m = [regex]::Matches($test,'(?msi)((?<=Project )\d{0,}).*?(FOAH|PRJ)(\d{1,10})')
Example of regex: https://regex101.com/r/yhgl9v/1
foreach($match in $m){
write-host "ID:" $match.Groups[1].Value
write-host "Prefix:" $match.Groups[2].Value
write-host "Number:" $match.Groups[3].Value
""
}
This will give you:
ID: 100
Prefix: FOAH
Number: 18
ID: 90
Prefix: FOAH
Number: 278
ID: 80
Prefix: FOAH
Number: 313
ID: 70
Prefix: PRJ
Number: 0031905
ID: 60
Prefix: PRJ
Number: 0031909
ID: 50
Prefix: PRJ
Number: 0032045
Is it this you are looking for?
$test = gc "C:\temp\stack.txt"
$m = [regex]::Matches($test,'(?msi)((?<=Project )\d{0,}).*?(FOAH|PRJ)(\d{1,10})')
$arr=#()
foreach($match in $m){
$arr += [PSCustomObject]#{
id = $match.Groups[1].Value
prefix = $match.Groups[2].Value
number = $match.Groups[3].Value
}
}
$arr | Export-Csv C:\temp\stock.csv -NoTypeInformation -Delimiter ';'
So you create a customobject (hashtable) that works with a value-index system.
Once you've filled up your array, you can later on (outside the loop), export it into a csv-file.
Your CSV-file will contain:
"id";"prefix";"number"
"100";"FOAH";"18"
"90";"FOAH";"278"
....
I'm having issues with the way an array loses its formatting when it is emailed and viewed in outlook 2013
The formatted array looks like this in PowerShell
vServer State Connection
------- ----- ----------
vServer-LB-1 UP 0
vServer-LB-2 DOWN 0
vServer-LB-3 UP 0
vServer-LB-4 UP 0
vServer-LB-5 UP 0
vServer-LB-6 UP 2
This is how I formatted the array (I have tried to email the unformatted array, but it is still wrong)
$formatserver = #{Expression={$_.name};Label="vServer";width=48}, `
#{Expression={$_.state};Label="State";width=17}, `
#{Expression={$_.establishedconn};Label="Connection"}
$Array = $server | Format-Table $formatserver
However, when emailed (not quite like this, but its not formatted correctly).
vServer State Connection
------- ----- ----------
vServer-LB-1 UP 0
vServer-LB-2 DOWN 0
vServer-LB-3 UP 0
vServer-LB-4 UP 0
vServer-LB-5 UP 0
vServer-LB-6 UP 2
Here is the code for emailing
$from = 'Reporting <Support#Me.com>'
$to = 'me#me.com'
$subject = 'Report'
$body = $Array | Out-String
$smtpServer = 'mail.me.com'
$msg = New-Object Net.Mail.MailMessage($from, $to, $subject, $body)
#$msg.IsBodyHTML = $true
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($msg)
Please note I have tried many combinations of | out-stringand $msg.IsBodyHTML = $true
You can use the <pre> tag in HTML to keep the spacing in your emails.
$body = $Array | Out-String | %{"<pre>"+$_+"</pre>"}
Make sure that you set IsBodyHTML as $true.
Note: Table formats a limited to the buffers of your PowerShell Shell/Console. So if your table width is more that the buffer width on your Shell/Console the table will not be shown in full.
To get round this you can set your shell buffer at the start of your script with the following:
$pshost = get-host
$pswindow = $pshost.ui.rawui
$newsize = $pswindow.buffersize
$newsize.height = 3000
$newsize.width = 1500
$pswindow.buffersize = $newsize
Or go to File >> Properties on your Shell/Console, and change the following property.
I have a .csv with a few hundred records that I need to dissect into several different files. There is a part of the code that takes an array of objects and filters the file based on the array. It works great for the part that finds things equal to whats in the array, but when I try to filter based on whats not contained in the array it ignores any version of a "not equal" operator I can find. I think it has something to do with the data type, but can't figure why it would make a difference when the equal operator works.
CSV File
"Number","Ticket","Title","Customer User","CustomerID","Accounted time","Billing"
"1","2014041710000096","Calendar issues","george.jetson","Widget, Inc","0.25","Labor",""
"2","2014041710000087","Redirected Folder permission","jane.smith","Mars Bars, Inc.","1","Labor",""
"3","2014041610000203","Completed with No Files Changed ""QB Data""","will.smith","Dr. Smith","0","Labor",""
PowerShell Code
$msaClients = #("Widget, Inc","Johns Company")
$billingList = import-csv "c:\billing\billed.csv"
$idZero = "0"
$msaArray = foreach ($msa in $msaClients) {$billingList | where-object {$_.CustomerID -eq $msa -and $_."Accounted time" -ne $idZero}}
$laborArray = foreach ($msa in $msaClients) {$billingList | where-object {$_.CustomerID -ne $msa -and $_."Accounted time" -ne $idZero}}
$msaArray | export-csv c:\billing\msa.csv -notypeinformation
$laborArray | export-csv c:\billing\labor.csv -notypeinformation
I have tried all the different logical operators for the not equal and it just seems to ignore that part. I have much more to the code if something doesn't seem right.
What am I missing, and Thanks in advance for any help!
If i understand this correct, you want the values in $msaArray, where $billingList contains customerIDs which are present in $msaClients but their corresponding Accounted time should not be eual to $idzero( 0 in this case)
PS C:\> $msaArray = ($billingList | where {(($msaclients -contains $_.customerid)) -and ($_.'accounted time' -ne $idzero)})
PS C:\> $msaArray | ft -auto
Number Ticket Title Customer User CustomerID Accounted time Billing
------ ------ ----- ------------- ---------- -------------- -------
1 2014041710000096 Calendar issues george.jetson Widget, Inc 0.25 Labor
And for $laborArray, where $billingList does not contain customerIDs which are present in $msaClients and their corresponding Accounted time should not be eual to $idzero as well( 0 in this case)
PS C:\> $laborArray = ($billingList | where {(!($msaclients -contains $_.customerid)) -and ($_.'accounted time' -ne $idZero)})
PS C:\> $laborArray | ft -auto
Number Ticket Title Customer User CustomerID Accounted time Billing
------ ------ ----- ------------- ---------- -------------- -------
2 2014041710000087 Redirected Folder permission jane.smith Mars Bars, Inc. 1 Labor
Your -ne operator is working, but you are looping too many times in $msaclients to get $laborArray.i.e, when $msa = "Widget, Inc", you got "Mars Bars, Inc." as output, but foreach loop ran again and $msa value changed to "Johns Company" and in this case you got "Mars Bars, Inc." and "Widget, Inc" as output too. Hence you ended up with three outputs.