parse multilines from a file and replace - parsing

I need to read a file where the content is like below :
Computer Location = afp.local/EANG
Description = RED_TXT
Device Name = EANG04W
Domain Name = afp.local
Full Name = Admintech
Hardware Monitoring Type = ASIC2
Last Blocked Application Scan Date = 1420558125
Last Custom Definition Scan Date = 1348087114
Last Hardware Scan Date = 1420533869
Last Policy Sync Date = 1420533623
Last Software Scan Date = 1420533924
Last Update Scan Date = 1420558125
Last Vulnerability Scan Date = 1420558125
LDAP Location = **CN=EANG04W**,OU=EANG,DC=afp,DC=local
Login Name = ADMINTECH
Main Board OEM Name = Dell Inc.
Number of Files = 384091
Primary Owner = **CN= LOUHICHI anoir**,OU=EANG,DC=afp,DC=localenter code here
I need to replace CN=$value by CN=Compagny where $value is what is retrived after CN= and before ,.

Ok, so you really should have updated your question an not posted the code in a comment, because it's really hard to read. Here's what I think you intended:
$file = 'D:\sources\scripts\2.txt'
$content = Get-Content $file | foreach ($line in $content) {
if ($line.Contains('CN=')) {
$variable = $line.Split(',').Split('=')[2]
$variable1 = $variable -replace $variable, "Compagny"
} Set-Content -path $file
}
That deffinately has some syntax errors. The first line is great, you define the path. Then things go wrong... Your call to Get-Content is fine, that will get the contents of the file, and send them down the pipe.
You pipe that directly into a ForEach loop, but it's the wrong kind. What you really want there is a ForEach-Object loop (which can be confusing, because it can be shortened to just ForEach when used in a pipeline like this). The ForEach-Object loop does not declare an internal variable (such as ($line in $content)) and instead the scriptblock uses the automatic variable $_. So your loop needs to become something like:
Get-Content $file | ForEach { <do stuff> } | Set-Content
Next let's look inside that loop. You use an If statement to see if the line contains "CN=", understandable, and functional. If it does you then split the line on commas, and then again on equals, selecting the second record. Hm, you create an array of strings anytime you split one, and you have split a string twice, but only specify which record of the array you want to work with for the second split. That could be a problem. Anyway, you assign that substring to $variable, and proceed to replace that whole thing with "company" and store that output to $variable1. So there's a couple issues here. Once you split the string on the commas you have the following array of strings:
"LDAP Location = **CN=EANG04W**"
"OU=EANG"
"DC=afp"
"DC=local"
That's an array with 4 string objects. So then you try to split at least one of those (because you don't specify which one) on the equals sign. You now have an array with 4 array objects, where each of those has 2 string objects:
("LDAP Location", "**CN", "EANG04W**")
("OU", "EANG")
("DC","afp")
("DC","local")
You do specify the third record at this point (arrays in PowerShell start at record 0, so [2] specifies the third record). But you didn't specify which record in the first array so it's just going to throw errors. Let's say that you actually selected what you really wanted though, and I'm guessing that would be "EANG04W". (by the way, that would be $_.Split(",")[0].Split("=")[1]). You then assign that to $Variable, and proceed to replace all of it with "Company", so after PowerShell expands the variable it would look like this:
$variable1 = "EANG04W" -replace "EANG04W", "company"
Ok, you just successfully assigned "company" to a variable. And your If statement ends there. You never output anything from inside your If statement, so Set-Content has nothing to set. Also, it would set that nothing for each and every line that is piped to the ForEach statement, re-writing the file each time, but fortunately for you the script didn't work so it didn't erase your file. Plus, since you were trying to pipe to Set-Content, there was no output at the end of the pipeline, you have assigned absolutely nothing to $content.
So let's try and fix it, shall we? First line? Works great! No change. Now, we aren't saving anything in a variable, we just want to update a file's content, so there's no need to have $Content = there. We'll just move on then, shall we? We pipe the Get-Content into a ForEach loop, just like you tried to do. Once inside the ForEach loop, we're going to do things a bit differently though. The -replace method performs a RegEx match. We can use that to our advantage here. We will replace the text you are interested in for each line, and if it's not found, no replacement will be made, and pass each line on down the pipeline. That will look something like this for the inside of the ForEach:
$_ -replace "(<=CN\=).*?(?=,)", "Company"
The breakdown of that RegEx match can be seen here: https://regex101.com/r/gH6hP2/1
But, let's just say that it looks for text that has 'CN=' immediately before it, and goes up to the first comma following it. In your example, that includes the two trailing asterisks, but it doesn't touch the leading ones. Is that what you intended? That would make the last line of your example file:
Primary Owner = **CN=Company,OU=EANG,DC=afp,DC=localenter code here
Well, if that is as intended, then we have a winner. Now we close out the ForEach loop, and pipe the output to Set-Content and we're all set! Personally, I would highly suggest outputting to a new file, in case you need to reference the original file for some reason later, so that's what I'm going to do.
$file = 'D:\sources\scripts\2.txt'
$newfile = Join-Path (split-path $file) -ChildPath ('Updated-'+(split-path $file -Leaf))
Get-Content $file | ForEach{$_ -replace "(?<=CN\=).*?(?=,)", "Company"} | Set-Content $newfile
Ok, that's it. That code will produce D:\sources\scripts\Updated-2.txt with the following content:
Computer Location = afp.local/EANG
Description = RED_TXT
Device Name = EANG04W
Domain Name = afp.local
Full Name = Admintech
Hardware Monitoring Type = ASIC2
Last Blocked Application Scan Date = 1420558125
Last Custom Definition Scan Date = 1348087114
Last Hardware Scan Date = 1420533869
Last Policy Sync Date = 1420533623
Last Software Scan Date = 1420533924
Last Update Scan Date = 1420558125
Last Vulnerability Scan Date = 1420558125
LDAP Location = **CN=Company,OU=EANG,DC=afp,DC=local
Login Name = ADMINTECH
Main Board OEM Name = Dell Inc.
Number of Files = 384091
Primary Owner = **CN=Company,OU=EANG,DC=afp,DC=localenter code here

Related

Bookmarks parsing issue

I have a LARGE number of bookmarks and wanted to export them and share them with a group I work with. The issue is that when I export them, there are ADD_DATE and LAST_MODIFIED fields added by the browser (Firefox). I was hoping to just use cut or awk to pull the fields I want but the lack of a space before the >(website_name) is making that difficult. And my regex skills are weak.
How do I add a single space before the second to last > at the end of the line so that I can use cut or awk to pull out the fields I want into a new file?
Ex: 123456">SecurityTrails would become 123456 >SecurityTrails
Please see below for examples of what I'm working with. Any help is greatly appreciated!
<DT>SecurityTrails
i use firefox myself. it frequently also embeds favicon into the exported bookmarks.html file via base64 encoding. so to account for the different scenarios (than just the one mentioned by OP), maybe something like
{mawk/mawk2/gawk} 'BEGIN { FS = "\042" } $1 = $1'
then do whatever cutting that you want. That's just assuming OP wanted to keep every bit of it, and simply remove the quotations.
Now, if the objective is just to take out URL+Name of it,
{mawk/mawk2/gawk} 'BEGIN { DBLQT="\042"; FS = "(<A HREF=" DBLQT "|>)" } /<A HREF=/ {
url = substr($2, 1, index($2, DBLQT) - 1);
sitename = $(NF-1);
sub(/<\/A$/, "", sitename) ;
print url " > " sitename ; }' # or whatever way you want the output to be
I just typed it in extra verbosity to show what \042 meant - the ascii octal for double quote.

Ignore the "Select Sheet" message on Excel Interop

Maybe someone here can help me out with this. I am trying to convert all XLS to XLSX/M files with powershell and interop. So far so good. In my next step, I have to adapt the link sources in each file, which works sometimes (also from XLS to XLSX/M).
I don’t know why, but sometimes the original worksheet name does not exist in the linked Excel file and results in a pop up with which the user has to interact:
I actually really don’t care so much about the sheet and I just want to ignore the message so that the script can continue.
In my code I use the function ChangeLink, like this:
$workbook.ChangeLink($fileLink_old, $fileLink_new)
I also have deactivated any warning on the excel object itself, but nothing helps:
$excel.DisplayAlerts = $False
$excel.WarnOnFunctionNameConflict = $False
$excel.AskToUpdateLinks = $False
$excel.DisplayAlerts = $False
The most convinient way for me would be just ignoring the pop up.
Is there a way without going through all cells by itself or modifing the externalLinks/_rels inside of the excel file?
Thanks in advance
Stephan
Edit:
To loop through each cell, not really efficient
ForEach ($Worksheet in #($workbook.Sheets)) {
Write-Host $Worksheet.Name
ForEach ($filelink in $fileLinks){
$worksheetname = $null
$fl_we = $fileLink.Substring(0, $fileLink.LastIndexOf('.'))
$found = $Worksheet.Cells.Find($fl_we.Substring(0, $fl_we.LastIndexOf('\')) + '\[' + $fl_we.Substring($fl_we.LastIndexOf('\')+1))
if($found -ne $null){
Write-Host Search $filelink
Write-Host $Worksheet.Cells($found.Row,$found.Column).Formula
$str_formula = $Worksheet.Cells($found.Row,$found.Column).Formula
$worksheetname = $str_formula.Substring($str_formula.IndexOf(']')+1,$str_formula.IndexOf('!')-$str_formula.IndexOf(']')-2)
Write-Host $worksheetname -ForegroundColor DarkGray
#Add worksheets with filename to list
}
}
}
#Check if worksheet exists in linked file

Confirming existence of a string in an xml table Lua

Good afternoon everyone,
My problem is that I have 2 XML lists
<List1> <Agency>String</Agency> </List1>
and
<List2><Agency2>String</Agency2><List2>.
In Lua I need to create a program which is parsing this list and when the user inputs a matching string from List 1 or List 2, the program needs to actually confirm to the user if the string belongs to either L1 or L2 or if the string is inexistent. I'm new to Lua and to programming generally speaking and I would be very grateful for you answers. I have LuaExpat as a plugin but I can't seem to be able to actually read from file, I can only do some beginner tricks if the xml list is written in the code. At a later time this small program will be fed by an RSS.
require("lxp")
local stuff = {}
xmldata="<Top><A/> <B a='1'/> <B a='2'/><B a='3'/><C a='3'/></Top>"
function doFunc(parser, name, attr)
if not (name == 'B') then return end
stuff[#stuff+1]= attr
end
local xml = lxp.new{StartElement = doFunc}
xml:parse(xmldata)
xml:close()
print(stuff[3].a)
This code is a tutorial over the web that works, everything is just fine it prints nr. 3. Now I want to know how to do that from an actual file, as if I input io.read:(file, "r" or "rb" ) under xmldata variable and run the same thing it returns either empty space or nil.

php str_replace produces strange results

I am trying to replace some characters in a text block. All of the replacements are working except the one at the beginning of the string variable.
The text block contains:
[FIRST_NAME] [LAST_NAME], This message is to inform you that...
The variables are defined as:
$fname = "John";
$lname = "Doe";
$messagebody = str_replace('[FIRST_NAME]',$fname,$messagebody);
$messagebody = str_replace('[LAST_NAME]',$lname,$messagebody);
The result I get is:
[FIRST_NAME] Doe, This message is to inform you that...
Regardless of which tag I put first or how the syntax is {TAG} $$TAG or [TAG], the first one never gets replaced.
Can anyone tell me why and how to fix this?
Thanks
Until someone can provide me with an explanation for why this is happening, the workaround is to put a string in front and then remove it afterward:
$messagebody = 'START:'.$messagebody;
do what you need to do
$messagebody = substr($messagebody,6);
I believe it must have something to do with the fact that a string starts at position 0 and that maybe the str_replace function starts to look at position 1.

Can I use two sets of variables in one foreach loop?

Is is possible to construct one single foreach loop that loops through using two separate sets of variables?
Below is a simplified example of what I'm trying to do - except this example lists two separate loops whereas I would like to set them up in one single loop.
$Sites = #("https://www.google.com" , "https://duckduckgo.com")
$Site_names = #( "Google" , "DuckDuckGO")
foreach ($element in $Sites) {
Write-Host "`n`n"
$element
Write-Host "`n`n"
}
foreach ($name in $Site_names) {
Write-Host "`n`n"
$name
Write-Host "`n`n"
}
There is other code to be used so the loop needs to be able to allow for multiple lines of code in the code block - so a single line solution if there is one isn't what I'm after. Also I didn't think using the pipeline would be workable (but I could certainly be wrong on that).
Two sets of variables: $Sites and $Site_names.
I would like one foreach loop that runs through and lists the site address and the site name with both values changing each time the loop is run.
First run: reference the URL "https://www.google.com" and the site name "Google".
Second run: reference the URL "https://duckduckgo.com" and the site name "DuckDuckGo".
Is this possible?
If you have two arrays of the same size you can simply use a for loop like this:
for ($i=0; $i -lt $Sites.Count; $i++) {
"{0}`t{1}" -f $Site_names[$i], $Sites[$i]
}
However, if the elements of your two arrays are correlated anyway, it would be better to use a hashtable instead:
$Sites = #{
'Google' = 'https://www.google.com'
'DuckDuckGo' = 'https://duckduckgo.com'
}
foreach ($name in $Sites.Keys) {
"{0}`t{1}" -f $name, $Sites[$name]
}

Resources