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
Related
I have a text file with lines in this format:
FirstName,LastName,SSN,$x.xx,$x.xx,$x.xx
FirstName,MiddleInitial,LastName,SSN,$x.xx,$x.xx,$x.xx
The lines could be in either format. For example:
Joe,Smith,123-45-6789,$150.00,$150.00,$0.00
Jane,F,Doe,987-65-4321,$250.00,$500.00,$0.00
I want to basically turn everything before the SSN into a single field for the name thus:
Joe Smith,123-45-6789,$150.00,$150.00,$0.00
Jane F Doe,987-65-4321,$250.00,$500.00,$0.00
How can I do this using PowerShell? I think I need to use ForEach-Object and at some point replace "," with " ", but I don't know how to specify the pattern. I also don't know how to use a ForEach-Object with a $_.Where so that I can specify the "SkipUntil" mode.
Thanks very much!
Mathias is correct; you want to use the -replace operator, which uses regular expressions. I think this will do what you want:
$string -replace ',(?=.*,\d{3}-\d{2}-\d{4})',' '
The regular expression uses a lookahead (?=) to look for any commas that are followed by any number of any character (. is any character, * is any number of them including 0) that are then followed by a comma immediately followed by a SSN (\d{3}-\d{2}-\d{4}). The concept of "zero-width assertions", such as this lookahead, simply means that it is used to determine the match, but it not actually returned as part of the match.
That's how we're able to match only the commas in the names themselves, and then replace them with a space.
I know it's answered, and neatly so, but I tried to come up with an alternative to using a regex - count the number of commas in a line, then replace either the first one, or the first two, commas in the line.
But strings can't count how many times a character appears in them without using the regex engine(*), and replacements can't be done a specific number of times without using the regex engine(**), so it's not very neat:
$comma = [regex]","
Get-Content data.csv | ForEach {
$numOfCommasToReplace = $comma.Matches($_).Count - 4
$comma.Replace($_, ' ', $numOfCommasToReplace)
} | Out-File data2.csv
Avoiding the regex engine entirely, just for fun, gets me things like this:
Get-Content .\data.csv | ForEach {
$1,$2,$3,$4,$5,$6,$7 = $_ -split ','
if ($7) {"$1 $2 $3,$4,$5,$6,$7"} else {"$1 $2,$3,$4,$5,$6"}
} | Out-File data2.csv
(*) ($line -as [char[]] -eq ',').Count
(**) while ( #counting ) { # split/mangle/join }
It certainly seemed like a simple enough task but for whatever reason this doesn't work:
#Verifies that the firefox proxy setting have been applied
#locate Prefsjs file
$PrefsFiles = Get-Item -Path ($env:SystemDrive+"\Users\*\AppData\Roaming\Mozilla\Firefox\Profiles\*\prefs.js")
#read in Prefsjs
$Prefsjs = (Get-Content $PrefsFiles)
#Block to compare
$Update= #"
user_pref("network.proxy.http", "0.0.0.0");
user_pref("network.proxy.http_port", 80);
"#
($Prefsjs -contains $Update)
The last line should return a true because the text actually does exist in $Prefsjs... Any ideas?
It's not going to match because you're comparing a multi-line string to an array of single line strings.
You need to compare like objects, which means $Prefsjs also needs to be a single, multi-line string. The easiest way to do that is to add the -Raw switch to your Get-Content:
#read in Prefsjs
$Prefsjs = (Get-Content $PrefsFiles -Raw)
But now $Prefsjs is not an array any more, so you can't use -Contains. It's now just a single string, so you can use the string contains() method to accomplish the same thing:
$Prefsjs.contains($Update)
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".
I have a path inside a txt file that needs to be manipulated, something like:
C:\Jenkins\Automation\Blah\Foo\Bar\646433\Schema\test\473289_12321.ps1
C:\Jenkins\Automation\Blah\Foo\Bar\2112\Schema\QA\473289_123211.ps1
I want to replace everything before the 7th backslash and then replace it with C:\Question. I was doing something similar in Powershell via:
(Get-Content $FullEnvSQLFilePath) | #get the content
Foreach-Object {$_ -replace [Regex]::Escape($StringToReplace), "$StringReplaceValue"} | #look for the string and replace
This worked fine when I knew what the exact verbiage was to look for. We now don't know that but we will want to remove everything before the 7th backslash and replace it with a value. Reverse order works fine too. I wasn't able to have much luck in Powershell via substring doing this. Thanks.
One option:
$text =
'C:\Jenkins\Automation\Blah\Foo\Bar\646433\Schema\test\473289_12321.ps1',
'C:\Jenkins\Automation\Blah\Foo\Bar\2112\Schema\QA\473289_123211.ps1'
$text | foreach {'C:\Question\{0}' -f $_.split('\',8)[-1]}
C:\Question\Schema\test\473289_12321.ps1
C:\Question\Schema\QA\473289_123211.ps1
this ([^\\]*\\){7} regex looks 7 times for a capture group ending on a backslash and replaces it.
UPDATED: .:\\([^\\]*\\){6} regex looks for strings that look like paths starting at any root drive .:\ followed by 6 times a capture group ending on a backslash based on your comment
$text = #"
C:\Jenkins\Automation\Blah\Foo\Bar\646433\Schema\test\473289_12321.ps1
C:\Jenkins\Automation\Blah\Foo\Bar\2112\Schema\QA\473289_123211.ps1
PRINT C:\Jenkins\Automation\Blah\Foo\Baz\2112\Schema\QA\473289_123212.ps1
C:\Jenkins\Automation\Blah\Foo\quux\2112\Schema\QA\473289_123213.ps1
"#
#depending on how you get the text (single string or array)
#$text.Split("`n") | % { $_ -Replace '.:\\([^\\]*\\){6}','C:\Example\' }
$text -Replace ".:\\([^\\`n]*\\){6}","C:\Example\"
Result:
C:\Example\Schema\test\473289_12321.ps1
C:\Example\Schema\QA\473289_123211.ps1
PRINT C:\Example\Schema\QA\473289_123212.ps1
C:\Example\Schema\QA\473289_123213.ps1
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