Delete all the text from file using an array - powershell

I have a code snippet as below:
$array1=#()
foreach($datec in $datecontent) {
$dc = $datec -split '/'
$mon = $dc[0]
$day = $dc[1]
$year = $dc[2]
if($thisweekdays -contains "$mon/$day/$year"){
$datec | Add-Content "C:\Previous_Week_Latest.txt"
$array1 += $datec
}
else{
#Do Nothing
}
}
Previous_Week_Latest file contents:
8/18/2015
8/13/2015
I have another text file containing dates as shown below. I am doing so many other things and getting created this file.
8/18/2015
8/13/2015
8/07/2015
7/31/2015
7/23/2015
I don't want those dates which are in the array, since I need to do some more operations with this text file. Basically what I need to achieve is that whatever there in the $array1 finally, I need to delete those from the text file. Something like this:
Get-Content "C:\split_weeks_temp.txt" | Where {$_ -match "$array1"} | Set-Content "C:\split_weeks.txt"
Can someone please help me at this?

I will assume that $array1 contains the properly formatted data just like you show in your example.
8/18/2015
8/13/2015
And that you just need to filter the contents of the other file where it will omit those dates in $array1. I am still investigating but you using -match in this way is the problem. Since it is an array you could just use -notin or -notcontains.
If you just have PowerShell 2.0
Where {$array1 -notcontains $_}
Or easier to undersand with PowerShell 3.0
Where {$_ -notin $array1}
I am still trying to figure out the issue with your current logic. You don't really explain what is wrong with your example.
Actually...
Perhaps there is trailing spaces in the date strings? I think that has something to do with it since you have spaces after all the dates you have posted in the question that are part of the "file".

Related

How to store an array of hashtables in a text file and then call all of the values for a given key in each hashtable

I am using a text file as the backend for an application that I am developing. I first started off leaving the text file in a human-readable format but I decided that there was no sense in that figured it would be best to leave out formatting.
Where I am now in the backend dev process is creating a single-line hashtable with identical keys but different values for each entry. Seems logical and easy to work with.
Here is a mock-up of the entries in the text file:
#{'bName'='1xx'; 'bTotal'='1yy'; 'bSet'='1zz'}
#{'bName'='2xx'; 'bTotal'='2yy'; 'bSet'='2zz'}
#{'bName'='3xx'; 'bTotal'='3yy'; 'bSet'='3zz'}
As you can see, the keys for each entry are identical, however, the values are going to be different. (The numerical and repetitious nature of the values are purely coincidental and put in place for the sake of a mock-up. Actual values will not be numerically-oriented and won't be repetitious as seen in the example.)
I am able to access keys and values by typing:
$hash = Get-Content .\Desktop\Test.txt | Out-String | iex
which outputs:
Name Value
---- -----
bName 1xx
bTotal 1yy
bSet 1zz
bName 2xx
bTotal 2yy
bSet 2zz
bName 3xx
bTotal 3yy
bSet 3zz
What I ultimately want to do is gather each of the values for bName, bTotal, and bSet so that I can append each to a separate WinForms ComboBox. The WinForms part will be simple, I am just having a bit of an issue with getting the values from each hashtable in the text file.
I tried:
$hash.Values | ?{$hash.Keys -contains 'bName'}
but it just prints out every $hash.Value regardless of the $hash.Key match given in the pipe.
I understand that $hash is an array and I figured I may have to pipe out each iteration in a foreach ($hash | %{}) loop but I'm not quite sure the correct way to do this. For example, when I try:
$hash | $_.Keys
or
$hash | $_.Values
it isn't treating each iteration like a hashtable.
What am I doing wrong here? Am I going about it in a convoluted way while there is a much easier way to accomplish this? I am open to all sorts of ideas or suggestions.
As an afterthought: It is kind of funny how often an obvious solution presents itself when you step away and divert your attention towards something else.
I went to grab lunch and I can't, for the life of me, begin to comprehend why I didn't realize that I could just very easily do this:
$hash.bName
or:
$hash.bTotal
or:
$hash.bSet
That will do exact as I was wanting to do. However, considering the answers provided, I may go a different route in terms of using an .ini file in CSV format rather than creating an array of hashtables.
One way of storing hashtables in a text file is the INI format.
[hashtable1]
bName=1xx
bTotal=1yy
bSet=1zz
[hashtable2]
bName=2xx
bTotal=2yy
bSet=2zz
[hashtable3]
bName=3xx
bTotal=3yy
bSet=3zz
INI files are basically a hashtable of hashtables in text form. They can be read like this:
$ht = #{}
Get-Content 'C:\path\to\hashtables.txt' | ForEach-Object {
$_.Trim()
} | Where-Object {
$_ -notmatch '^(;|$)'
} | ForEach-Object {
if ($_ -match '^\[.*\]$') {
$section = $_ -replace '\[|\]'
$ht[$section] = #{}
} else {
$key, $value = $_ -split '\s*=\s*', 2
$ht[$section][$key] = $value
}
}
and written like this:
$ht.Keys | ForEach-Object {
'[{0}]' -f $_
foreach ($key in $ht[$_].Keys) {
'{0}={1}' -f $key, $ht[$_][$key]
}
} | Set-Content 'C:\path\to\hashtables.txt'
Individual values in such a hashtable of hashtables can be accessed like this:
$ht['section']['key']
or like this:
$ht.section.key
Another option would be to store each hashtable in a separate file
hashtable1.txt:
bName=1xx
bTotal=1yy
bSet=1zz
hashtable2.txt.
bName=2xx
bTotal=2yy
bSet=2zz
hashtable3.txt:
bName=3xx
bTotal=3yy
bSet=3zz
That would allow you to import each file into a hashtable via ConvertFrom-StringData:
$ht1 = Get-Content 'C:\path\to\hashtable1.txt' | Out-String |
ConvertFrom-Stringdata
Writing the files would basically be the same as above (there is no ConverTo-StringData cmdlet):
$ht1.Keys | ForEach-Object {
'{0}={1}' -f $_, $ht[$_]
} | Set-Content 'C:\path\to\hashtables1.txt'
PowerShell has built in csv handling so it makes it a good choice to use in this case. So, assuming you had your data stored in a file in the standard csv format with headers:
"bName","bTotal","bSet"
"1xx","1yy","1zz"
"2xx","2yy","2zz"
"3xx","3yy","3zz"
Then you import your data like this:
$data = Import-Csv $path
Now you have an array of PsCustomObject and each header in the csv file is a property of the object. So if, for example, you wanted to get the bTotal of the second object you would do the following:
$data[1].bTotal
2yy

Parsing imported CSV

I am trying to parse a .csv file using the Import-CSV commandlet as shown below:
$lease_import = ipcsv -Path 'C:\leases.csv'-Delimiter "," | where {
($_.binding_state -ne "ABANDONED") -and ($_.mac_address -ne "") -and (($_.ends -replace "T"," " )-match "2014")
}
A general 'ends' field in this CSV looks like this: 2014-01-23T13:49:38.000Z. I want to replace the 'T' with a space and I want to replace .000Z with an empty string. Finally, the dashes would have to get replaced by a /. End result would have to be something along the lines of this:
2014/01/23 13:49:38
I tried starting simple by using -replace to change the "T" to a space following this link: http://blogs.technet.com/b/heyscriptingguy/archive/2011/03/21/use-powershell-to-replace-text-in-strings.aspx. However, this doesn't work for me.
Am I trying to do too much at once?
There could be more elegant solutions by trying to parse the DateTime out of the string but a very simple one would be
("2014-01-23T13:49:38.000Z".TrimEnd(".000Z") -Replace "T"," ") -replace "-","/"
which would return
2014/01/23 13:49:38
In your loop this would look like
($_.ends.TrimEnd(".000Z") -Replace "T"," ") -replace "-","/"
In place of .TrimEnd() you could just do another Replace but since TrimEnd is there to remove trailing characters why not use it.
I did try to use something like [datetime]::ParseExact but they need to have clean strings with not extra data else you get parsing errors. You can clean the string like we have with the -replace's but then it becomes redundant to use the function. Someone else might have a cleaner approach

Change specific part of a string

I've got a .txt-File with some text in it:
Property;Value
PKG_GUID;"939de9ec-c9ac-4e03-8bef-7b7ab99bff74"
PKG_NAME;"WinBasics"
PKG_RELATED_TICKET;""
PKG_CUSTOMER_DNS_SERVERS;"12314.1231
PKG_CUSTOMER_SEARCH_DOMAINS;"ms.com"
PKG_JOIN_EXISTING_DOMAIN;"True"
PKG_DOMAINJOIN_DOMAIN;"ms.com"
PKG_DOMAINJOIN_USER;"mdoe"
PKG_DOMAINJOIN_PASSWD;"*******"
So now, is there a way to replace those *'s with e.g. numbers or sth. ?
If so, may you tell me how to do it?
Much like Rahul I would use RegEx as well. Considering the application I'd run Get-Content through a ForEach loop, and replace text as needed on a line-by-line basis.
Get-Content C:\Path\To\File.txt | ForEach{$_ -replace "(PKG_DOMAINJOIN_PASSWD;`")([^`"]+?)(`")", "`${1}12345678`$3"}
That would output:
Property;Value
PKG_GUID;"939de9ec-c9ac-4e03-8bef-7b7ab99bff74"
PKG_NAME;"WinBasics"
PKG_RELATED_TICKET;""
PKG_CUSTOMER_DNS_SERVERS;"12314.1231
PKG_CUSTOMER_SEARCH_DOMAINS;"ms.com"
PKG_JOIN_EXISTING_DOMAIN;"True"
PKG_DOMAINJOIN_DOMAIN;"ms.com"
PKG_DOMAINJOIN_USER;"mdoe"
PKG_DOMAINJOIN_PASSWD;"12345678"
On second thought, I don't know if I'd do that. I might import it as a CSV, update the property, and export the CSV again.
Import-CSV C:\Path\To\File.txt -Delimiter ";" |%{if($_.Property -eq "PKG_DOMAINJOIN_PASSWD"){$_.value = "12345678";$_}else{$_}|export-csv c:\path\to\newfile.txt -delimiter ";" -notype
If You are using Powershell V2.0 (Hopefully) you can try something like below. gc is short hand for get-content commandlet.
(gc D:\SO_Test\test.txt) -replace '\*+','12345678'
With this the resultant data would be as below (notice the last line)
Property;Value
PKG_GUID;"939de9ec-c9ac-4e03-8bef-7b7ab99bff74"
<Rest of the lines here>
PKG_DOMAINJOIN_USER;"mdoe"
PKG_DOMAINJOIN_PASSWD;"12345678" <-- Notice here; *'s changed to numbers
Rahul's answer was good, I just wanted to mention that *+ will replace all instances of a single * character or more, so it would match any other place there is at least one star. If what you posted is all you would ever expect for you sample data though this would be fine.
You could alter the regex match to make it more specific if it was needed by changing it to something like
\*{3,0}
which would match 3 or more stars, or very specific would be
(?<=")\*{3,}(?=")
which would replace 3 or more stars which are surrounded by double quotes.
Here's a function that uses regex lookahead and lookbehind zero-length assertions to replace named parameters in a string similar to your example:
function replace-x( $string, $name, $value ) {
$regex = "(?<=$([regex]::Escape($name));`").*(?=`")"
$string -replace $regex, $value
}
Its reusable for different settings in your file, e.g:
$settings = get-content $filename
$settings = replace-x $settings PKG_DOMAINJOIN_USER foo
$settings = replace-x $settings PKG_DOMAINJOIN_PASSWD bar

Read a Csv file with powershell and capture corresponding data

Using PowerShell I would like to capture user input, compare the input to data in a comma delimited CSV file and write corresponding data to a variable.
Example:
A user is prompted for a “Store_Number”, they enter "10".
The input, “10” is then compared to the data in the first position
or column of the CSV file.
Data, such as “District_Number” in the corresponding position /
column is captured and written to a variable.
I have gotten this method to work with an Excel file (.xlsx) but have found it to be terribly slow. Hoping that PowerShell can read a CSV file more efficiently.
Link to an example CSV file here:
Store_Number,Region,District,NO_of_Devices,Go_Live_Date
1,2,230,10,2/21/2013
2,2,230,10,2/25/2013
3,2,260,12,3/8/2013
4,2,230,10,3/4/2013
5,2,260,10,3/4/2013
6,2,260,10,3/11/2013
7,2,230,10,2/25/2013
8,2,230,10,3/4/2013
9,2,260,10,5/1/2013
10,6,630,10,5/23/2013
What you should be looking at is Import-Csv
Once you import the CSV you can use the column header as the variable.
Example CSV:
Name | Phone Number | Email
Elvis | 867.5309 | Elvis#Geocities.com
Sammy | 555.1234 | SamSosa#Hotmail.com
Now we will import the CSV, and loop through the list to add to an array. We can then compare the value input to the array:
$Name = #()
$Phone = #()
Import-Csv H:\Programs\scripts\SomeText.csv |`
ForEach-Object {
$Name += $_.Name
$Phone += $_."Phone Number"
}
$inputNumber = Read-Host -Prompt "Phone Number"
if ($Phone -contains $inputNumber)
{
Write-Host "Customer Exists!"
$Where = [array]::IndexOf($Phone, $inputNumber)
Write-Host "Customer Name: " $Name[$Where]
}
And here is the output:
Old topic, but never clearly answered. I've been working on similar as well, and found the solution:
The pipe (|) in this code sample from Austin isn't the delimiter, but to pipe the ForEach-Object, so if you want to use it as delimiter, you need to do this:
Import-Csv H:\Programs\scripts\SomeText.csv -delimiter "|" |`
ForEach-Object {
$Name += $_.Name
$Phone += $_."Phone Number"
}
Spent a good 15 minutes on this myself before I understood what was going on. Hope the answer helps the next person reading this avoid the wasted minutes!
(Sorry for expanding on your comment Austin)
So I figured out what is wrong with this statement:
Import-Csv H:\Programs\scripts\SomeText.csv |`
(Original)
Import-Csv H:\Programs\scripts\SomeText.csv -Delimiter "|"
(Proposed, You must use quotations; otherwise, it will not work and ISE will give you an error)
It requires the -Delimiter "|", in order for the variable to be populated with an array of items. Otherwise, Powershell ISE does not display the list of items.
I cannot say that I would recommend the | operator, since it is used to pipe cmdlets into one another.
I still cannot get the if statement to return true and output the values entered via the prompt.
If anyone else can help, it would be great. I still appreciate the post, it has been very helpful!

Issue trying filter within Powershell

I am finishing a last piece of this mini-app where I'm pulling names from a text file. When pulling the names from a ..txt I am filtering out certain prefixes like *eft, *nsm with code like below.
$lines = (Get-Content C:\temp\PROD\Repeat.txt -totalcount 200)
$flines = $lines|?{$_ -notlike "*eft", "nsm*", "*" , "*" .... }
$objOutputBox.Text = $flines
The problem I'm having is that it is only grabbing the "*eft" and not the rest of them. I thought I could filter an array of strings with this structure? What am I missing here if you do not mind?
Thanks
You cannot apply -notlike like this. You'll have to use the operator multiple times:
-notlike '*eft' -notlike 'nsm*' ...
But a better way would probably be a regular expression:
-notmatch 'eft$|^nsm|...'