sirbounty
asked on
Replacing a portion of a string with function results
I am using an ldap query that tests for various levels of specific department codes.
The problem is, during re-orgs, the level may change. I'd like to automate a fix for that issue.
I have a function that will give me the correct portion of the query, in the format of
There may be one or multiple instances of this criteria in the search filter.
I have the code that will search the filter for that data, pull out the department number, search for it and return the new department (if it changed). Though I'm not convinced this is the best approach... I may be 'changing' something that hasn't changed for example.
Here is what I'm using at the moment:
Ultimately I'd like to split the string and compare each department against where it currently sits and only replace it if it has been altered. Perhaps a regex expert can chime in?
Example of a query
The problem is, during re-orgs, the level may change. I'd like to automate a fix for that issue.
I have a function that will give me the correct portion of the query, in the format of
(l5deptcode=12345)
There may be one or multiple instances of this criteria in the search filter.
I have the code that will search the filter for that data, pull out the department number, search for it and return the new department (if it changed). Though I'm not convinced this is the best approach... I may be 'changing' something that hasn't changed for example.
Here is what I'm using at the moment:
foreach ($li in $searcher.Filter.Split('(')) {
if ($li.contains('deptcode')) {check-depts $li.split('=')[1].replace(')','')}
}
Ultimately I'd like to split the string and compare each department against where it currently sits and only replace it if it has been altered. Perhaps a regex expert can chime in?
Example of a query
(&(|(estatus=A)(estatus=L))(|(&(eType=D)(&(resid=E*)(hiredDate<=2020-08-21)))(&(eType=C)(&(resid=N*)(hiredDate<=2020-08-21))))(|(l6deptcode=19431)(l7deptcode=61886)(l7deptcode=43172)(l8deptcode=76616)(l9deptcode=18406)))
ASKER
If I can strip out the L?deptcode numbers, I can pass them all through my function and have it return them in their new level (if it changed). The function will return the query format. So if I pass it "12345", it will return "(l8deptcode=12345)"
OK, so this
really does the same thing as what you had before
To use regex to replace only those department numbers that have changed, you have to
1) know what has changed
2) search for the specific string (not just a pattern) that should be changed
3) then change the value
Here's concept code.
So this is really searching for (L?deptcode= followed by the specific number that we know has changed, followed by a closing parentheses. I don't know if the number after the "L" has any importance to this process.
[regex]::Matches($searcher.filter,"\(l\d+deptcode=(?<dept>\d+)\)") | % { $_.Groups['dept'].Value }
really does the same thing as what you had before
foreach ($li in $searcher.Filter.Split('(')) {
if ($li.contains('deptcode')) {check-depts $li.split('=')[1].replace(')','')}
}
To use regex to replace only those department numbers that have changed, you have to
1) know what has changed
2) search for the specific string (not just a pattern) that should be changed
3) then change the value
Here's concept code.
$data = @"
dept,changed
19431,
61886,61800
43172,
76616,
18406,18300
"@ | ConvertFrom-Csv
$data.Where({"" -ne $_.changed}) | ForEach-Object {
$searcher.Filter = $searcher.Filter -replace "(\(l\d+deptcode=)$($_.dept)(\))","`${1}$($_.changed)`${2}"
} -End { $searcher.Filter }
So this is really searching for (L?deptcode= followed by the specific number that we know has changed, followed by a closing parentheses. I don't know if the number after the "L" has any importance to this process.
Here's a slightly different way of doing the search and replace (with the same result).
$data.Where({"" -ne $_.changed}) | ForEach-Object {
$searcher.Filter = $searcher.Filter -replace "(?<=\(l\d+deptcode=)$($_.dept)(?=\))","$($_.changed)"
} -End { $searcher.Filter }
ASKER
I think there's a touch of miscommunication here.
The department number will not change, but the level of that number may.
Using your regex above, I can display the new level using this:
81984 l5deptcode changed to l8deptcode
Now I just need to plug that back in to the filter with the new level (l8deptcode=81984)
The department number will not change, but the level of that number may.
Using your regex above, I can display the new level using this:
foreach ($dept in [regex]::Matches($searcher.filter,"\(l\d+deptcode=\d+\)") | Select -ExpandProperty value) {
$deptNo = $dept.split('=')[1].replace(')','') #this would give me 81984
$orglvl = $dept.replace('(','').replace(')','').split('=')[0] #this would give me l5deptcode
$newlvl = (Check-Depts $deptNo).replace(')','').replace('(','').split('=')[0] #this would give me l8deptcode
if ($orglvl -ne $newlvl) {
write-host "$deptNo $orglvl changed to $newlvl" -ForegroundColor Yellow
}
Results:81984 l5deptcode changed to l8deptcode
Now I just need to plug that back in to the filter with the new level (l8deptcode=81984)
OK, yes that definitely changes my understanding.
Give this a shot.
Give this a shot.
foreach ( $dept in ([regex]::Matches($searcher.filter,"\(l\d+deptcode=(?<dept>\d+)\)")) ) {
$newlvl = Check-Depts $dept.Groups['dept'].Value
if ( $dept.Groups[0].Value -ne $newlvl ) {
$searcher.Filter = $searcher.Filter -replace "$([regex]::Escape($dept.Groups[0].Value))","$newlvl"
}
}
ASKER
I'm not getting Groups though?
$dept is simply a string value - do I need to iterate through that regex differently?
$dept is simply a string value - do I need to iterate through that regex differently?
ASKER
Tried this but it wipes out my filter... leaving just one '(l13deptcode=81921)' value without any of the filter leading or trailing that reference.
foreach ($dept in [regex]::Matches($searcher.filter,"\(l\d+deptcode=\d+\)") | Select -ExpandProperty value) {
$deptNo = $dept.split('=')[1].replace(')','')
$orglvl = $dept.replace('(','').replace(')','').split('=')[0]
$newlvl = (Check-Depts $deptNo).replace(')','').replace('(','').split('=')[0]
if ($orglvl -ne $newlvl) {
$searcher.Filter = $searcher.Filter -replace $orglvl,$newlvl
}
}
In my last post, $dept is not just a string.
ASKER
Sorry, but I believe I'm confused now. :\
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I see. My function simply returns a string however. The function actually loops through all department levels to find out where the presence of that department number is, and when found, returns that single string (l3deptcode=xxxxx).
So I'm not sure how modify this from the group representation.
So I'm not sure how modify this from the group representation.
My function returns a string as well (and from what you've described, in the exact same format). Try it (with the limited set of numbers it can handle) and tell me how the output differs.
As for the second code block, you should just be able to run it with no modification to update the query (filter) with the new L numbers.
As for the second code block, you should just be able to run it with no modification to update the query (filter) with the new L numbers.
Just to be clear: AD does not update the database if a value does not change. It's smarter than that.
ASKER
Thanks Michael - I'm not updating AD (and I also cannot use adsisearcher). I'm using ldap against a data view from a 3rd party product.
Apologies footech - I see where I was confused.
I think I have it working now. I'll close this out shortly. Thanks!
Apologies footech - I see where I was confused.
I think I have it working now. I'll close this out shortly. Thanks!
ASKER
Thanks for the help!
Glad to help!
How do we know something's been altered, and what exactly is altered?
This may be something of a start. Using something like this, you get a list of the departments in the filter.
Open in new window