Jump to content

Recommended Posts

Posted

Below is my script that moves users who are found in a particular ou(s) and adds them to a security group

Also removes users when they are no longer in that OU.

 

Scripts works great.... but cannot get it to display any output to the text file... its empty...

When the script is run.... there is no console output... it just runs

 

Need it to display which users have been added or removed from the security group

 

 

Import-Module ActiveDirectory
## Your AD domain name
$ADDomain = 'dc=contoso,dc=com'
## Dynamic group name
$ADGroupname = 'Group1'
## Logfile
$log = "c:\logs\dynamic_grp$(Get-Date -format ddMMyy).txt"
## OU list to search users
$ADOUs = @(
"OU=Staff OU1,$ADDomain",
"OU=Staff OU2,$ADDomain"
)
$users = @()
# Searching users in the specified OUs
foreach($OU in $ADOUs){
$users += Get-ADUser -Filter * -SearchBase "$OU"
}
foreach($user in $users)
{
Add-ADGroupMember -Identity $ADGroupname -Members $user.samaccountname -ErrorAction SilentlyContinue |Out-File -filepath $log -Append
}
## Make sure that each user in the group meets the selection criteria. If not, they are removed from the group
$members = Get-ADGroupMember -Identity $ADGroupname
foreach($member in $members) 
{
if($member.distinguishedname -notlike "*OU=Staff OU1,$ADDomain*" -and $member.distinguishedname -notlike "*OU=Staff OU2,$ADDomain*")
{
Remove-ADGroupMember -Identity $ADGroupname -Members $member.samaccountname -Confirm:$false |Out-File -filepath $log -Append
}
}

Posted (edited)

For straight output I tend to just repeat the command in quotes. To a logfile is slightly different. try:

"Add-ADGroupMember -Identity $($ADGroupname) -Members $($user.samaccountname) -ErrorAction SilentlyContinue" |Out-File -filepath $log -Append

 

I like the full command as I can spot any errors, but it could easily be something like

"$($user.samaccountname) added to $($ADGroupname)"

 

I've not used "Out-File -filepath $log -Append", I've always used

Add-Content $log  "`nsome sort of log data`n$($DateStamp)`n"

but probably only because that was what I used first...

 

Depending on the situation I often just redirect the whole to standard out and error out to a logfile.

Edited by AlexB
Posted (edited)

So there are a few things here, firstly I would use the get-date -Format filedatetime command, not that this will help you with the output but it will get you a nice unique number for your log files and they sort well (also i never knew that this was even a thing until a few weeks ago!)

 

Secondly (actually the first thing and most important) Try Catch statements if you are going to do/ take action on something then you need to handle what happens if something fails.

 

Thirdly (or are we now secondly) I would consider changing how you iterate over your objects so rather than using foreach ($user in $users) I would approach this, this way $Users.foreach({ }) (requires PS v4 or later) you will see significant performance increases in your scripts due to the work that has been put in under the hood to make this more performant. (try it for yourself)

 

This brings me onto what is the real issue and is the enemy while scripting with PS -ErrorAction and how it deals with terminating and none terminating errors essentially what you are doing is killing the informational and error pipes hence why no out to screen or log file.

 

I am rewriting the code will post it shortly....

Edited by HPlum78
Posted (edited)

Import-Module ActiveDirectory
## Your AD domain name
$ADDomain = (Get-ADDomain).distinguishedName

## Dynamic group name$ADGroupname = 'FLS-Staff'

## Logfile$logPath = "C:\localapp\PowerShell\Logs\DynGrpScript\"
$LogFile = "dyn_Grp_Script_$(Get-Date -format filedatetime).txt"

if(!(Test-Path $logPath$LogFile)){    
Try{
       New-item -Path $logPath -Name $LogFile -ItemType File        
$Log = Get-Item $logPath$LogFile
       }
       Catch{
       Exit    }}

## OU list to search users
$ADOUs = @("OU=Staff,OU=User Accounts,$ADDomain")

# Searching users in the specified 
OUs$users = @()

$ADOUs.ForEach({
   Try{
       $users += Get-ADUser -Filter * -SearchBase $_
       Add-Content $Log.FullName "INFO | $(get-date -Format dd/MM_HH:MM:ss) | getting users from $_.)"
       }
       Catch{
           Add-Content $Log.FullName "ERR | $(get-date -Format dd/MM_HH:MM:ss) | getting users from $_.)"
   }
           })$users[0..10].ForEach({
   Try{
       Add-Content $log.FullName "INFO | $(get-date -Format dd/MM_HH:MM:ss) | Trying to add $($_.samaccountname) to $ADGroupname"
       Add-ADGroupMember -Identity $ADGroupname -Members $_.samaccountname
       }
       Catch{
           Add-Content $log.FullName "WRN |$(get-date -Format dd/MM_HH:MM:ss) | Trying to add $($_.samaccountname) to $ADGroupname"
   }
   })

## Make sure that each user in the group meets the selection criteria. If not, they are removed from the group

Try{
   Add-Content $log.FullName "INFO | $(get-date -Format dd/MM_HH:MM:ss) | Getting group members of group $ADGroupname"

   $members = Get-ADGroupMember -Identity $ADGroupname
   }
   Catch{
       Add-Content $log.FullName "ERR | $(get-date -Format dd/MM_HH:MM:ss) | Failed to get members of $ADGroupname"
       Exit
}

Add-Content $log.FullName "INFO | $(get-date -Format dd/MM_HH:MM:ss) | Checking groups and memebership"

$members.ForEach({
       Add-Content $log.FullName "INFO | $(get-date -Format dd/MM_HH:MM:ss) | Checking $($_.distinguishedname)"
   Try{
       if($_.distinguishedname -notlike "*$ADOUs*"){
           Add-Content $log.FullName "INFO | $(get-date -Format dd/MM_HH:MM:ss) | Removing $($_.distinguishedname) from group $ADOUs"
           Remove-ADGroupMember -Identity $ADGroupname -Members $_.samaccountname -Confirm:$false
           }
       }
       Catch{
           Add-Content $log.FullName "WRN | $(get-date -Format dd/MM_HH:MM:ss) | Failed to Remove $($_.samaccountname) from group $ADOUs"
       }
})

 

So thats what i have come up with, error trapping is a kind of art in its self and although i have written the logging inline as it were if you take a look at one of my previous posts you can grab the function that I have posted for writing out error logs. Also I think that function creates the log file as well.

 

The other advantage of writing log this way is the output looks like this:-

 

INFO | 29/01_20:01:54 | Trying to add PN851052 to FLS-Staff

INFO | 29/01_20:01:54 | Trying to add PN908418 to FLS-Staff

WRN | 29/01_20:01:54 | Failed to add PN463155 to FLS-Staff

INFO | 29/01_20:01:54 | Getting group members of group FLS-Staff

INFO | 29/01_20:01:54 | Checking groups and memebership

INFO | 29/01_20:01:54 | Checking CN=Debbia Dziewatkoski,OU=Staff,OU=User Accounts,DC=PLUMNET,DC=CO,DC=UK

INFO | 29/01_20:01:54 | Checking CN=Johnnalynn Terzer,OU=Staff,OU=User Accounts,DC=PLUMNET,DC=CO,DC=UK

INFO | 29/01_20:01:54 | Checking CN=Eleithyia Pathiyiljose,OU=Staff,OU=User Accounts,DC=PLUMNET,DC=CO,DC=UK

 

so you can go to your log folder for the script and run the following PS command:-

 

cat *.* | Select-String Rem

 

This command will return something like the following from all the logs in the directory:

 

INFO | 29/01_20:01:55 | Removing CN=Servanne Eckeard,OU=Students,OU=User Accounts,DC=PLUMNET,DC=CO,DC=UK from group OU=Staff,OU=User Accounts,DC=PLUMNET,DC=CO,DC=UK

 

essentially the command lets you plough through your logs looking for a string/ part of a string, allowing you to quickly find what has happened on your accounts/ groups in your domain. Note that getting your folder structure for your script logging right is a must. (again i have written a function to search the whole log tree or the function lets you select the script logs to search, I will post that function if anyone requires it)

 

Oh and the users in my test domain have all been created by a handy little script on GitHub you can find it here https://github.com/RobBridgeman/ADImporter (I used it to create ~5000 staff/ student users for testing this script in a few mins)

 

##Edit - Code formatting went sideways so did what I could! should still work....

Edited by HPlum78
Posted

Thank you all for your replies...

 

Thank you Plum for your code...

 

I have come across a few things that didn't work....

 

1) Every time the script is run it adds the same users even though they are already a member of $ADGroupname - so tracing which new users have been added would be difficult

 

2) When you have more than one OU to search through.. It adds the users to the group but then immediately removes them

I can revert to my original script which seems to solve the problem - so its just a minor issue, but I prefer the elegance of your coding if you could get it to work

 

if($member.distinguishedname -notlike "*OU=Staff OU1,$ADDomain*" -and $member.distinguishedname -notlike "*OU=Staff OU2,$ADDomain*")

 

And this would be an additional request which would make this perfect (but optional)

Some how get it to email logfile it created at the end of the process

Posted (edited)

Oh yeah see what I have done there let me take a look and rejig it sorry.

 

And yes I will dig out a function for the mailing part as well, it was another thing I wanted to cover TBH. As if the script fails at any a catch and then exits you would want to know that had happened. The way I have written the script means that it's a hard fail at a couple of points and no one would know.

 

Will get on to it hopefully later today.

 

H.

Edited by HPlum78
Posted (edited)
Sorry for the delay been on other stuff, I have fixed the checking you mention in point 1 and when I have looked at how the script is dealing with checking if the users should remain I have decided to rewrite that as you only really want to update the script in one place so I have been refactoring the script to work that way. Then I got thinking about something else when updating users on mass and if you use AAD connect you will know that it has an upper limit on the amount of change that is allowed before it essentially says this don't feel right and emails the global admins saying that its hit the delete limit for example. So with that in mind I was looking at adding a switch to the script so a -maxchange (or something like) to limit the scrip and a way to arm an disarm based on a manual intervention. Anyhow I will aim to put some code up later today, however its Six Nations today and I love my rugby. Edited by HPlum78
Posted

Don't worry about the 500 user limit, must of the users have been moved in to the group manually, its just automating the new users that get added to the teachers OU's

Take your time. enjoy the rugby

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now



×
×
  • Create New...