I am parsing a bunch of data in a textfile. I get the data with Get-Content.
Then I loop through each row in $data. Split each row on a space and load those values into an array.
I then loop through each $string in the array.
If the $string matches a specific value I want to delete it out of the array.
$index.Delete(), $index.Remove() does not work, Here is what I have.
$data = Get-Content "C:\Users\$userName\Desktop\test-data.txt"
foreach($row in $data){
if($row)
{
[Array]$index = $row.Split(" ")
$i = 0
foreach($string in $index){
Write-Host $string
if($string -eq "value1" -or $string -eq "value2" -or $string -eq "value3")
{
$index.Delete() //This does not work.
}
}
I have also tried something like this as well but it just was not working out at all.
for($i -eq $index.length; $i -le 0; $i++)
{
Write-Host $index[$i] #this would hit once then give me an error saying the value is null
if($index[$i] -eq "value1" -or $index[$i] -eq "value2" -or $index[$i] -eq "value3")
{
$index.Remove() #does not hit here at all/nor will it work.
Write-Host $index
}
}
How do I remove something from the $index array..?
Is there a better way to do this?
Any help would be much appreciated, thanks.
The easiest way would be to chain -ne operators:
[Array]$index = $row.Split(" ") -ne $value1 -ne $value2 -ne $value3
Each one will remove all the elements of the array that match the value in the variable, and the result will be passed on to the next. When it's finished, the array will contain the elements the didn't match any of the $value variables.
Try this:
[array]$index = $row.Split(" ",[stringSplitOptions]::RemoveEmptyEntries) -notmatch "\b(?:$value1|$value2|$value3)\b"
Related
I have to check for multiple array entries in an if statement.
if (($Right.IdentityReference -eq $User) -or ($Right.IdentityReference -eq ("Domain\" + $GroupArrayList[0])) -or ($Right.IdentityReference -eq ("Domain\" + $GroupArrayList[1])))
This will continue with $GroupArrayList[2], $GroupArrayList[3], ...
Is there any way how I can go trough every entry of the array? I can't write every position down because the array size is dynamic. How can I create such a loop?
You can use a Foreach
Foreach ($ArrayItem in $GroupArrayList) {
if (($Right.IdentityReference -eq $User) -or ($Right.IdentityReference -eq ("Domain\" + $ArrayItem))) {
# Do stuff
}
}
The variable $ArrayItem will refer to your $GroupArrayList[2], $GroupArrayList[3],...
I don't think you even need a loop for that, but instead use the -contains operator like this:
if (($Right.IdentityReference -eq $User) -or ($GroupArrayList -contains ($Right.IdentityReference -replace '^Domain\\',''))
You simply strip off the Domain\ from the $Right.IdentityReference and see if the string that remains can be found in the $GroupArrayList array.
As you're ORing the comparison's why not testing if -in array?
if ($Right.IdentityReference -in
$User,
("Domain\" + $GroupArrayList[0]),
("Domain\" + $GroupArrayList[1]) ) {
I have a text file domains.txt
$domains = ‘c:\domains.txt’
$list = Get-Content $domains
google.com
google.js
and an array
$array = #(".php",".zip",".html",".htm",".js",".png",".ico",".0",".jpg")
anything in $domain that ends in something in #arr should NOT be in my final list
So google.com would be in final list but google.js would not.
I found some other stackoverflow code that give me the exact opposite of what I'm looking for but, hah I can't get it reversed!!!!
This gives me the exact opposite of what I want, how do I reverse it?
$domains = ‘c:\domains.txt’
$list = Get-Content $domains
$array = #(".php",".zip",".html",".htm",".js",".png",".ico",".0",".jpg")
$found = #{}
$list | % {
$line = $_
foreach ($item in $array) {
if ($line -match $item) { $found[$line] = $true }
}
}
$found.Keys | write-host
this gives me google.js I need it to give me google.com.
I've tried -notmatch etc and can't get it to reverse.
Thanks in advance and the more explanation the better!
Take the .s off, mash the items together into a regex OR, tag on an end-of-string anchor, and filter the domains against it.
$array = #("php","zip","html","htm","js","png","ico","0","jpg")
# build a regex of
# .(php|zip|html|htm|...)$
# and filter the list with it
$list -notmatch "\.($($array -join '|'))`$"
Anyway, the simple way to invert your result is to walk through $found.keys | where { $_ -notin $list }. Or to change your test to $line -notmatch $item.
But beware that you are doing a regex match and something like top500.org would match .0 and throw your results out. If you need to match at the end specifically, you need to use something like $line.EndsWith($item).
other solution
$array = #(".php",".zip",".html",".htm",".js",".png",".ico",".0",".jpg")
get-content C:\domains.txt | where {[System.IO.Path]::GetExtension($_) -notin $array}
I'm evolving my Surveillance script, so i can choose a Service/Maintenance Window. Where all errors are ignored between two time intervals.
This is what i got:
Add-Type -TypeDefinition #"
public struct ServiceWindow
{
public int SWStart;
public int SWEnd;
}
"#
[array]$SWArray = New-Object ServiceWindow
$time = Get-Date -Format HHMM
$time
$ActiveBatchVar = "1000-1005;1306-1345;2300-2305"
$ActiveBatchVar = $ActiveBatchVar.Split(";")
For ($i = 0; $i -lt $ActiveBatchVar.Length; $i++)
{
$tempSW = New-Object ServiceWindow
$tempSW.SWStart = $ActiveBatchVar[$i].Split("-")[0]
$tempSW.SWEnd = $ActiveBatchVar[$i].Split("-")[1]
If ($i -eq 0) { $SWArray = $tempSW } else { $SWArray += $tempSW }
}
Write-Host Complete array...
$SWArray
ForEach-Object ($SWArray) {
Get-Date -Format HHMM
If ($time -ge $_.SWStart -and $time -lt $_.SWEnd) {Write-Host Wohoo we have hit a service window service window...}
}
I get an error in my last ForEach-Object loop. and can't figure out what is wrong.
The point is that I would like to check if the current time is between two given times, like "1000-1005".
Anyone got a clue what’s missing, or maybe a way to simplify the whole thing ;)
Ok, a few things here... You really seem to like the Split() method. You may want to look into some alternatives, like this:
$ActiveBatchVar = #(#("1000","1005"),#("1306","1345"),#("2300","2305"))
See what we did there? It's an array of arrays. #() is the array notation. So I have an array, with 3 arrays in it.
I'm not real familliar with structs, but I am familliar with custom objects, so I would use that if it were me. Then you could do something like:
$SWArray = #() #That's an empty array, we'll add things to it now that it exists
ForEach ($Batch in $ActiveBatchVar){
$SWArray += New-Object PSObject -Property #{
SWStart = $Batch[0]
SWEnd = $Batch[1]
}
}
So then we change the last bit so that you are assigning $time just before your next loop to keep it as accurate as possible, and correct the ForEach just a little and the whole thing would look like this:
$ActiveBatchVar = #(#("1000","1005"),#("1306","1345"),#("2300","2305"))
$SWArray = #()
ForEach ($Batch in $ActiveBatchVar){
$SWArray += New-Object PSObject -Property #{
SWStart = $Batch[0]
SWEnd = $Batch[1]
}
}
Write-Host Complete array...
$SWArray
$time = date -f HHmm
ForEach($SW in $SWArray) {
If ($time -ge $SW.SWStart -and $time -lt $SW.SWEnd) {
Write-Host "Wohoo we have hit a service window service window..."
}
}
Minimum changes:
ForEach-Object ($SWArray) {
to
$SWArray | % {
Also your last Write-Host should enclose the message in quoes ie
{Write-Host "Wohoo..."}
ForEach-Object ($SWArray) {}
This is the wrong syntax, you should use the keyword in
Foreach-Object ($array in $SWArray) {}
if you have a small array...
($SWArray).foreach({
Get-Date -Format HHMM
If ($time -ge $_.SWStart -and $time -lt $_.SWEnd)
{Write-Host Wohoo we have hit a service window service window...}
})
I'm populating an array variable $array at some point in my code, for example like below
this
is
an
array
varaible
What if, I wanted to print out the array variable like thisisanarrayvariable as one liner
i took the below approach, but i'am not getting any out while the program is hanging
for ($i=0;$i -le $array.length; $i++)
{ $array[$i] }
obviuosly, i dont want to glue them together like $array[0]+$array[1]+$array[2]..
Hope i can get a better answer.
Joining array elements with no separator
Use the -join operator...
$array -join ''
...or the static String.Join method...
[String]::Join('', $array)
...or the static String.Concat method...
[String]::Concat($array)
For all of the above the result will be a new [String] instance with each element in $array concatenated together.
Fixing the for loop
Your for loop will output each element of $array individually, which will be rendered on separate lines. To fix this you can use Write-Host to write to the console, passing -NoNewline to keep the output of each iteration all on one line...
for ($i = 0; $i -lt $array.Length; $i++)
{
Write-Host -NoNewline $array[$i]
}
Write-Host
The additional invocation of Write-Host moves to a new line after the last array element is output.
If it's not console output but a new [String] instance you want you can concatenate the elements yourself in a loop...
$result = ''
for ($i = 0; $i -lt $array.Length; $i++)
{
$result += $array[$i]
}
The += operator will produce a new intermediate [String] instance for each iteration of the loop where $array[$i] is neither $null nor empty, so a [StringBuilder] is more efficient, especially if $array.Length is large...
$initialCapacity = [Int32] ($array | Measure-Object -Property 'Length' -Sum).Sum
$resultBuilder = New-Object -TypeName 'System.Text.StringBuilder' -ArgumentList $initialCapacity
for ($i = 0; $i -lt $array.Length; $i++)
{
$resultBuilder.Append($array[$i]) | Out-Null # Suppress [StringBuilder] method returning itself
}
$result = $resultBuilder.ToString()
Just use
-join $array
which will glue all elements together.
I'm using Powershell 1.0 to remove an item from an Array. Here's my script:
param (
[string]$backupDir = $(throw "Please supply the directory to housekeep"),
[int]$maxAge = 30,
[switch]$NoRecurse,
[switch]$KeepDirectories
)
$days = $maxAge * -1
# do not delete directories with these values in the path
$exclusionList = Get-Content HousekeepBackupsExclusions.txt
if ($NoRecurse)
{
$filesToDelete = Get-ChildItem $backupDir | where-object {$_.PsIsContainer -ne $true -and $_.LastWriteTime -lt $(Get-Date).AddDays($days)}
}
else
{
$filesToDelete = Get-ChildItem $backupDir -Recurse | where-object {$_.PsIsContainer -ne $true -and $_.LastWriteTime -lt $(Get-Date).AddDays($days)}
}
foreach ($file in $filesToDelete)
{
# remove the file from the deleted list if it's an exclusion
foreach ($exclusion in $exclusionList)
{
"Testing to see if $exclusion is in " + $file.FullName
if ($file.FullName.Contains($exclusion)) {$filesToDelete.Remove($file); "FOUND ONE!"}
}
}
I realize that Get-ChildItem in powershell returns a System.Array type. I therefore get this error when trying to use the Remove method:
Method invocation failed because [System.Object[]] doesn't contain a method named 'Remove'.
What I'd like to do is convert $filesToDelete to an ArrayList and then remove items using ArrayList.Remove. Is this a good idea or should I directly manipulate $filesToDelete as a System.Array in some way?
Thanks
The best way to do this is to use Where-Object to perform the filtering and use the returned array.
You can also use #splat to pass multiple parameters to a command (new in V2). If you cannot upgrade (and you should if at all possible, then just collect the output from Get-ChildItems (only repeating that one CmdLet) and do all the filtering in common code).
The working part of your script becomes:
$moreArgs = #{}
if (-not $NoRecurse) {
$moreArgs["Recurse"] = $true
}
$filesToDelete = Get-ChildItem $BackupDir #moreArgs |
where-object {-not $_.PsIsContainer -and
$_.LastWriteTime -lt $(Get-Date).AddDays($days) -and
-not $_.FullName.Contains($exclusion)}
In PSH arrays are immutable, you cannot modify them, but it very easy to create a new one (operators like += on arrays actually create a new array and return that).
I agree with Richard, that Where-Object should be used here. However, it's harder to read.
What I would propose:
# get $filesToDelete and #exclusionList. In V2 use splatting as proposed by Richard.
$res = $filesToDelete | % {
$file = $_
$isExcluded = ($exclusionList | % { $file.FullName.Contains($_) } )
if (!$isExcluded) {
$file
}
}
#the files are in $res
Also note that generally it is not possible to iterate over a collection and change it. You would get an exception.
$a = New-Object System.Collections.ArrayList
$a.AddRange((1,2,3))
foreach($item in $a) { $a.Add($item*$item) }
An error occurred while enumerating through a collection:
At line:1 char:8
+ foreach <<<< ($item in $a) { $a.Add($item*$item) }
+ CategoryInfo : InvalidOperation: (System.Collecti...numeratorSimple:ArrayListEnumeratorSimple) [], RuntimeException
+ FullyQualifiedErrorId : BadEnumeration
This is ancient. But, I wrote these a while ago to add and remove from powershell lists using recursion. It leverages the ability of powershell to do multiple assignment . That is, you can do $a,$b,$c=#('a','b','c') to assign a b and c to their variables. Doing $a,$b=#('a','b','c') assigns 'a' to $a and #('b','c') to $b.
First is by item value. It'll remove the first occurrence.
function Remove-ItemFromList ($Item,[array]$List(throw"the item $item was not in the list"),[array]$chckd_list=#())
{
if ($list.length -lt 1 ) { throw "the item $item was not in the list" }
$check_item,$temp_list=$list
if ($check_item -eq $item )
{
$chckd_list+=$temp_list
return $chckd_list
}
else
{
$chckd_list+=$check_item
return (Remove-ItemFromList -item $item -chckd_list $chckd_list -list $temp_list )
}
}
This one removes by index. You can probably mess it up good by passing a value to count in the initial call.
function Remove-IndexFromList ([int]$Index,[array]$List,[array]$chckd_list=#(),[int]$count=0)
{
if (($list.length+$count-1) -lt $index )
{ throw "the index is out of range" }
$check_item,$temp_list=$list
if ($count -eq $index)
{
$chckd_list+=$temp_list
return $chckd_list
}
else
{
$chckd_list+=$check_item
return (Remove-IndexFromList -count ($count + 1) -index $index -chckd_list $chckd_list -list $temp_list )
}
}
This is a very old question, but the problem is still valid, but none of the answers fit my scenario, so I will suggest another solution.
I my case, I read in an xml configuration file and I want to remove an element from an array.
[xml]$content = get-content $file
$element = $content.PathToArray | Where-Object {$_.name -eq "ElementToRemove" }
$element.ParentNode.RemoveChild($element)
This is very simple and gets the job done.