Get CN value from ADUser DistinguishedName - powershell

I have a PS script that checks some custom user's properties in Active Directory.
One of the properties is "Manager".
$data = Get-ADUser $user -Properties * | Select-Object DisplayName, LockedOut, Enabled, LastLogonDate, PasswordExpired, EmailAddress, Company, Title, Manager, Office
Write-Host "9." $user "manager is" $data.manager -ForegroundColor Green
When I run the script I've got:
User's manager is CN=cool.boss,OU=Users,OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC=com
The problem is that text "OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC=com" will be different for some users
How can I modify output and remove everything except "cool.boss"?
Thank you in advance

This should be a more or less safe and still easy way to parse it:
($data.manager -split "," | ConvertFrom-StringData).CN

To complement the helpful answers here with PowerShell-idiomatic regex solutions:
Using -split, the regex-based string splitting operator:
$dn = 'CN=cool.boss,OU=Users,OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC=com'
($dn -split '(?:^|,)CN=|,')[1] # -> 'cool.boss'
Using -replace, the regex-based string substitution operator:
$dn = 'CN=cool.boss,OU=Users,OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC=com'
$dn -replace '(?:^|,)CN=([^,]+).*', '$1' # -> 'cool.boss'
Note:
The above solutions do not rely on a specific order of the name-value pairs (RDNs) in the input (that is, a CN entry needn't be the first one), but they do extract only the first CN entry's value, should multiple ones be present, and they do assume that (at least) one is present.
In principle, DNs (Distinguished Names), of which the input string is an example, can have , characters embedded in the values of the name-value pairs that make up a DN, escaped as \, (or, in hex notation, \2C); e.g., "CN=boss\, cool,OU=Users,..."
A truly robust solution would have to take that into account, and would ideally also unescape the resulting value; none of the existing answers do that as of this writing; see below.
Robustly parsing an LDAP/AD DN (Distinguished Name):
The following Split-DN function:
handles escaped, embedded , chars., as well as other escape sequences, correctly
unescapes the values, which includes not just removing syntactic \, but also converting escape sequences in the form \<hh>, where hh is a two-digit hex. number representing a character's code point, to the actual character they represent (e.g, \3C, is converted to a < character).
outputs an ordered hashtable whose keys are the name components (e.g., CN, OU), with the values for names that occur multiple times - such as OU - represented as an array.
Example call:
PS> Split-DN 'CN=I \3C3 Huckabees\, I do,OU=Users,OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC=com'
Name Value
---- -----
CN I <3 Huckabees, I do
OU {Users, SO, PL, RET…}
DC {domain, com}
Note how escape sequence \3C was converted to <, the character it represents, and how \, was recognized as an , embedded in the CN value.
Since the input string contained multiple OU and DC name-value pairs (so-called RDNs, relative distinguished names), their corresponding hashtable entries became arrays of values (signified in the truncated-for-display-only output with { ... }, with , separating the elements).
Function Split-DN's source code:
Note: For brevity, error handling and validation are omitted.
function Split-DN {
param(
[Parameter(Mandatory)]
[string] $DN
)
# Initialize the (ordered) output hashtable.
$oht = [ordered] #{}
# Split into name-value pairs, while correctly recognizing escaped, embedded
# commas.
$nameValuePairs = $DN -split '(?<=(?:^|[^\\])(?:\\\\)*),'
$nameValuePairs.ForEach({
# Split into name and value.
# Note: Names aren't permitted to contain escaped chars.
$name, $value = ($_ -split '=', 2).Trim()
# Unescape the value, if necessary.
if ($value -and $value.Contains('\')) {
$value = [regex]::Replace($value, '(?i)\\(?:[0-9a-f]){2}|\\.', {
$char = $args[0].ToString().Substring(1)
if ($char.Length -eq 1) { # A \<literal-char> sequence.
$char # Output the character itself, without the preceding "\"
}
else { # A \<hh> escape sequence, conver the hex. code point to a char.
[char] [uint16]::Parse($char, 'AllowHexSpecifier')
}
})
}
# Add an entry to the output hashtable. If one already exists for the name,
# convert the existing value to an array, if necessary, and append the new value.
if ($existingEntry = $oht[$name]) {
$oht[$name] = ([array] $existingEntry) + $value
}
else {
$oht[$name] = $value
}
})
# Output the hashtable.
$oht
}

You can use the .split() method to get what you want.
$DN = "CN=cool.boss,OU=Users,OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC =com"
$DN.Split(',').Split('=')[1]
What i'd recommend, is throwing it into another Get-ADUser to get the displayname for neater output(:

you could use regex for that:
$s = "CN=cool.boss,OU=Users,OU=SO,OU=PL,OU=RET,OU=HBG,DC=domain,DC =com"
$pattern = [regex]"CN=.*?OU"
$r = $pattern.Replace($s, "CN=OU")
$r

Related

Powershell - How to use an * as a String Filter

I need to filter out only the AD groups from the Net User command in powershell. All the AD groups begin with an * so i would like to filter out the string by displaying everything that's preceeded by an *
I get an error since '*' is a special character and cannot be used. How do i get powershell to ignore it as a special character?
I cannot use any other commands to get AD groups, so Get-AD is not an option. i only have Net user to work with.
My base script,
Net User USER /domain | Select-String '*'
I cannot use any other script than Net user to accomplish this task, even though Get-AD would be simpler, i do not have the option.
Santiago's helpful answer shows a more robust, OO solution that is much more in the spirit of PowerShell.
To answer your question as asked:
Select-String by default interprets its (positionally implied) -Pattern argument as a regex (regular expression), where * is a metacharacter.
While \-escaping regex metacharacters is possible (and is necessary in the event that you need more sophisticated matching that requires a regex), the direct solution is to add the -SimpleMatch switch, which causes the -Pattern argument to be interpreted as a literal (verbatim) string:
net user $someuser /domain | Select-String * -SimpleMatch
Also note that what Select-String outputs by default aren't just the matching input lines as-is, but Microsoft.PowerShell.Commands.MatchInfo objects that provide metadata for each match, with the matching line text stored in the .Line property.
While that distinction doesn't matter much for displaying results, it may for programmatic processing, so if you only want to output the text of the matching lines, add -Raw in PowerShell (Core) 7+, or pipe to | ForEach-Object Line in Windows PowerShell.
The above will show those net user output lines that contain a literal *, and therefore all group memberships, which is good enough for the human observer.
You indeed need regex matching and operations if you want to extract the group names individually, for later programmatic processing:
# Use an ordered hashtable to collect the group names in,
# with keys 'Local' and 'Global', targeting the *current* user in this example.
$groupMemberships = [ordered] #{}
(((net user $env:USERNAME) -join "`n") -split "`n`n")[-1] -split '\n' -match ' \*' |
ForEach-Object {
$tokens = $_ -split ' \*'
if ($tokens[0] -notmatch '^ ') {
$key = if ($groupMemberships.Count -eq 0) { 'Local' } else { 'Global' }
}
$groupMemberships[$key] += #($tokens[1..($tokens.Count-1)].Trim())
}
$groupMemberships # display result.
Sample output:
Name Value
---- -----
Local { Administrators }
Global { Department1, Region1 }
That is $groupMemberships.Local $groupMemberships.Global then contains the name(s) of the local / global (AD) groups the user is a member of, respectively, as an array.
Note:
The solution above is complex, because it tries to be as robust as possible.
Notably, it is possible - albeit not likely in practice - that output lines that are unrelated to group names contain * as well, notably the Comment and User's comment fields.
Therefore, only the last paragraph of net user's output is considered, which is known to contain the group names - note that matching lines by field-name parts such as Local and Global is explicitly avoided, as the field names are localized based on your system's display language.
The last paragraph is known to list the local group memberships first, followed by the global (AD) ones. Each line in the last paragraph can contain multiple (*-prefixed) group names and there can be overflow lines for additional groups that don't fit on the first line for the given scope. Such overflow flow lines can be detected by starting with whitespace.
Instead of trying to parse the output from net user USER /domain I would use what's already available in powershell. You can get the current logged on user's Active Directory Group Membership using adsi and adsisearcher.
Here are 2 different ways of accomplishing it.
By querying the user's memberof attribute:
$searcher = [adsisearcher]::new(
[adsi] "LDAP://$env:USERDNSDOMAIN",
[string] "(cn=$env:USERNAME)",
[string[]] ("memberOf", "cn")
)
$searcher.FindOne().Properties['memberof'] | ForEach-Object {
$searcher.Filter = "(distinguishedName=$_)"
$searcher.FindOne().Properties['cn'][0]
}
By querying all groups having the user as a member:
$searcher = [adsisearcher]::new(
[adsi] "LDAP://$env:USERDNSDOMAIN",
[string] "(cn=$env:USERNAME)",
[string[]] ("distinguishedName", "cn")
)
$userDn = $searcher.FindOne().Properties['distinguishedName'][0]
$searcher.Filter = "(&(objectCategory=group)(member=$userDn))"
$searcher.FindAll() | ForEach-Object {
$_.Properties['cn'][0]
}
You can use a backslash to escape regex special characters and use ^ to specify start of string:
> #("a", "*b", "c*", "*d", "e**") | Select-String -Pattern '^\*'
*b
*d
So, to display the groups you could use, for example:
Net User USER /domain | % { $_ -split "\s+" -match "^\*" }
As per the comment, if the group names may contain spaces then obviously splitting on space characters would be inappropiate.
An alternative:
Net User USER /domain | % { $_ -split '^[^*]+\*?' -match '.+' }
Or, if we only want to look at the lines beginning "Local Group Memberships" or "Global Group Memberships" we could use, for example:
Net User USER /domain |
? { $_ -match '^(?:Local|Global) Group Memberships +\*(.+)' } | % { $matches[1] }

Powershell passing multiple parameters from one script to another [duplicate]

I've seen the # symbol used in PowerShell to initialise arrays.
What exactly does the # symbol denote and where can I read more about it?
In PowerShell V2, # is also the Splat operator.
PS> # First use it to create a hashtable of parameters:
PS> $params = #{path = "c:\temp"; Recurse= $true}
PS> # Then use it to SPLAT the parameters - which is to say to expand a hash table
PS> # into a set of command line parameters.
PS> dir #params
PS> # That was the equivalent of:
PS> dir -Path c:\temp -Recurse:$true
PowerShell will actually treat any comma-separated list as an array:
"server1","server2"
So the # is optional in those cases. However, for associative arrays, the # is required:
#{"Key"="Value";"Key2"="Value2"}
Officially, # is the "array operator." You can read more about it in the documentation that installed along with PowerShell, or in a book like "Windows PowerShell: TFM," which I co-authored.
While the above responses provide most of the answer it is useful--even this late to the question--to provide the full answer, to wit:
Array sub-expression (see about_arrays)
Forces the value to be an array, even if a singleton or a null, e.g. $a = #(ps | where name -like 'foo')
Hash initializer (see about_hash_tables)
Initializes a hash table with key-value pairs, e.g.
$HashArguments = #{ Path = "test.txt"; Destination = "test2.txt"; WhatIf = $true }
Splatting (see about_splatting)
Let's you invoke a cmdlet with parameters from an array or a hash-table rather than the more customary individually enumerated parameters, e.g. using the hash table just above, Copy-Item #HashArguments
Here strings (see about_quoting_rules)
Let's you create strings with easily embedded quotes, typically used for multi-line strings, e.g.:
$data = #"
line one
line two
something "quoted" here
"#
Because this type of question (what does 'x' notation mean in PowerShell?) is so common here on StackOverflow as well as in many reader comments, I put together a lexicon of PowerShell punctuation, just published on Simple-Talk.com. Read all about # as well as % and # and $_ and ? and more at The Complete Guide to PowerShell Punctuation. Attached to the article is this wallchart that gives you everything on a single sheet:
You can also wrap the output of a cmdlet (or pipeline) in #() to ensure that what you get back is an array rather than a single item.
For instance, dir usually returns a list, but depending on the options, it might return a single object. If you are planning on iterating through the results with a foreach-object, you need to make sure you get a list back. Here's a contrived example:
$results = #( dir c:\autoexec.bat)
One more thing... an empty array (like to initialize a variable) is denoted #().
The Splatting Operator
To create an array, we create a variable and assign the array. Arrays are noted by the "#" symbol. Let's take the discussion above and use an array to connect to multiple remote computers:
$strComputers = #("Server1", "Server2", "Server3")<enter>
They are used for arrays and hashes.
PowerShell Tutorial 7: Accumulate, Recall, and Modify Data
Array Literals In PowerShell
I hope this helps to understand it a bit better.
You can store "values" within a key and return that value to do something.
In this case I have just provided #{a="";b="";c="";} and if not in the options i.e "keys" (a, b or c) then don't return a value
$array = #{
a = "test1";
b = "test2";
c = "test3"
}
foreach($elem in $array.GetEnumerator()){
if ($elem.key -eq "a"){
$key = $elem.key
$value = $elem.value
}
elseif ($elem.key -eq "b"){
$key = $elem.key
$value = $elem.value
}
elseif ($elem.key -eq "c"){
$key = $elem.key
$value = $elem.value
}
else{
Write-Host "No other value"
}
Write-Host "Key: " $key "Value: " $value
}

Is it possible to alter part of a variable based on its value?

I have a script that grabs a list of AD usernames for members of a student group and allocates those as an array of $students
Later the script will need to take those usernames and input them into a URL
$students = Get-ADGroupMember -Identity "GG_LHS All Students" | Select-Object -ExpandProperty SamAccountName | Sort-Object SamAccountName
foreach ($student in $students)
{
foreach ($OneDriveAdmin in $OneDriveAdmins)
Set-SPOUser -Site https://mydomain-my.sharepoint.com/personal/$($student)_mydomain_co_uk
In the cases where we have duplicate usernames, our naming scheme adds increments in the format of .1 and .2, but I need to change the ".1" to a "_1" to work in the URL.
My initial thinking is an IF statement during the $students declaration
IF SamAccountName is like '.1' replace '.1' with '_1'
Is this possible to do via powershell?
To offer a streamlined alternative to Santiago Squarzon's helpful answer, using the (also regex-based) -replace operator:
# Sample student account names
$students = 'jdoe.1', 'jsixpack', 'jroe.2'
# Transform all names, if necessary, and loop over them.
foreach ($student in $students -replace '\.(?=\d+$)', '_') {
$student
}
Regex notes: \. matches a verbatim ., and (?=...) is a look-ahead assertion that matches one or more (+) digits (\d) at the end ($) of the string. What the look-ahead assertion matches doesn't become part of the overall match, so it is sufficient to replace only the . char.
Output:
jdoe_1
jsixpack
jroe_2
Note:
-replace - like -match accepts an array as its LHS, in which case the operation is performed on each element, and a (usually transformed) new array is returned.
If the regex on the RHS in a given replacement operation doesn't match, the input string is passed through (returned as-is), so it is safe to attempt replacement on strings that don't match the pattern of interest.
You could add this check in your loop, if student matches a dot followed by any amount of digits (\.(\d+)), replace for the same digits but prepending and underscore instead (-replace $Matches[0], "_$($Matches[1])"):
foreach($student in $students) {
if($student -match '\.(\d+)$') {
$student = $student -replace $Matches[0], "_$($Matches[1])"
}
# rest of your code here
}
See https://regex101.com/r/fZAOur/1 for more info.

question about powershell text manipulation

I apologise for asking the very basic question as I am beginner in Scripting.
i was wondering why i am getting different result from two different source with the same formatting. Below are my sample
file1.txt
Id Name Members
122 RCP_VMWARE-DMZ-NONPROD DMZ_NPROD01_111
DMZ_NPROD01_113
123 RCP_VMWARE-DMZ-PROD DMZ_PROD01_110
DMZ_PROD01_112
124 RCP_VMWARE-DMZ-INT.r87351 DMZ_TEMPL_210.r
DMZ_DECOM_211.r
125 RCP_VMWARE-LAN-NONPROD NPROD02_20
NPROD03_21
NPROD04_22
NPROD06_24
file2.txt
Id Name Members
4 HPUX_PROD HPUX_PROD.3
HPUX_PROD.4
HPUX_PROD.5
i'm trying to display the Name column and with this code i'm able to display the file1.txt correctly.
PS C:\Share> gc file1.txt |Select-Object -skip 1 | foreach-object { $_.split(" ")[1]} | ? {$_.trim() -ne "" }
RCP_VMWARE-DMZ-NONPROD
RCP_VMWARE-DMZ-PROD
RCP_VMWARE-DMZ-INT.r87351
RCP_VMWARE-LAN-NONPROD
However with the file2 im getting a different output.
PS C:\Share> gc .\file2.txt |Select-Object -skip 1 | foreach-object { $_.split(" ")[1]} | ? {$_.trim() -ne "" }
4
changing the code to *$_.split(" ")[2]}* helps to display the output correctly
However, i would like to have just 1 code which can be apply for both situation.appreciate if you can help me to sort this.. thank you in advance...
This happens because the latter file has different format.
When examined carefully, one notices there are two spaces between 4 and HPUX_PROD strings:
Id Name Members
4 HPUX_PROD HPUX_PROD.3
^^^^
On the first file, there is a single space between number and string:
Id Name Members
122 RCP_VMWARE-DMZ-NONPROD DMZ_NPROD01_111
^^^
As how to fix the issue depends if you need to match both file formats, or if the other has simply a typing error.
The existing answers are helpful, but let me try to break it down conceptually:
.Split(" ") splits the input string by each individual space character, whereas what you're looking for is to split by runs of (one or more) spaces, given that your column values can be separated by more than one space.
For instance 'a b'.split(' ') results in 3 array elements - 'a', '', 'b' - because the empty string between the two spaces is considered an element too.
The .NET [string] type's .Split() method is based on verbatim strings or character sets and therefore doesn't allow you to express the concept of "one ore more spaces" as a split criterion, whereas PowerShell's regex-based -split operator does.
Conveniently, -split's unary form (see below) has this logic built in: it splits each input string by any nonempty run of whitespace, while also ignoring leading and trailing whitespace, which in your case obviates the need for a regex altogether.
This answer compares and contrasts the -split operator with string type's .Split() method, and makes the case for routinely using the former.
Therefore, a working solution (for both input files) is:
Get-Content .\file2.txt | Select-Object -Skip 1 |
Foreach-Object { if ($value = (-split $_)[1]) { $value } }
Note:
If the column of interest contains a value (at least one non-whitespace character), so must all preceding columns in order for the approach to work. Also, column values themselves must not have embedded whitespace (which is true for your sample input).
The if conditional both extracts the 2nd column value ((-split $_)[1]) and assigns it to a variable ($value = ), whose value then implicitly serves as a Boolean:
Any nonempty string is implicitly $true, in which case the extracted value is output in the associated block ({ $value }); conversely, an empty string results in no output.
For a general overview of PowerShell's implicit to-Boolean conversions, see this bottom section of this answer.
Since this sort-of looks like csv output with spaces as delimiter (but not quite), I think you could use ConvertFrom-Csv on this:
# read the file as string array, trim each line and filter only the lines that
# when split on 1 or more whitespace characters has more than one field
# then replace the spaces by a comma and treat it as CSV
# return the 'Name' column only
(((Get-Content -Path 'D:\Test\file1.txt').Trim() |
Where-Object { #($_ -split '\s+').Count -gt 1 }) -replace '\s+', ',' |
ConvertFrom-Csv).Name
Shorter, but because you are only after the Name column, this works too:
((Get-Content -Path 'D:\Test\file2.txt').Trim() -replace '\s+', ',' | ConvertFrom-Csv).Name -ne ''
Output for file1
RCP_VMWARE-DMZ-NONPROD
RCP_VMWARE-DMZ-PROD
RCP_VMWARE-DMZ-INT.r87351
RCP_VMWARE-LAN-NONPROD
Output for file2
HPUX_PROD

How to trim string until first capital letter

Here is my issue. If I type $env:UserName, the output is JoeDow
What I need is to trim this string from the end until the first capital character.
The output should be JoeD
I tried everything and had no luck
Thanks in advance
M
RegEx is amazing, but simple in this case:
$String = 'JoeDow'
$String -creplace '[a-z]+$'
This simply says case sensitively replace any lowercase character from a-z that's at the end of the string.
In your case:
$env:USERNAME -creplace '[a-z]+$'
Note: There are lots of ways I can think of doing this. The particular approach above assumes there's 2 Capital letters and we want to chop only the lowercase letters after the last capital letter. If you give it a string like 'Joe' it will return "J", because it'll replace the trailing lowercase letters just the same. Therefore if this is not a super-consistent scenario we'd likely have to go another route.
Update, Building on Sage's nice example
If you use .LastIndexOfAny(), again with assurance the format is stable, you can nail it in very few lines:
$String = "JoeDow"
$CapitalLetters = [Char[]](65..90)
$String.Substring(0, ($String.LastIndexOfAny($CapitalLetters) +1 ))
This relies on the last capital not the second capital. Again, it depends on how reliable the pattern your expecting is.
Another RegEx Approach:
$String = "JoeDow"
$String = -join ($String -csplit "([A-Z])")[1..3]
$String
This one uses capital letters as the delimiter, however the parens instructs the -csplit operator to return the delimiter in the array. So, by picking the correct range we can be sure to grab "J" + "oe" + "D". Unlike the other examples this uses the 2nd capital, not necessarily the last. While the other chose the last which was not necessarily the 2nd.
You can easily get an array of all the capital letters in Powershell with [char[]](65..90)
From there, using .IndexOfAny method, you can gather the position of the second capital letter and use the substring method to select the string from its beginning to the second capital letter exclusively.
That would look like this.
Function Get-TrimmedName($Name) {
$CapitalLetters = [char[]](65..90)
$SecondCapEndIndex = $Name.IndexOfAny($CapitalLetters, 1) + 1
$TrimmedName = $Name
if ($SecondCapEndIndex -gt 0 -and $SecondCapEndIndex -lt $Name.Length) {
$TrimmedName = $Name.Substring(0, [int]$SecondCapEndIndex)
}
return $TrimmedName
}
Get-TrimmedName -Name 'JoeDow' # returns JoeD
Get-TrimmedName -Name 'MaxD' # returns MaxD
Get-TrimmedName -Name 'Max' # returns Max
Get-TrimmedName -Name 'PatrickDesjardins' # returns PatrickD
Now, just because fun needed to be had, here is a more complex version that will go futher and work with more complex name such as JohnDoeDawson (Would return JohnDD), allow you to get initials out of it (eg: JohnDoeDawson = JDD) and even convert names to Title cases on the fly (eg: "john doe dawson" = JohnDD)
<#
.SYNOPSIS
Get the trimmed version of a name.
.DESCRIPTION
Returns the complete first name and the trimmed down last names (First letter only)
.PARAMETER Name
Name to be trimmed.
.PARAMETER Initials
If set, only the initials will be returned.
.PARAMETER TitleCase
If set, the name passed down will be converted to TitleCase first. It is good to be noted that names with no
spaces will loose any capitals after the First letter (eg: JohnDoe -> Johndoe) so it is best used when the name is formatted
with spaces.)
.EXAMPLE
An example
.NOTES
General notes
#>
Function Get-TrimmedName([String]$Name, [Switch]$Initials, [Switch]$TitleCase) {
$CapitalLetters = [char[]](65..90)
$Index = 0
$output = [System.Text.StringBuilder]::new()
if ($TitleCase) {
$Ti = [cultureinfo]::CurrentCulture.TextInfo
$Name = $Ti.ToTitleCase($Name)
}
$MyCapLetters =
while ($true) {
$Index = $Name.IndexOfAny($CapitalLetters, $Index)
if ($Index -eq -1) { break }
$Index
$Index += 1
}
if ($Initials) {
if ($MyCapLetters.Count -eq 0) {
return $Name[0]
}
Foreach ($C in $MyCapLetters) { $Output.Append($Name.Substring($C, 1)) | Out-Null }
return $Output.ToString()
}
$MyCapLetters = $MyCapLetters.Where( { $_ -gt 0 })
if ($MyCapLetters.Count -gt 0) {
$output.Append($Name.Substring(0, $MyCapLetters[0] + 1)) | Out-Null
}
else {
return $Name
}
foreach ($C in $MyCapLetters | Select-Object -Skip 1) {
$output.Append($Name.Substring($C, 1)) | Out-Null
}
return $output.ToString()
}
Now some examples of this more complex function
#Base example
Get-TrimmedName -Name JohnDoe # Returns JohnD
# Works with complex names
get-trimmedname 'PatrickDesjardinsPowell' # returns PatrickDP
#Initials only
get-trimmedname 'PatrickDesjardinsPowell' -Initials # Returns PDP
#TitleCase - if the name contains spaces
get-trimmedname -name "John doe" -TitleCase #Returns JohnD
get-trimmedname -name "john doe" -TitleCase #Returns JohnD
# Do not use titlecase if the name is in 1 word
# TitleCase behavior is to find word boundaries so "jOHNDoe" would get converted to Johndoe since
# considered as a single word.
get-trimmedname -name "JohnDoe" -titlecase #Returns Johndoe
References
MSDN - .Net String.IndexOfAny Method
MSDN - .Net String.Substring Medhod
MSDN - Everything about arrays - Powershell - Special Index tricks
OK, I need to add some more information. I'm going to run this script on the remote machine via Intune. The problem is if I put a full email address in the script - all good, but if I use a variable like $env:username it pickup system credentials, and the script failed. Is any way to get a username on the remote machine using Intune? It will be executed on a couple of computers. Thanks