I have a .CSV file that I'm filling in some AD info with. The following script is supposed to fill in "Office" on a given users AD properties. The Header in the CSV file with the different "Office" names is called 'office'.
Other Info:
Exchange 2013 Hybrid Server
Forrest Functional Level = 2003 (Just demoted old dc's last week)
All DC's are now 2012 R2. Any suggestions would be appreciated.
This used to work with QADuser cmdlets so I simply found the cmdlet/parameter equivilents and changed them.
New script that doesn't work:
Import-CSV d:\scripts\ExchangeExportQuery.csv | ForEach-Object {$myOff = $_.Office if ($_.DistinguishedName -ne $null -and ($_.DistinguishedName.StartsWith("CN=")) ) {Get-User -ResultSize 'unlimited' -identity $_.DistinguishedName | foreach-object { Set-User -identity $_.DistinguishedName -Office $myOff}}}
Old script that actually worked on old exchange 2007 server with QAD cmdlets:
Import-CSV d:\scripts\ExchangeExportQuery.csv | ForEach-Object {
$myOff = $_.Office
if ($_.DN -ne $null -and ($_.DN.StartsWith("OU=")) ) {
Get-QADUser -SizeLimit 0 -SearchRoot $_.DN |
foreach-object { Set-QADUser -identity $_.DN -Office $myOff}
I may be way off here and better off starting from scratch, but any help would be appreciated.
The issue is syntax. You either need to make it multiple lines or insert a semicolon to separate commands after $myOff = $_.Office and before If (. My suggestion is the following, or make it easier to read:
Import-CSV d:\scripts\ExchangeExportQuery.csv | ForEach-Object {
$myOff = $_.Office
if ($_.DistinguishedName -ne $null -and ($_.DistinguishedName.StartsWith("CN=")) ) {
Get-User -ResultSize 'unlimited' -identity $_.DistinguishedName | foreach-object {
Set-User -identity $_.DistinguishedName -Office $myOff
} #End nested ForEach
} #End If
} #End Outer ForEach
Related
I need some help with a script :)
This script look in our AD for disabled accounts.
Import to CSV then "compare through 0365 and check if the user have E3 license.
So what I would need help with is maybe if else or try catch statements.
So if user are disabled in AD and have a E3 license export to CSV file.
When I ran script I get user not found red text is the maybe a way to handle all error text?
Thanks in advance
$DisabledAccounts = Get-ADUser -Filter {Enabled -eq $false} |
Select userprincipalname |
Export-csv "C:\\Temp\\disabledADUser.csv"
$user = Import-Csv "C:\\Temp\\disabledADUser"
$user | ForEach-Object {
$0365User= Get-MsolUser -UserPrincipalName $\_.UserPrincipalName |
Where-Object {($\_.licenses).AccountSkuId -match "SPE\_E3"} |
Select userprincipalnameione -ErrorAction SilentlyContinue
if ($0365User) {
Write-Host " " -ForegroundColor "red"
}else {
Write-Host "" -ForegroundColor "green"
}
}
You should avoid filtering with curly brackets : -Filter { Enabled -eq $false }, but use instead double quotes -Filter "Enabled -eq $false"
However, since you only need UserPrincipalName attributes, I would prefer Search-ADAccount cmdlet.
Search-ADAccount -AccountDisabled -UsersOnly | ForEach-Object `
-Begin { $o365Users = #() } `
-Process { $o365Users += Get-MsolUser -UserPrincipalName $_.UserPrincipalName |
Where-Object {($_.Licenses).AccountSkuId -match "SPE_E3"} |
Select UserPrincipalName -ErrorAction SilentlyContinue } `
-End { $o365Users } | Export-CSV "C:\Temp\DisabledADUserWithLicenseAttached.csv"
the -Begin parameter for the ForEach-Object cmdlet is called at start only once to create an array which is populate in the -Process block, when all users have been verified, the -End block outputs the array to be converted into a csv.
For your information MSOnline PowerShell Module will be removed at the end of the year. You should consider using the Microsoft.Graph module instead (Here some informations about license management with it). You can also use PnP.PowerShell which is a very powerfull non-Microsoft and open source module but referenced by Microsoft here.
I am trying to gather some information on disabled user accounts that have mailboxes. I am specifically looking for just user mailboxes not shared mailboxes.
Here is what I have so far.
$Mailboxes = Get-Mailbox | where {$_.RecipientTypeDetails -eq 'UserMailbox'}
$date = get-date -f "MMddyyyy_HHmm"
$Disabled = #()
Foreach ($Mailbox in $Mailboxes) {
if((Get-ADUser -Identity $Mailbox.SamAccountName).Enabled -eq $False){
$Disabled += Get-MailboxStatistics $Mailbox.SamAccountName | Select -Property DisplayName,TotalItemSize
}
}
$Disabled | Sort DisplayName | Export-Csv -Path "%path%\DisabledADUsersWithMailbox_$date`.csv" -NoTypeInformation
Additionally what I would like to collect is the users Title, Manager, LastlogonDate all of which can be found using Get-Aduser. I am unsure how I go about collecting the information from both cmdlets and then exporting it all to csv. I have read that I may need to create a custom object. I am struggling with setting that up in this script.
Any help would be much appreciated.
Thanks
the following lines should give you what you want, can't verify it as I have no exchange running here.
$date = get-date -f "MMddyyyy_HHmm"
$Disabled = #(
Foreach ($Mailbox in $Mailboxes) {
$adUser = get-aduser -Identity $Mailbox.SamAccountName -Properties enabled,manager,title,lastlogontimestamp
If ($adUser.Enabled -eq $False){
$mailStats = Get-MailboxStatistics $Mailbox.SamAccountName
$attrsht = [ordered]#{
displayname=$mailstats.displayname
totalitemsize=$mailStats.totalitemsize
samaccountname=$aduser.samaccountname
enabled=$aduser.enabled
manager=$aduser.manager
title=$aduser.title
lastlogontimestamp=[datetime]::FromFileTime($aduser.lastlogontimestamp)
}
new-object -TypeName psobject -Property $attrsht
}
}
)
$Disabled | Sort-Object DisplayName | Export-Csv -Path "%path%\DisabledADUsersWithMailbox_$date`.csv" -NoTypeInformation
Avoid adding elements to an array by using +=. It is slow, alternatively take a look at generic array lists.
so I have a script that works fine that I found online and changed to suit my needs. I have pasted this script below. However, in the output there is a lot of disabled users that have permissions to the mailboxes. E.g. I'd get an Output like "Mailbox Name^Mailbox#email.com^ActiveUser ActiveUser DisabledUser" So I am wondering if there is a way to make the script skip disabled users, same way how it leaves out self permissions.
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
. $env:ExchangeInstallPath\bin\RemoteExchange.ps1
Connect-ExchangeServer -auto
$OutFile = “C:\Send_As_Permissions.txt”
“DisplayName” + “^” + “Email Address” + “^” + “Send As” | Out-File $OutFile -Force
$Mailboxes = Get-Mailbox -resultsize unlimited | Select Identity, Alias, DisplayName, DistinguishedName, WindowsEmailAddress
ForEach ($Mailbox in $Mailboxes) {
$SendAs = Get-ADPermission $Mailbox.identity | where {($_.ExtendedRights -like “*Send-As*”) -and -not ($_.User -like “NT AUTHORITY\SELF”) -and -not ($_.User -like “s-1-5-21*”)} | % {$_.User}
$Mailbox.DisplayName + “^” + $Mailbox.WindowsEmailAddress + “^” + $SendAs | Out-File $OutFile -Append
}
If you want to report on enabled mailboxes only, filter the output from Get-Mailbox on the IsMailboxEnabled property:
$Mailboxes = Get-Mailbox -resultsize unlimited | Where-Object { $_.IsMailboxEnabled } | Select ...
If you want to report on individual rights assignments for enabled accounts only, you'll have to query AD based on the value of the User property you extract:
$SendAs = Get-ADPermission $Mailbox.identity | where {($_.ExtendedRights -like “*Send-As*”) -and -not ($_.User -like “NT AUTHORITY\SELF”) -and -not ($_.User -like “s-1-5-21*”)} | % {$_.User}
$domain,$username = $SendAs.Split('\')
$ADUser = Get-ADUser -Identity $username -Server $domain
if($ADUser.Enabled){
# output to report
}
I was wondering if this script could be changed into one for only active users?
import-module ActiveDirectory
Start-Transcript -Path "C:\test\teetest.txt"
$groups = Get-ADGroup -filter {(name -like "runners*") -or (name -like "helpers*")
foreach($group in $groups)
{
$countUser = (Get-ADGroupMember $group.DistinguishedName).count
Write-Host "The group $($group.Name) has $countUser user(s)."
}
Stop-Transcript
Any help would be appreciated.
If I understand your question correctly and by active users you mean groups with at least 1 member(i.e. greater than 0). You could just filter out results using Where-Object cmdlet. Like so:
$groups = Get-ADGroup -filter {(name -like "runners*") -or (name -like "helpers*") -Properties Members | Where-Object { $_.Members.Count –gt 0 }
Yes, you can add a filter to only get the number of active Members in the Group.
Since Get-ADGroupMember doesn't supply all properties for the Users you have to do another lookup for each of them:
$countUser = (Get-ADGroupMember $group.DistinguishedName | % { Get-ADuser -Identity $_ -Property Enabled | Where-Object {$_.Enabled -eq $true}}).count
Explanation:
% { Get-ADuser -Identity $_ -Property Enabled - Get the Informations for each User found in the Group with the Enabled Property added to it
Where-Object {$_.Enabled -eq $true} - Filters the users that are enabled
I think this may be because the Get-ADGroupMember not just returns user objects with a limited set of properties, but can also return groups and computers.
Since you are only looking for users that are direct descendents of the groups 'runners*' or 'helpers*', it is better to limit the objects returned by the Get-ADGroupMember cmdlet to be users only.
Below I do this by adding Where-Object { $_.objectClass -eq "user" }.
Next, to ensure the .Count property can be used I would suggest to enclose the thing in a #() so the returned value actually is an array and therefore has the Count property.
For a script like this, I also suggest NOT to try and put it all in one single line, because that makes spotting mistakes (like forgetting a closing bracket) more difficult.
Try this:
Start-Transcript -Path "C:\test\teetest.txt"
$groups = Get-ADGroup -Filter {(name -like "runners*") -or (name -like "helpers*")}
foreach($group in $groups) {
$countUser = 0
Get-ADGroupMember $group.DistinguishedName | Where-Object { $_.objectClass -eq "user" } |
ForEach-Object {
if ((Get-ADuser -Identity $_.DistinguishedName).Enabled) { $countUser++ }
}
Write-Host "The group $($group.Name) has $countUser user(s)."
}
Stop-Transcript
Replace the $countUser statement alone with below example.
For only Enabled User Accounts
$countUserEnabled = (get-aduser -filter *|where {$_.enabled -eq "True"}).count
For only Disabled User Accounts
$countUserDisabled = (get-aduser -filter *|where {$_.enabled -ne "False"}).count
#BenH and #TheMadTechnician were extremely helpful in assisting me with a script, to remove Distro Lists (only) from users in specific AD OU's. I forgot to add a needed criteria, so decided to post this as a separate question (original thread here)
#BenH's approach was like this:
$OUs = 'OU=PendingDeletion,OU=Users,DC=Stuff,DC=Place,DC=net','OU=HoldForReview,OU=Users,DC=Stuff,DC=Place,DC=net'
$Users = ForEach ($OU in $OUs) {
Get-ADUser -Filter * -SearchBase $OU
}
ForEach ($User in $Users) {
Get-ADPrincipalGroupMembership -Identity $user |
Where-Object {$_.GroupCategory -eq 0} |
ForEach-Object {
Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $_
}
}
My question - can I force the script to only take action on accounts that have expired more than 30days ago, by adding a variable and "Where-Object" logic to the first loop like this?:
$OUs = 'OU=PendingDeletion,OU=Users,DC=Stuff,DC=Place,DC=net','OU=HoldForReview,OU=Users,DC=Stuff,DC=Place,DC=net'
$30DaysOld = (Get-Date).AddDays(-30)
$Users = ForEach ($OU in $OUs) {
Get-ADUser -Filter * -SearchBase $OU |
Where-Object {$_.AccountExpirationDate -gt $30DaysOld}}
ForEach ($User in $Users) {
Get-ADPrincipalGroupMembership -Identity $user |
Where-Object {$_.GroupCategory -eq 0} |
ForEach-Object {
Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $_
}
}
Possible? Or would I need to change the -gt to a -lt in order to get the correct date range?
Thanks for looking!
Making an answer as requested. The problem is with the Where statement:
Where-Object {$_.AccountExpirationDate -gt $30DaysOld}
While logically is sounds like it's right 'where the account expired more than 30 days ago' it actually comes out to 'where the Date that the account expired is greater than what the Date was 30 days ago'. When you consider that some systems measure dates as seconds passed since the Unix Epoch (Jan 1, 1970 at 12:00:00 AM UTC), and dates are converted to integers, and it makes more sense that the -gt operator selects whichever date happens later chronologically as more seconds have passed since the epoch, and the integer is a larger number.
If you change the -gt to -lt it accomplishes what you're looking for. Also, adding -and $_.AccountExpirationDate to it makes sure that the AccountExpirationDate is not null. So we end up with:
Where-Object {$_.AccountExpirationDate -lt $30DaysOld -and $_.AccountExpirationDate}
#TheMadTechnician nailed it:
Perhaps Where{$_.AccountExpirationDate -lt $30DaysOld -and $_.AccountExpirationDate} would work for you. That makes sure they're more than 30 days old, and makes sure that the value isn't $null. If you still feel that too many results are being generated, go and look at the dates. Are there actually any that expired less than 30 days ago, or have not yet expired?
I needed to change the nested "where" statement to:
Where-Object {$_.AccountExpirationDate -lt $30DaysOld -and $_.AccountExpirationDate}
So the functioning code is:
$30DaysOld = (Get-Date).AddDays(-30)
$OUs = 'OU=PendingDeletion,OU=Users,DC=Stuff,DC=Place,DC=net','OU=HoldForReview,OU=Users,DC=Stuff,DC=Place,DC=net'
$Users = ForEach ($OU in $OUs) {
Get-ADUser -Filter * -Properties AccountExpirationDate -SearchBase $OU |
Where-Object {$_.AccountExpirationDate -lt $30DaysOld -and $_.AccountExpirationDate}
}
ForEach ($User in $Users) {
Get-ADPrincipalGroupMembership -Identity $user |
Where-Object {$_.GroupCategory -eq 0} |
ForEach-Object {
Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $_ -Confirm:$false
}
}
OP here - I've been continuing to work on this (with assistance), and added some additional embellishments that I thought someone else might find useful, so I wanted to share it back.
TheMadTechnician and BenH deserve all the credit for breaking the back of this.
This will now write the names of distros removed to the AD account, use a semicolon separator (to cut/paste the names if you need to re-add the distros), and won't add clutter to the AD account if it's run against the account more than once.
# Variables
$30DaysOld = (Get-Date).AddDays(-30)
$OUs = (
'OU=PendingDeletion,OU=Users,DC=Stuff,DC=Place,DC=net',
'OU=HoldForReview,OU=Users,DC=Stuff,DC=Place,DC=net'
)
# Collect the needed users
$Users = ForEach ($OU in $OUs) {
Get-ADUser -Filter * -Properties AccountExpirationDate,info -SearchBase $OU |
Where-Object {$_.AccountExpirationDate -lt $30DaysOld -and $_.AccountExpirationDate}
}
# Collect each user's Distro Lists & REMOVE
ForEach ($User in $Users) {
$distrosremoved=#()
Get-ADPrincipalGroupMembership -Identity $user |
Where-Object {$_.GroupCategory -eq "distribution"} |
ForEach-Object {
$distrosremoved+=$_.name
Remove-ADPrincipalGroupMembership -Identity $user -MemberOf $_ -Confirm:$false
}
# Collect info from the Telephone > Notes field, and ADD the list of Distros into the existing info
if($distrosremoved){
$distro_str="Removed Distro Lists: `r`n"+($distrosremoved -join "; ")
if ($user.info){
$newinfo=$user.info+"`r`n"+$distro_str
Set-ADUser $user -Replace #{info=$newinfo}
}else{
$newinfo=$distro_str
Set-ADUser $user -Add #{info=$distro_str}
}
}
}