How to bring in the original string after comparison - powershell

this is the first time I ask a question. I'm a foreigner and I'm not good at english. so it's a little bit hard to explain my question. Maybe my title is wrong too...
I am trying to compare all the names and info in Active Directory with the time, and then add them to the group,but the info has "WIFI" and numbers,So I a regex the info and compared it with time
$time = Get-Date -Format "yyyyMMdd"
$ccc = Get-ADUser -Filter {info -like "WIFI*" }-properties name,info | select name,info
$bbbs = $ccc -replace '\D+([0-9]*).*','$1'
Get-ADUser -Filter {info -like "WIFI*" }-properties name,info | select name,info | export-csv -path c:\test.csv -NoTypeInformation -Encoding "UTF8"
Import-CSV "C:\test.csv" | % {Add-ADGroupMember -Identity namegroup -Members $_.Name}
$bbbs -lt $time
The output of $ccc is here
name info
---- ----
mike WIFI-20210515 VPN-20210512
terry WIFI-20210519 VPN-20210519
hack WIFI-20210530 VPN-20210513
The output of $bbbs is here
20210515
20210519
20210530
But I don't know how to WIFI-"datatime" is less than the current date, remove it from the group.(
I joined the group using a CSV file)
I can't figure out how to do it.

Although it is still very unclear what (date) numbers from info you want to compare, but one way of doing what I think you want to achieve can be:
# get the reference date as DateTime object
$refDate = (Get-Date).Date # today at midnight
# better keep the returned ADUsers objects complete, with added 'Info' property
# if you want to add them to a Group. By default, Get-ADUser returnes these properties:
# DistinguishedName, Enabled, GivenName, Name, ObjectClass, ObjectGUID, SamAccountName, SID, Surname, UserPrincipalName
$users = Get-ADUser -Filter "Info -like 'WIFI*'" -Properties Info |
# for convenience, also add a custom property 'WifiDate' converted to DateTime object to compare against.
# if you need to use the other date (the one after "VPN-"), then change below `$1` to `$2`
Select-Object *, #{Name = 'WifiDate'; Expression = {[datetime]::ParseExact(($_.Info -replace '^WIFI-(\d{8}).*(\d{8})', '$1'), 'yyyyMMdd', $null)}}
# next filter to get all users that have a 'WifiDate' earlier than today
$usersToAddToGroup = $users | Where-Object { $_.WifiDate -lt $refDate }
Now you can add these to an AD group using something like:
Add-ADGroupMember -Identity 'TheNameOfTheGroup' -Members $usersToAddToGroup
Of course, if you want to remove those users from the group, replace Add-GroupMember with Remove-ADGroupMember
Regex details:
^ Assert position at the beginning of the string
WIFI- Match the characters “WIFI-” literally
( Match the regular expression below and capture its match into backreference number 1
\d Match a single digit 0..9
{8} Exactly 8 times
)
. Match any single character that is not a line break character
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
( Match the regular expression below and capture its match into backreference number 2
\d Match a single digit 0..9
{8} Exactly 8 times
)

Related

Whitespace & $null variable handling in PowerShell?

I'm trying to create a script that will grab all users in an OU and change the current primary alias to a secondary alias while adding a new primary smtp address and retaining any other secondary aliases. We have users with 0 aliases, some with 1, some with 2, and some with 3. I am running into an issue when any one of the $sp1, $sp2, $sp3, $sp4, $sp5 are either white space or null. I'm still learning powershell so I'm not sure how to handle that without a lot of pain lol.
$Users = Get-AdUser -Filter * -SearchBase "OU=TestScriptedSMTPAddrChange,OU=***,DC=***,DC=com" -Properties proxyAddresses | Select-Object SamAccountName, proxyAddresses #Change first OU= to the OU you want to change
Foreach ($SAN in $Users){
$SecondaryProxyRaw = $SAN.proxyAddresses #grab proxyAddresses and dump them
$SecondaryProxyRed = $SecondaryProxyRaw.replace('SMTP','smtp') #change primary SMTP addr to secondary smtp addr
$sp1,$sp2,$sp3,$sp4,$sp5 = $SecondaryProxyRed.split(" ",1) #split the proxyAddresses array into variables
$NewPrimaryProxy = "SMTP:$($SAN.SamAccountName)#newdomain.com"} #assign new primary SMTP address
Set-ADUser -Identity $SAN.SamAccountName -replace #{proxyAddresses = "$NewPrimaryProxy","$sp1","$sp2","$sp3","$sp4","$sp5"}
}
Get-AdUser -Filter * -SearchBase "OU=TestScriptedSMTPAddrChange,OU=***,DC=***,DC=com" -Properties proxyAddresses | Select-Object SamAccountName, UserPrincipalName, #{Name="Proxyaddresses";Expression={$_.proxyAddresses -join "*"}}
You should not rely on a user having 1, 3 or perhaps 77 addresses in its proxyAddresses attribute by trying to split these into a fixed number of variables.
Just get them all, replace the uppercase SMTP: into lowercase 'smtp:', filter out the possible one that would be equal to the new proxy address and add the new primary address to the array.
Then, replace the entire proxyAddresses array with the strongly typed (i.e. cast to string[]]) new array.
$Users = Get-AdUser -Filter * -SearchBase "OU=TestScriptedSMTPAddrChange,OU=***,DC=***,DC=com" -Properties proxyAddresses
foreach ($SAN in $Users) {
$NewPrimaryProxy = 'SMTP:{0}#newdomain.com' -f $SAN.SamAccountName
# if you like you can sort the proxies but for the system this will have no effect
$proxies = #($SAN.ProxyAddresses -replace '^SMTP:', 'smtp:' | Where-Object { $_ -ne $NewPrimaryProxy }) + $NewPrimaryProxy
# Note: proxyAddresses needs a Strongly typed string array, that is why we cast $proxies array with [string[]]
$SAN | Set-ADUser -Replace #{proxyAddresses = [string[]]$proxies}
}
.split(" ",1)
doesn't split at all - by definition it returns the input string as-is, because you're asking for 1 token only - see the docs for the .NET [string] type's .Split() method.
To split by runs of whitespace, you can use the unary form of PowerShell's -split operator:
# Split by whitespace and collect tokens in an array.
# -ne '' filters out empty elements, so that if
# $SecondaryProxyRed is effectively empty, $sps becomes an empty array.
$sps = -split $SecondaryProxyRed -ne ''
You can then create an array with $NewPrimaryProxy as the first element, followed by the elements of $sps, if any:
Set-ADUser -Identity $SAN.SamAccountName -replace #{
proxyAddresses = #($NewPrimaryProxy) + $sps
}

Filter Records on Multiple Values

I have to get a list of AD users where the Manager field contains one of the following names on my FilterValues list.
I see that someone recommended to use the Where-Object, however when I run the script nothing gets returned. I have tried many approaches but I can't seem to find where I am going wrong. Any advise will be greatly appreciated, TIA.
$FilterValues = $('Williams', 'Smith', 'Johnson')
Get-ADUser -Filter "extensionAttribute10 -like '1.0'" -Properties *
| Where-Object {$_.Manager -contains $FilterValues}
| Format-Table Name, Manager
*** If I run the script without the Where-Object portion I get values back.
The -contains is for testing values in an array, unlike the string .Contains() method. In this case, I'd suggest using the regex -match operator like this:
# an array of manager names
$FilterValues = 'Williams', 'Smith', 'Johnson'
# create a regular expression of the manager names by combining them with the regex OR symbol '|'
# the [regex]::Escape() is there to make sure characters that have special meaning in regex are escaped.
$regexManagers = ($FilterValues | ForEach-Object { [regex]::Escape($_) }) -join '|'
Get-ADUser -Filter "extensionAttribute10 -like '1.0'" -Properties Name, Manager |
Where-Object {$_.Manager -match $regexManagers } |
Format-Table
P.S. It is always a bad idea to search for ALL properties with -Properties * when you only want two properties returned.

powershell get-aduser specific date range

Hello and thank you for taking the time to read this.
I am writing a program that will look back at a certain date range and then return the values that I specify in a get-aduser cmdlet
The code I have thus far is here:
$grabDate = Read-Host 'enter how many days back you want to search'
$date = Get-Date
$desiredDate = $date.AddDays(- $grabDate)
Write-Host $desiredDate 'to' $date 'is your search range'
Pause
Get-ADUser -Filter * -Properties Name, LastLogonDate | Where-Object { $date.AddDays(- $grabDate) } | Select-Object name, LastLogonDate
I know that this is not the cleanest code and there are some redundant steps my main focus is on the line:
Get-ADUser -Filter * -Properties Name, LastLogonDate | Where-Object { $date.AddDays(- $grabDate) } | Select-Object name, LastLogonDate
when I enter 30 days to search back, I am getting strange entries from 2016, does anyone see anything strange with my code?
No need for the pipeline here - just use a little simple math, a conversion from string to int, and use the -Filter parameter as it was designed.
Set $grabDate like this, so you get an actual int value, not a string
# Convert Read-Host input to an integer, and multiply by -1 to get the negative value
$grabDate = [Convert]::ToInt32( (Read-Host 'enter how many days back you want to search' ) ) * -1
Then call Get-ADUser with the following -Filter parameter:
# Use the filter to return only the users who haven't logged on in the
# last $grabDate days
Get-ADUser -Filter "LastLogonDate -ge '$((Get-Date).AddDays( $grabDate ))'"
This way, you only return the ADUsers you care about and you don't have to process the list of users a second time. Using -Filter * can be a costly operation, especially in larger AD environments.
Import-Module ActiveDirectory
# Set the number of days since last logon
$DaysInactive = 90
$InactiveDate = (Get-Date).Adddays(-($DaysInactive))
#-------------------------------
# FIND INACTIVE USERS
#-------------------------------
# Below are four options to find inactive users. Select the one that is most appropriate for your requirements:
# Get AD Users that haven't logged on in xx days
$Users = Get-ADUser -Filter { LastLogonDate -lt $InactiveDate -and Enabled -eq $true } -Properties LastLogonDate | Select-Object #{ Name="Username"; Expression={$_.SamAccountName} }, Name, LastLogonDate, DistinguishedName

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

Using PowerShell to generate a unique username in AD

I'm writing a script to be used by help desk staff to quickly (and accurately) create AD user accounts by inputting basic employee information. We use portions of a persons name in order to create the samAccountName. Which I've achieve by the following.
$GivenName = "Joe"
$Surname = "Smith"
$SamAccountName = $Surname.substring(0, [System.Math]::Min(5, $Surname.Length)) + $GivenName.Substring(0,1)
This works great as long as there isn't already a "Joe Smith" (or John or Jennifer Smithers, etc). The solution would be to add a number to the end. When manually creating accounts the help desk would search AD look at what number suffix to use if necessary. I'm trying to figure out how PowerShell can do that for us. I've gone through several ideas with help from what I've found online but so far I've been unsuccessful.
My first thought was to do something like this.
$SamSuffix = 2
If ((Get-ADUser -LDAPFilter "(SamAccountName=$samAccountName)")-eq $Null)
{
"$SamAccountName does not exist in AD" #out result for testing.
}
Else{
do
{
Get-ADUser -LDAPFilter "(SamAccountName=$SamAccountName + $SamSuffix++)"
}
until (Get-ADUser -LDAPFilter "(SamAccountName=$SamAccountName + $SamSuffix)")-eq $Null)
}
This obviously doesn't work. Even if it did I don't know how I'd get to the 'next step' to create the account.
I also tried pulling the existing names into a list
$SamExist = (Get-ADUser -LDAPFilter "(SamAccountName=$SamAccountName*)" | Select SamAccountName)
do {$SamAccountName + $SamSuffix++}
until ($SamExist -notcontains $SamAccountName -or $SamAccountName + $SamSuffix)
This also doesn't work but if it did I can see that it would automatically add the suffix even if it wasn't needed.
You approach where you get all the existing matches first would be where I would start. Lets assume $SamAccountName is smithj
$existingAccounts = Get-ADUser -Filter "samaccountname -like '$SamAccountName*'" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty samaccountname
So $existingaccounts that have a samaccountname's starting with smithj. If there are not any then $existingAccounts would be null and we can test for that.
if($existingAccounts){
# Figure out what the suffix will be
$highestValue = $existingAccounts -replace "^$SamAccountName" |
ForEach-Object{[int]$_} |
Measure-Object -Maximum |
Select-Object -ExpandProperty Maximum
} else {
# Create the user as normal.
}
Pretending there are some accounts that exist we trim the leading characters from the samaccountname, convert the remaining to an integer and select the highest from that. So $highestValue is the last number used in a conflicting account.
Add one to that and you have a guaranteed username you can create assuming nothing changes in those moments i.e. two users making to smithj accounts.
If you are looking to fill gaps where a user might have left and you want to use the next available after 1 then you could do this.
$existingAccounts = "smithj1", "smithj5", "smithj10", "smithj2", "smithj3"
# Figure out what the next unused suffix will be
$existingSuffixes = $existingAccounts -replace "^$SamAccountName" | ForEach-Object{[int]$_}
# Once again determine the maximum one in use
$highestValue = $existingSuffixes | Measure-Object -Maximum | Select-Object -ExpandProperty Maximum
# Find the first gap between 1 and the max suffix
$nextAvailableSuffix = 1..($highestValue + 1) | Where-Object{$existingSuffixes -notcontains $_} | Sort-Object desc | Select -First 1
$nextAvailableSuffix would contain 4 using the above example. We add 1 to highest value in case the only other one is 2 so that way there will only be an answer to $nextAvailableSuffix