Powershell - keep specific word in a string - powershell

I'm doing AD extract and I sort the field "distinguishedname" and I want to keep only a specific part of the value that represent the "parent OU" of the user itself.
I'm running this command to do an add extract of all users:
import-module activedirectory
get-aduser -filter * -properties *| Select-Object -Property SamAccountName,CN,co,ExtensionAttribute10,extensionAttribute11,extensionAttribute12,EmailAddress,whenCreated,Enabled,LastLogonDate,accountexpirationdate,distinguishedname |Sort-Object -Property Name | Export-Csv -Delimiter ";" -path "u:\theOutFile_NOFILTER_July.txt"
The column "distinguishedname" look like this:
distinguishedname
CN=familly\, user,OU=Remote Users,OU=New York,OU=My,DC=Company,DC=Local
CN=nameless\, cat,OU=Remote Users,OU=Ottawa,OU=My,DC=Company,DC=Local
CN=Cameron\, James,OU=Regular Users,OU=Hollywood,OU=My,DC=Company,DC=Local
CN=Bon\, Jean,OU=regular Users,OU=Springfield,OU=My,DC=Company,DC=Local
Note July 10
some time I will hit those line:
CN=Dog\, Cesar,OU=Special Accounts,OU=Regular Users,OU=Alma,OU=My,DC=Company,DC=Local
CN=keys\, Alicia,OU=Special Accounts,OU=Regular Users,OU=Paris,OU=My,DC=Company,DC=Local
CN=Clansy\, Door,OU=Map Drives,OU=Remote Users,OU=Rome,OU=My,DC=Company,DC=Local
In those case I am getting result such Remote Users an Regular Users instead of the City. I've tried some modification in your command you gave but in vain.
But I would like the first command to return this result instead:
distinguishedname
New York
Ottawa
Hollywood
Springfield
I can't effort to find how.
thanks in advance

Select-Object has a very versatile feature to create calculated properties using a hash in the place of a property name, where the key "Name" is set to the name of the calculated property (effectively, the column heading), and "Expression" is set to a code block that determines the value of the property, for each object in the pipeline. This will do what you want:
Get-Aduser -Filter * -Properties * | Select-Object -Property SamAccountName,CN,co,ExtensionAttribute10,extensionAttribute11,extensionAttribute12,EmailAddress,whenCreated,Enabled,LastLogonDate,accountexpirationdate,#{Name='distinguishedname'; Expression={[regex]::match($_.distinguishedname,'OU=.+?OU=(.+?),(OU|DC)=').Groups[1].Value}} | Sort-Object -Property Name | Export-Csv -Delimiter ";" -Path "u:\theOutFile_NOFILTER_July.txt"
Here's a breakdown what's going on:
Name='distinguishedname' tells it to create a new column called 'distinguishedname'. I used that name to match your example of the output you're looking for, but it doesn't have to be the name of an existing property. It would probably make more sense to change the name to something more descriptive of the values you're calculating, e.g. Name="parentOU".
[regex]::match is used to extract the desired portion from $_.distinguishedname using the regular expression OU=.+?OU=(.+?),(OU|DC)=, which isolates the name of the second OU in the list using a match group.
.Groups[1].Value returns the value of the first match group (the part matched by the contents of the first set of parentheses). .Value on its own without .Groups[1] would return the entire matched string, from the first OU= to the = following name of the parent OU. The following would work just as well, using zero-width assertions instead of a match group: [regex]::match($_.distinguishedname,'(?<=OU=.+?OU=).+?(?=,(OU|DC)=)').Value

Related

Powershell - add extra column called RoleUserA* inside CSV file

I want to add an extra, empty column called RoleUserA* to a CSV file, as attempted below. RoleUserA* is not an AD Attribute.
Get-ADUser -Filter {Enabled -eq $true} -Properties * |
Select givenName, sn, displayname, samaccountname, RoleUserA*, title |
Export-Csv -Path "c:\tmp\users.csv" -NoTypeInformation -Encoding UTF8
Desired output:
givenName,sn,displayname,samaccountname,RoleUserA*,title
user01,sn1,User01 SN,user01,,specialist
user02,sn2,User02 SN,user02,,specialist
However, RoleUserA* isn't being added as a column.
The (positionally implied) -Property parameter of the Select-Object cmdlet (whose built-in alias is select) interprets its arguments as wildcard expressions.
Therefore, RoleUserA* looks for existing properties on the input objects whose name starts with RoleUserA - and simply adds none to the output objects if no existing property matches; a simple example:
# Because 'bar*' matches no existing properties, it is *ignored*.
PS> [pscustomobject] #{ foo = 1 } | Select-Object foo, bar*
foo
---
1
While escaping * as `* ('RoleUserA`*') so that it is used literally, as a (non-existent, in this case) property name, should be possible, it unfortunately isn't as of PowerShell 7.2.2,[1] as Mathias R. Jessen points out, and he also points to the solution that does work:
Use a calculated property, whose Name entry (shortened to n below) is always treated literally; using { $null } as the Expression (e) entry script block creates the property with value $null:[1]
Get-ADUser -Filter 'Enabled -eq $true' -Properties * |
Select givenName, sn, displayname, samaccountname, #{n='RoleUserA*';e={ $null }}, title |
Export-Csv -Path "c:\tmp\users.csv" -NoTypeInformation -Encoding UTF8
Note: In scripts used long-term, it's better to spell out the entry keys of the calculated property in full, i.e.:
#{ Name = 'RoleUserA*'; Expression = { $null } }
[1] This should be considered a bug, or at least needs documenting - see GitHub issue #17068
[2] Using just { } - i.e. an empty script block, almost works the same, but it actually creates an "Automation Null" value (the System.Management.Automation.Internal.AutomationNull.Value singleton), which in expressions behaves the same as $null, but acts differently in a pipeline - see this answer for more information.
That said, in the context of converting to CSV this difference won't matter.

PowerShell pipe ExpandProperty to another Select-Object

I want to get the aliases for all email recipients in my O365 tenant.
If I were doing this one traditional Exchange, the easiest is to Get-Recipient and pull out the SMTPAddress property using Exchange Manangement Console. (Note the Select piped into another Select; works like a champ.)
Get-Recipient | Select Name,SamAccountName -ExpandProperty EmailAddresses | Select Name,SamAccountName,SmtpAddress
The issue is when I try to do the same thing in EXO, the "EmailAddresses" property is output as a flat string and so when I try to pipe it to a 2nd select, the only Property is the Length, not the actual value of the string.
The following kind of works, but I feel like there has to be a better way?
Get-EXORecipient | Select Name -ExpandProperty EmailAddresses | % {Write-Output "$($_.Name),$($_)"}
What -ExpandProperty EmailAddresses expands to are strings, as you state.
The additional properties that these strings are decorated with if you also pass (positionally implied) -Property arguments, such as Name in your example, are present, but will typically not surface unless you explicitly access them on the now-decorated output strings.
If you want output objects that contain each email address as a property, more work is needed.
Get-EXORecipient | ForEach-Object {
foreach ($emailAddress in $_.EmailAddresses) {
[pscustomobject] #{
EmailAddress = $emailAddress
Name = $_.Name
# ... add further properties of interest here
}
}
}

Multiple rows in a grid [duplicate]

This question already has answers here:
Export hashtable to CSV with the key as the column heading
(2 answers)
Closed 4 years ago.
I'm trying to list all ad group memberships of specific users. The input would be a string of logins split with a comma 'login1,login2'.
So I go over each user and list their memberships with the username as title. Somehow it only shows the first entry. Also it shows the user groups in one row and I don't know how to change that.
Code below:
$users = $logon -split ','
$q = #()
foreach ($user in $users) {
$usernm = Get-ADUser -Filter 'samAccountName -like $user' | select Name
$useraccess = Get-ADPrincipalGroupMembership $user | Select-Object Name
$userobj = New-Object PSObject
$userobj | Add-Member Noteproperty $usernm.Name $useraccess.Name
$q += $userobj
}
Expected output would be something like:
fullnameuser1 fullnameuser2 list of users goes on...
------------- ------------- ------------------------
adgroup1 adgroup3 ...
adgroup2 adgroup4
... ...
In principle this would also mean that if i typed $q.'fullnameuser1' output would be:
fullnameuser1
-------------
adgroup1
adgroup2
...
Whenever the code is ran, it will only ever add the first user's access, also returning all groups on one row. So somehow I need to go over all the group memberships and add a row for each one.
First and foremost, PowerShell does not expand variables in single-quoted strings. Because of that Get-ADUser will never find a match unless you have a user with the literal account name $user. Also, using the -like operator without wildcards produces the same results as the -eq operator. If you're looking for an exact match use the latter. You probably also need to add nested quotes.
Get-ADUser -Filter "samAccountName -eq '${user}'"
Correction: Get-ADUser seems to resolve variables in filter strings by itself. I verified and the statement
Get-ADUser -Filter 'samAccountName -eq $user'
does indeed return the user object for $user despite the string being in single quotes.
If you want a fuzzy match it's better to use ambiguous name resolution.
Get-ADUser -LDAPFilter "(anr=${user})"
You may also want to avoid appending to an array in a loop, and adding members to custom objects after creation. Both are slow operations. Collect the loop output in a variable, and specify the object properties directly upon object creation.
$q = foreach ($user in $users) {
...
New-Object -Type PSObject -Property {
$usernm.Name = $useraccess.Name
}
}
Lastly, I'd consider using the user's name as the property name bad design. That would be okay if you were building a hashtable (which is mapping unique keys to values), but for custom objects the property names should be identical for all objects of the same variety.
New-Object -Type PSObject -Property {
Name = $usernm.Name
Group = $useraccess.Name
}
Basily query all the users and store it in $users, example:
Get-ADUser -Filter * -SearchBase "dc=domain,dc=local"
And then you can export the results as csv or a table.
To Export as CSV :
Get-ADPrincipalGroupMembership <Username> | select name, groupcategory, groupscope | export-CSV C:\data\ADUserGroups.csv`
To Format the result as Table in the console itslef :
Get-ADPrincipalGroupMembership <Username> | select name, groupcategory, groupscope | Format-Table

Need to split (cutout a part of) the result of a powershell command into a CSV

I have a command that spits outs Active Directory SamAccountName, Description, Distinguished name into a CSV. My issue is that I only need the part of the distinguished name after the user name. I know this is conceptually simple, but I don't know enough about using Splits to get the results.
Here is my command:
get-content users.txt | get-aduser -pr
SamAccountName,Description,DistinguishedName | select
SamAccountName,Description,DistinguishedName | Export-Csv users.csv
Here is my output:
Line1-- "user1","user1 description","CN=Lastname\, Firstname(user1),OU=OU2,OU=OU1,OU=Site-1,OU=Accounts_User,DC=domain,DC=company,DC=com"
Line2--- "user2","user2 description","CN=Lastname\, Firstname,OU=OU1,OU=Site-2,OU=Accounts_User,DC=domain,DC=company,DC=com"
What I need is to drop the CN=username2(username2), part of the result. So that my output looks like:
"user2","user2 description","OU=OU1,OU=Site-2,OU=Accounts_User,DC=domain,DC=company,DC=com"
You can use Select-Object dynamic expressions to manipulate a property and return that as part of your results, by constructing a select expression like:
Select-Object #{Name="NewName"; Expression={..any scriptblock..}}
In your case, I would remove the unwanted string part with a regex, by matching the CN=([^=]*),OU= and leaving only the OU= part only:
$_.DistinguishedName -ireplace "CN=([^=]*),OU=","OU="
So Altogether:
get-content users.txt |
get-aduser -pr SamAccountName,Description,DistinguishedName |
Select SamAccountName,Description, #{Name="NewDN"; Expression={$_.DistinguishedName -ireplace "CN=([^=]*),OU=","OU="}} |
Export-Csv users.csv

Why is this not working? - Trying to save properties in a variable for use multiple times in a function

I am trying to find a way to save the properties for a select statement in PowerShell but it isn't working. I haven't found a way to make an entire statement a literal so that it isn't reviewed until the variable is opened.
Here is what works:
$wsus.GetSummariesPercomputerTarget($CurrentMonthUpdateScope, $ComputerScope) |
Select-Object #{L="WSUSServer";E={$Server}},
#{L="FromDate";E={$($CurrentMonthUpdateScope.FromCreationDate).ToString("MM/dd/yyyy")}},
#{L="ToDate";E={$($CurrentMonthUpdateScope.ToCreationDate).ToString("MM/dd/yyyy")}},
#{L='Computer';E={($wsus.GetComputerTarget([guid]$_.ComputerTargetID)).FullDomainName}},
DownloadedCount,
NotInstalledCount,
InstalledPendingRebootCount,
FailedCount,
Installedcount |
Sort-Object -Property "Computer"
and I am trying to get the properties mentioned (starting just after the Select-Object statement and ending just before the last pipe) placed in a variable so that I can use the same properties multiple times with different scopes.
I have tried this:
$Properties = '#{L="WSUSServer";E={$Server}},
#{L="FromDate";E={$($CurrentMonthUpdateScope.FromCreationDate).ToString("MM/dd/yyyy")}},
#{L="ToDate";E={$($CurrentMonthUpdateScope.ToCreationDate).ToString("MM/dd/yyyy")}},
#{L="Computer";E={($wsus.GetComputerTarget([guid]$_.ComputerTargetID)).FullDomainName}},
DownloadedCount,
NotInstalledCount,
InstalledPendingRebootCount,
FailedCount,
Installedcount'
$wsus.GetSummariesPercomputerTarget($CurrentMonthUpdateScope, $ComputerScope) |
Select-Object $Properties |
Sort-Object -Property "Computer"
While this runs it doesn't give any data and I think it confuses PowerShell.
This gives the same response:
$Properties = "#{L=`"WSUSServer`";E={$Server}},
#{L=`"FromDate`";E={$($CurrentMonthUpdateScope.FromCreationDate).ToString(`"MM/dd/yyyy`")}},
#{L=`"ToDate`";E={$($CurrentMonthUpdateScope.ToCreationDate).ToString(`"MM/dd/yyyy`")}},
#{L=`"Computer`";E={($wsus.GetComputerTarget([guid]$_.ComputerTargetID)).FullDomainName}},
DownloadedCount,
NotInstalledCount,
InstalledPendingRebootCount,
FailedCount,
Installedcount"
Any options, thoughts, etc.?
The -Property argument of Select-Object expects an array, not a string. So something like this:
$Properties = #(#{L="WSUSServer";E={$Server}},
#{L="FromDate";E={$($CurrentMonthUpdateScope.FromCreationDate).ToString("MM/dd/yyyy")}},
#{L="ToDate";E={$($CurrentMonthUpdateScope.ToCreationDate).ToString("MM/dd/yyyy")}},
#{L="Computer";E={($wsus.GetComputerTarget([guid]$_.ComputerTargetID)).FullDomainName}},
"DownloadedCount",
"NotInstalledCount",
"InstalledPendingRebootCount",
"FailedCount",
"Installedcount")
Note, you will need to turn the simple property names into strings within your array.