Closed lazywinadmin closed 5 years ago
Posted on: 2013-10-20T06:29:18Z
Good stuff! Here are some functions for processing ldap paths you may like. I hid them in a recent script release (but never actually used them, like a hidden little gift).
Function Get-TreeFromLDAPPath
{
# $Output = [System.Web.HttpUtility]::HtmlDecode(($a | ConvertTo-Html))
[CmdletBinding()]
Param
(
[Parameter(HelpMessage="LDAP path.")]
[string]
$LDAPPath,
[Parameter(HelpMessage="Determines the depth a tree node is indented")]
[int]
$IndentDepth=1,
[Parameter(HelpMessage="Optional character to use for each newly indented node.")]
[char]
$IndentChar = 3,
[Parameter(HelpMessage="Don't remove the ldap node type (ie. DC=)")]
[Switch]
$KeepNodeType
)
$regex = [regex]'(?^.+)\=(?.+$)'
$ldaparr = $LDAPPath -split ','
$ADPartCount = $ldaparr.count
$spacer = ''
$output = ''
for ($index = ($ADPartCount); $index -gt 0; $index--)
{
$node = $ldaparr[($index-1)]
if (-not $KeepNodeType)
{
if ($node -match $regex)
{
$node = $matches['LDAPName']
}
}
if ($index -eq ($ADPartCount))
{
$line = ''
}
else
{
$line = $IndentChar
$spacer = $spacer + (' ' * $IndentDepth)
# This fixes an offset issue
if ($index -lt ($ADPartCount - 1))
{
$spacer = $spacer + ' '
}
}
$line = $spacer + $line + $node + "`n"
$output = $Output+$line
}
[string]$output
}
Function Get-ObjectFromLDAPPath
{
[CmdletBinding()]
Param
(
[Parameter(HelpMessage="LDAP path.")]
[string]
$LDAPPath,
[Parameter(HelpMessage="Determines the depth a tree node is indented")]
[switch]
$TranslateNamingAttribute
)
$output = @()
$ldaparr = $LDAPPath -split ','
$regex = [regex]'(?^.+)\=(?.+$)'
$position = 0
$ldaparr | %{
if ($_ -match $regex)
{
if ($TranslateNamingAttribute)
{
switch ($matches['LDAPType'])
{
'CN' {$_ldaptype = "Common Name"}
'OU' {$_ldaptype = "Organizational Unit"}
'DC' {$_ldaptype = "Domain Component"}
default {$_ldaptype = $matches['LDAPType']}
}
}
else
{
$_ldaptype = $matches['LDAPType']
}
$objprop = @{
LDAPType = $_ldaptype
LDAPName = $matches['LDAPName']
Position = $position
}
$output += New-Object psobject -Property $objprop
$position++
}
}
Write-Output -InputObject $output
}
Posted on: 2013-10-20T07:19:14Z
Thanks Zachary! I will check it out
Posted on: 2013-10-20T18:15:04Z
Another way of using Regex here is to use these two lines:
'OU=MTL1,OU=CORP,DC=FX,DC=LAB' -match '(?<=(^OU=))(?=(,))'
$matches[0]
This uses the regex concepts of lookahead and lookbehind which are covered fairly well in this article:
http://blogs.technet.com/b/...
This matches the string that comes after the pattern '^OU='(the caret '^' is the beginning of line metacharacter) and before the pattern ','. The -match operator returns a boolean and stores the actual matches in the $matches variable.
Splitting on ',*..=' requires you to know where substring is in the string in order to choose the correct index from the array. If that's the case the substring method is going to be more straightforward than regex. If you're not sure where in the string the pattern is you're better off using regex.
Posted on: 2013-10-20T18:22:52Z
Another useful link on Regular Expressions in .net:
Regular Expression Language - Quick Reference
http://msdn.microsoft.com/e...
Posted on: 2013-10-20T20:56:58Z
Thanks Jay, Useful !
I added the link to the post.
Posted on: 2013-10-20T23:21:43Z
Here is another way, except that with this method you can select column 1 or column 2 at the same time side by side, take a look:
$var1 = "OU=MTL1,OU=CORP,DC=FX,DC=LAB"
This gives column 1
$var1 | % {"{1}" -f($_ -split ',*..=')}
MTL1
Now you want column 1 and 3
$var1 | % {"{1} {3}" -f($_ -split ',*..=')}
MTL1 - FX
if you want a separator of some kind, the dash in this case, "-":
$var1 | % {"{4} - {1}" -f($_ -split ',*..=')}
FX - MTL1
Enjoy!
Posted on: 2013-10-21T00:36:54Z
Thanks Jay, weird i'm getting an error with
'OU=MTL1,OU=CORP,DC=FX,DC=LAB' -match '(?<=(^OU=))(?=(,))'
$matches[0]
The first line return $false.
Thanks again for the information, really useful! very appreciated
Posted on: 2013-10-21T00:43:11Z
Awesome! Thanks Luis, Great info!
It's actually faster with your line
PS C:\Users\Francois-Xavier> Measure-Command { ($var1 -split ',*..=')[1]}
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 1
Ticks : 16121
TotalDays : 1.86585648148148E-08
TotalHours : 4.47805555555556E-07
TotalMinutes : 2.68683333333333E-05
TotalSeconds : 0.0016121
TotalMilliseconds : 1.6121
PS C:\Users\Francois-Xavier> Measure-Command { $var1 | % {"{1}" -f($_ -split ',*..=')}}
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 0
Ticks : 5494
TotalDays : 6.3587962962963E-09
TotalHours : 1.52611111111111E-07
TotalMinutes : 9.15666666666667E-06
TotalSeconds : 0.0005494
TotalMilliseconds : 0.5494
Posted on: 2013-10-21T06:26:18Z
I added a couple of links at the bottom of the post. The Scripting Guy Ed Wilson and Lee Holmes wrote some nice articles about the subjet, hope this help!
Posted on: 2013-10-22T04:45:30Z
My apologies the first line should be:
'OU=MTL1,OU=CORP,DC=FX,DC=LAB' -match '(?<=(^OU=))\w*(?=(,))'
Posted on: 2013-10-22T04:55:21Z
Nice!! Thanks Jay :-)
Posted on: 2014-04-14T19:53:05Z
I'm trying to use this to strip off the first 3 digits in a phone number report I have to do, so I need to query AD, get all user names & phone numbers, then strip off/delete the 1st 3 digits, and then export and email the csv. Any idea's how to do that reliably?
Posted on: 2014-04-21T21:03:07Z
What if you only want to get the first OU value after DC=, in this example Corp from the string. Also where you could have something like CN=PC-Name,OU=Sales,OU=Chicago,DC=Central,DC=FXCorp,DC=com
CN=PC-Name,OU=Sales,OU=LA,DC=West,DC=FXCorp,DC=com
Posted on: 2014-04-21T21:09:37Z
Hi Ernie,
What about :
("CN=PC-Name,OU=Sales,OU=LA,DC=West,DC=FXCorp,DC=com" -split ",")[4].substring(3)
Posted on: 2014-04-21T21:26:55Z
Hi Marie,
For the AD query and trim of 3 first digits, this should do it:
Posted on: 2014-04-24T18:33:24Z
Thanks, that's great! My only problem is I should have mentioned I don't have an AD Web proxy so I have to use the Quest Cmdlets, can I do this using them? Then take the output of usernames and phone numbers, export to a network path or email a csv file?
Thank you so much!!
Marie
Posted on: 2014-04-24T18:54:52Z
Hi Marie, the script I shared with you use ADSI, so you dont need any module or snapin like Quest Cmdlets. It should just work fine
Exporting the output can just be done using Export-CSV -path exported_users.csv
Example:
Get-DomainUser -DisplayName "*" | Export-CSV -path c:\exported_users.csv
Posted on: 2014-04-30T05:01:03Z
Thank you Francois! I did not realize at first this was using ADSI, we have a 2003 domain and I don't have an AD Web service running and that leaves me struggling often, hence why I rely on the Quest AD Module.
I do get the Username "SAMAccountName", Description, Display Name, and Telephone Number. The number outputs without the 1st three digits as I asked how to do, but I am left with the number as "-123-4567". How can I remove that leading "-" symbol?
I then get this error and I think it's because I am searching the entire domain, how can I limit this to a single OU?
Exception calling "Substring" with "1" argument(s): "startIndex cannot be larger than length of string.
Parameter name: startIndex"
At C:\scripts\list.ps1:6 char:9
+ New-Object -TypeName PSObject -Property @{
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentOutOfRangeException
Posted on: 2014-05-05T13:20:27Z
Hi Francois, is there any way to do what I want that's not going to be a big challenge?
I've spend a few days banging my head off the wall and can't figure this out
Posted on: 2014-05-06T17:10:28Z
Hi Marie,
You just need to change the substring value.
see here, this should do it
Posted on: 2014-05-08T18:25:48Z
This is great, I need to narrow the scope to only 1 OU and all the SUB-OUs under that though, is it possible?
Then I just have to export that to a csv file and run this as a scheduled task.
Posted on: 2014-05-13T19:23:04Z
I found some ways to filter and query only an OU, but nothing is working right if I try to narrow the search scope.
Posted on: 2014-05-17T16:54:38Z
Hi Marie,
This should do it
https://gist.github.com/laz...
You need to specify the DistinguishedName of the OU
Posted on: 2016-04-17T20:52:42Z
I happen to notice your discussion on variables and substrings.
Say I have a txt file and I want to compare first two substrings on each line of the file.
The two substrings are separated by a + sign only. So how do I get to compare substring1 with substring 2 on each line knowing that these substrings are only separated by a + operator, and count the occurrence of a match of these two substring1 substring2 on all the lines of the txt file?
Thanks
Posted on: 2016-04-17T21:55:31Z
Or search substrings in an array of patterns; the array is made of 50000 lines of text. The substrings are delimited/separated by a plus sign on each line and I want to compare substring1 with substring2 on each line...
Posted on: 2017-04-17T12:17:01Z
Hi. Good tip! Thnx.
But what can I do if my output is two strings?
Example:
Input: Get-ADDomain | Select ComputersContainer
Output:
ComputersContainer
------------------
CN=Computers,DC=contoso,DC=com
How I can select only DC=contoso,DC=com in new variables?
Posted on: 2017-04-18T02:31:33Z
Hi Tom, not sure what you are trying to do...
You can do something like that:
((Get-ADDomain).ComputersContainer -split ',')[-2,-1] -join ','
Posted on: 2017-06-17T21:30:08Z
I did so
$dname = Get-ADDomain | % { $_.Forest }
$dname = $dname.Split("{.}")
And my final solution looks like https://github.com/getsuein...
I just did $Var.Split(",")[0].Replace"OU=" "")
Salut François-Xavier,
Tres bon post, sa aide beaucoup. mais j'ai une question. Comment je peux inverser le CN d'un manager d'usager, lorsqu'il est formater "Lastname,\ Firstname" ? J'ai besoin d'avoir comme resultat "Firstname" + " " + "Lastname"
Voici mon resultat : PS C:\WINDOWS\system32> $DN = 'CN=Dummy\, Test,OU=Users,OU=Montreal,DC=lab,DC=com'
PS C:\WINDOWS\system32> $DN | % {"{1}" -f($_ -split ',*..=')} Dummy\, Test
Merci de ton aide.
voici ma trouvaille, $DN | % {"{2} {1}" -f(($_ -split ',*..=') -replace "\,","").split(" ")}
reste a voir comment l'integrer pour faire une variable de Get-ADUser -properties manager
je dois avoir dans le style @{label='Manager';expression={$_.manager }} mais que celui soit deja corriger
@{Name="4";Expression={% {"{2} {1}" -f(($_.manager -split ',*..=') -replace "\,","").split(" ")}}},
my best practice $var = ("OU=MTL1,OU=CORP,DC=FX,DC=LAB".Split(",")[0]).Split("=")[1]
Hello there,
this topic might be an older one, but I thought, I could still contribute something here.
I have tested the Regex user recommendations.
Jay's one falls short, since it seems to only returns the very first OU=
If you like to use a full string Regex for the sake of it, then this is my recommendation: (?:|.,)OU=(MTL1)(?:,.|) $matches[1]
First, you need your string to start with "Nothing" or with "any char followed by comma". Then you want "OU=MTL1", right? If you like MTL1 as a separated match value for later access, use "OU=(MTL1)". Finally you want the string followed by "nothing" or "a comma followed by anything".
In this case Match[1] will always be "MTL1" or $null, if not found. If you like to access this value like Robert did ($matches["MTL1"]), use this expanded line:
"(?:|.,)OU=(?
This solution will match MTL1 at any position, it won't match MTL11.
Since I like readable code, I do things like this to separate the wierd stuff from the actual information: $StartWith_nothing_OR_AnythingAndComma = "^(?:|.,)" $CloseWith_nothing_OR_CommaAndAnything = "(?:|,.)$"
'OU=CORPO,OU=MTL1,OU=MTL2,OU=MTL11,OU=CORP,DC=FX,DC=LAB' -match $( "${StartWith_nothing_OR_AnythingAndComma}"
Otherwise: The cleanest solution doesn't involve so much of sophisticated Regex-Queriing:
$AD_ArrayList = "OU=MTL1,OU=CORP,DC=FX,DC=LAB" -split "," $ADArrayList | Where { $ -match '=MTL1$' }
Result is $null or "OU=MTL1" so many times as it could be found inside the array. It is easy from here on.
If you like to read only MTL1, then just add: ... | foreach-object {$_ -replace('OU=','')}
If you just wanna know, if it matches, use (-eq or -ne): $null -eq $( $ADArrayList | Where { $ -match '=MTL1$' } )
Don't overcomplicate things so much. The reader of your sourcecode, which might probably you yourself in a few weeks, will be thankful.
Oh dear, it is markdown. Sorry, here is the full Expression "(?:|.*,)OU=(?\<MTL1>MTL1)(?:,.*|)"
Oh, I'm so sorry. While being occupied with solving my own problem, I completely missed the issue with this target. Please delete my posts above, if you like so and are able to.
Assuming, the wanted sitecode can always be found at the beginning of the string and returning the name of the sitecode is the target, this is my solution.
... -match "^OU=(?\<SiteCode>\w+)(?:,.*|)$" $matches['SiteCode'] would give the result.
It modifies Robert's recommendation so far, that the characters after OU= must be of type \w+ (Word: [A-Za-z0-9_] Furthermore it says, Word is followed by "a comma and anything" or "nothing", encapsulated in a "please count me as a match-bracket -> (?: )"
This notation may raise the readability, especially, if you want to know, what happens without needing to know every bit of detail:
$siteCode = "(?\<SiteCode>\w+)" $FollowedBy_commaAndAnything_or_Nothing = "(?:,.*|)"
... match "^OU=${SiteCode}${FollowedBy_commaAndAnything_or_Nothing}$"
PowerShell - Get a SubString out of a String using RegEx
https://lazywinadmin.com/2013/10/powershell-get-substring-out-of-string.html