How to have powershell go through a list of users and if they exists move them to ou mentioned if not display the username with failed. - powershell

Okay so i have the following code. It works but it returns failed for each user. The first 2 users are supposed to fail but the last one should be success but it should only show all the failed attempts and then place it in a text file. This is what I have so far besides the output to a text file.
Import-Module ActiveDirectory
#$sam = read-host "Enter username"
#$user = Get-ADUser -filter {SamAccountName -eq $sam}
$user = #("user2","user3","olduser2")
foreach($sam in $user){
if(Get-Aduser $sam){
$Name = (Get-ADUser $sam -Properties cn).name
$path = "OU=Term,OU=test,DC=patel,DC=COM"
Get-ADUser $Name | Move-ADObject -TargetPath $path
}
if(!$sam){
Write-Host "$sam failed"
}
It would return
user2 failed
with a an error message because it cant be found
user3 failed
with a an error message because it cant be found
olduser2 failed
without error message.

The iterator variable ($sam) in the ForEach goes out of scope when the ForEach loop exits. At that point, $sam -eq $null is true (equivalent to !$sam), and therefore you will get the failure message. Try
$user = #("user2","user3","olduser2")
foreach($sam in $user){
if(Get-Aduser $sam){
$Name = (Get-ADUser $sam -Properties cn).name
$path = "OU=Term,OU=test,DC=patel,DC=COM"
Get-ADUser $Name | Move-ADObject -TargetPath $path
} else {
Write-Host "$sam failed"
}
}
and see if that gives you the results you want - and if you can understand why it does. There are other improvements you can make in the script, as well - but you should get it working first, then think about optimization.

As Jeff Zeitlin mentioned in the comments of the answer. This would be better to do error checking in a try catch loop.
$user = #("user2","user3","olduser2")
foreach($sam in $user) {
try {
$path = "OU=Term,OU=test,DC=patel,DC=COM"
Get-ADUser $sam -ErrorAction Stop | Move-ADObject -TargetPath $path -ErrorAction Stop
}
catch {
Write-Host "$sam failed"
}
}

Related

Powershell script skipping some users

I have the following script that should run through all identities from Sailpoint IdentityIQ, and remove the membership, but it randomly don't affect users, we saw in the logs that it process one user correctly and then the next one starts but the script then start with the next user not updating the one before.
Can we add a lock or retry until it's done?
Here's the code we already have.
Thank you!
$ADgroups = Get-ADPrincipalGroupMembership -Identity $adUser | where {$_.Name -ne "Domain Users"}
if ($ADgroups -ne $null){
try{
Remove-ADPrincipalGroupMembership -Identity $adUser -MemberOf $ADgroups -Confirm:$false
wlog "info" "Removed all assigned AD groups." $mainfn
} catch { }
}
As already commented, your current code does not output errors, because you do nothing in the catch block. Also, by not specifying -ErrorAction Stop, not all errors will make the code execute whatever is in the catch block..
Try
# assuming the variable $adUser is a valid AD object or the DistinguishedName, GUID, SID or SamAccountName
$ADgroups = Get-ADPrincipalGroupMembership -Identity $adUser | Where-Object {$_.Name -ne "Domain Users"}
# force $ADgroups to be an array here so you can use its .Count property
if (#($ADgroups).Count) {
try {
# append ErrorAction STop to also capture non-terminating errors in the catch block
Remove-ADPrincipalGroupMembership -Identity $adUser -MemberOf $ADgroups -Confirm:$false -ErrorAction Stop
# log success
wlog "info" "Removed all assigned AD groups." $mainfn
}
catch {
# log error
wlog "error" $_.Exception.Message $mainfn
}
}

PowerShell script to query AD and report if UPNs in a CSV file are found

I have a simple script that references a CSV file containing user account UPNs and then removes these users from an AD group.
$CSVFile = Read-Host -Prompt 'Enter the name of the user CSV file (filename.csv)'
$Path = 'C:\scripts'
$UPNs = Import-Csv $Path\$CSVFile
$UIDs = Foreach ($UPN in $UPNs.userprincipalname) {
(Get-Aduser -filter {UserPrincipalName -eq $UPN}).SamAccountName
}
Remove-ADGroupMember "My-AD-Group" -Members $UIDs
The problem is that if the CSV file contains a UPN that isn't in AD, it will fail and give an error referencing that "Members" cannot be a null value. Once I remove the invalid UPN the script will work fine. I would like to add a kind of error check that goes through the UPNs and if one is not found in AD, it won't abort the entire function. I would like it to give an output with a list of the UPNs that couldn't be matched in AD. Thank you in advance for any suggestions.
You can either switch strategy to process them 1-by-1 - suppress the error from Get-ADUser with -ErrorAction SilentlyContinue and then use an if statement to test if anything was returned:
$CSVFile = Read-Host -Prompt 'Enter the name of the user CSV file (filename.csv)'
$Path = 'C:\scripts'
$UPNs = Import-Csv $Path\$CSVFile
foreach ($UPN in $UPNs.userprincipalname) {
$UID = (Get-ADUser -Filter {UserPrincipalName -eq $UPN} -ErrorAction SilentlyContinue).SamAccountName
if($UID){
Remove-ADGroupMember "My-AD-Group" -Members $UIDs
}
}
Alternative filter out any possible $null values from the $UIDs array before passing it to Remove-ADGroupMember:
Remove-ADGroupMember "My-AD-Group" -Members $UIDs.Where({$_})
If you want to send a warning to the PS Host showing those UPNs which were not found and also skip null or white space elements on your CSV you could use:
$UIDs = Foreach ($UPN in $UPNs.userprincipalname)
{
if([string]::IsNullOrWhiteSpace($UPN))
{
continue
}
if(-not($usr = Get-ADUser -LDAPFilter "(UserPrincipalName=$UPN)"))
{
Write-Warning "- Not Found: $UPN"
}
else
{
$usr.DistinguishedName
}
}
Remove-ADGroupMember "My-AD-Group" -Members $UIDs

Powershell issue with executing in Task Scheduler

I have below script that add users to o365 group at start of their work as below:
$DateMaxTime = (Get-date).AddDays(0)
$DateMaxTimeNew = (Get-date).AddDays(-30)
$usersRO = Get-ADUser -Filter * -Properties * -SearchBase "OU=Users,OU=Resources,OU=Romania,OU=DataManagement,DC=USA"|where {$_.Description -like "*TEMP*" -or $_.Description -like "*PERM*" } |select samaccountname,description,name
$groupsRO = '#O365-EXTERNALACCESS'
$FinalResultRO = New-object System.Collections.ArrayList
ForEach($groupRO in $groupsRO){
$membersRO = Get-ADGroupMember -Identity $groupRO -Recursive | Select -ExpandProperty samaccountname
Foreach ($userRO in $usersRO){
$AcountNameRO = $userRO.samaccountname
$DatePartRONew = get-aduser -identity $AcountNameRO -Properties * | Select-Object whenCreated
$DatePartSubsRONew = $DatePartRONew.whenCreated
$DataPartROdesc=$userRO.description
$expressionRO = ([regex]'(\d{2}/\d{2}/\d{4})').Match($DataPartROdesc).Groups[0].Value
$DatePartRO= $expressionRO
$FinalDateRO = [datetime]::ParseExact($DatePartRO,'dd/MM/yyyy',$null)
If ($DatePartSubsRONew -lt $DateMaxTimeNew){
Write-Host "$AcountNameRO ouf of date scope"}
else {Write-Host "$AcountNameRO in scope"
If ((get-date $FinalDateRO.Date) -eq (get-date $DateMaxTime.Date)){
Write-Host "$AcountNameRO is a today Starter"
If ($membersRO -notcontains $AcountNameRO ) {
Write-Host "Adding external group $groupRO for: $AcountNameRO"
Add-ADGroupMember -Identity "#O365-EXTERNALACCESS" -Members $AcountNameRO
$FinalResultRO.Add((New-Object psobject -Property #{User=$AcountNameRO}))
}
Else {Write-Host "$AcountNameRO exists in group $groupRO"}
}Else {Write-Host "$AcountNameRO is not a Starter"}
}
}
}
$listRO = [array]$FinalResultRO |Select User |Out-String
$listRO.gettype()
if [string]::IsNullOrEmpty($listRO){
Write-Host "nothing to send"
}
Else {
Write-Host "Mail sent"
Send-MailMessage -From "mail1#donut.com" -To "mail2#donut.com" -Subject "Following users have been granted external access rights" -smtpServer "donut" -body "$($listRO)"
}
I run this script daily in task scheduler with higest privilage .
For some reasons, sometimes when script is executing , telling me that users has been added to group but its not changing in Active DIrectory . Only when I run the script second time its working (manually on powershell , not using task scheduler).
What can be a reason for this ?
I would check this line
Add-ADGroupMember -Identity "#O365-EXTERNALACCESS" -Members $AcountNameRO
Your code runs even if it hits some error for whatever reason. I would add a try catch statement to figure out what went wrong (could be DNS, Network, some problem with $AcountNameRO variable ...).
try {Add-ADGroupMember -Identity "#O365-EXTERNALACCESS" -Members $AcountNameRO}
catch{
write-host "something went wrong in Add-ADGroupMember"
Send-MailMessage -From "mail1#donut.com" -To "mail2#donut.com" -
Subject "please check Add-ADGroupMember"
write-host $_
}
Of course, write-host is a bad idea when running a scheduled task because you do not see the output. So I would dump the output in a file or the eventlog or write an email. Bill wrote a nice summary of what you could do concerning the logging.
https://adamtheautomator.com/powershell-logging/

Powershell Script to check if Active Directory User Last Logon

I'm trying to write a powershell script that accepts an username as an argument, and displays the last logon time of the user. If the user has not logged in before, the message has not logged in before should be displayed.
For example, if you run .\lastlogon -username marywong the message is displayed:
marywong last logon time 13/07/2017
If you run .\lastlogon -username guest, I get the message:
guest has not logged in before
Below is my code, however it doesn't seem to be looping into the else loop when the user has not logged in before.
param (
[string]$username
)
$user = Get-ADUser -Filter {sAMAccountName -eq $username} | Get-ADObject -Properties lastLogon
$lastlogontime = $user.lastlogon
If ($user -ne $Null) {
if($user.LastLogon -gt $time) {
$displaylastlogon = [datetime]::FromFileTime($lastlogontime)
Write-Host $username " last logon time" $displaylastlogon
}
else {
$displaylastlogon = [datetime]::FromFileTime($lastlogontime)
Write-Host $username " has not logged in before"
}
}
else {
Write-Host $username " does not exist"
}
There is information to be gained from using Get-ADUser and Get-ADObject separately. If the user has never logged in, they are still a user that exists. That is different from a user that does not exist.
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true, Position = 0)]
[string]$username
)
$user = Get-ADUser -Filter {SamAccountName -eq $username}
if ($user -ne $null) {
$userlogon = $user | Get-ADObject -Properties lastLogon
if ($userlogon.LastLogon -ne $null) {
$lastlogontime = [DateTime]::FromFileTime($userlogon.LastLogon)
Write-Host $username " last logon time" $lastlogontime
} else {
Write-Host $username " has not logged in before"
}
} else {
Write-Host $username " does not exist"
}
When you use the lastLogon you get a format that AD uses...
then when the if is running you get
Could not compare "131820853335016078" to "09/24/2018 18:18:57". Error: "Cannot convert value "9/24/2018 6:18:57 PM" to type "System.Int64". Error: "Invalid cast from 'DateTime' to 'Int64'.""
so it's not getting to the else..
try using the LastLogonDate property, it will help you more.
try to use this:
$user = Get-ADUser -Filter {sAMAccountName -eq $username} -Properties LastLogonDate
$lastlogontime = $user.lastlogonDate
Edit:
you have some more issues with you code:
You need to remove the displaylastlogon
you cant use -gt because it will always be false.. the user cant log in the future.. you need to use -lt
here is the full script, working:
$user = Get-ADUser -Filter {sAMAccountName -eq $username} -Properties LastLogonDate
$lastlogontime = $user.lastlogonDate
If ($user -ne $Null) {
if($lastlogontime -lt $time)
{
Write-Host $username " last logon time" $lastlogontime
}
else
{
Write-Host $username " has not logged in before"
}
}
else
{
Write-Host $username " does not exist"
}
Another Edit:
I just notice that its not answering the case when user never logon, because you will get $null and $null is lower then the current Time. so you need to check that the lastlogontime is not null
change the if to this:
if($lastlogontime -ne $null -and $lastlogontime -lt $time)

Get-ADUser Check for conflicting proxyAddresses

Currently I have a script that creates user accounts.
Note: Not all users have the same UPN (UserPrincipalName)
User accounts are in the following format: <firstinit><lastname>.
If this conflicts, the format will be changed to: <firstinit><middleinit><lastname>
Recently I have ran into an issue where the user's proxyAddress is conflicting with existing users. This is a problem because AD will not catch this.
Issue:
Checking every AD-User's proxy address is very time consuming if not included in the filter. However, when including proxyAddresses in the filter the results are inconsistent. I am assuming this is because the proxyAddresses attribute is an array.
Inconsistent:
Import-Module ActiveDirectory
$FirstLast = "jrider#ChuckNorrisKills.com"
$conflictCheck = Get-ADUser -Properties mail, proxyAddresses -Filter "mail -eq '$FirstLast' -or UserPrincipalName -eq '$FirstLast' -or proxyAddresses -eq `"smtp:'$FirstLast'`"" | measure
if($conflictCheck.Count -gt 0)
{
Write-Host "New user conflicts with existing user" -ForegroundColor Red
}
I have come up with a solution that will resolve me issue. Unfortunately this is very slow (expected):
Import-Module ActiveDirectory
function Test-NewADUser
{
Param(
[Parameter(Mandatory=$true)][string]$firstname,
[Parameter(Mandatory=$true)][string]$lastname,
[Parameter(Mandatory=$false)][string]$middle
)
[bool]$proxExsists = $false
$domain = '#chuckNorrisKills.com'
$FirstLast = $firstname.Substring(0,1)+$lastname+$domain
Get-ADUser -Filter * -Properties proxyAddresses | foreach {
#xpand the proxy address and iterate through it
foreach($address in $_.proxyAddresses)
{
#As you can see this goes through every user
Write-Host "Address: " $address -ForegroundColor Yellow
if($address -eq "smtp:$FirstLast")
{
Write-Host "Found Conflict" -ForegroundColor Red
$proxExsists = $true
}
}
}
}
Test-NewADUser -firstname jack -lastname Rider
Question(s):
Is there a way to expand proxyAddresses and check for conflicts in the -Filter?
If not, should I bother with Jobs, or an alternate way of checking for conflicts?
Thank you in advance for any help
You don't need to expand it, as the proxyAddress filter should be reliable.
So, this should be very straightforward:
function Validate-proxyAddress($email)
{
if (Get-ADUser -Filter "proxyAddresses -eq 'smtp:$email'")
{
return $true
}
elseif (Get-ADUser -Filter "mail -eq '$email'")
{
return $true
}
elseif (Get-ADUser -Filter "UserPrincipalName -eq '$email'")
{
return $true
}
return $false
}
or you can join it all in one like your code, hasn't tested it, so if you get false, the user not exist, should be ok to continue...
Also, you can use -like instead of -eq if you need (in cases where missing the smtp prefix somehow):
"proxyAddresses -like '*$email*'"