bulk creation of forwarding addresses and contacts via powershell - powershell

I am trying to move mailboxes to a new Exchange server on a different O365 tenant. This script is a portion of this move which attempts to list all Exchange Online users who have licenses, create a contact for each user pointing to their new email address, and forwards their email to their new address as well as their mailbox
#requires -Version 3 -Modules MSOnline
$mailboxlist = Get-Mailbox | Select-Object -Property userprincipalname |
Get-MsolUser | Where-Object -Property islicensed -EQ -Value $true |
Select-Object -Property firstname, lastname, userprincipalname |
Where-Object -Property firstname -NE -Value $null |
Format-list -AutoSize
#Begin foreach loop
foreach ($item in $mailboxlist)
{
#Create the forwarding address
$forwardingaddress = $item.firstname + '.' + $item.lastname + '#newdomain.com'
#Check for a contact, add if not present
If (!(Get-MailContact $forwardingaddress -ErrorAction silentlycontinue)){
New-MailContact $forwardingaddress -ExternalEmailAddress $forwardingaddress
}
#assign forwarding address
set-mailbox -ForwardingAddress $forwardingaddress -DeliverToMailboxAndForward $true
}
The result of the above is a $mailboxlist which is populated with first and last names and the users UPN which is also an email address. The result of $forwardingaddress is .#newdomain.com.
I don't think I am creating the initial data correctly for the foreach loop. I know that if I replace the $item.firstname with $_.firstname I get the same empty result. I would much appreciate if someone knowledgeable on the topic could assist.
Thanks!
Edit: Final config with Kiran's suggestion
#requires -Version 3 -Modules MSOnline
$mailboxlist = Get-Mailbox | Get-MsolUser | Where-Object { ($_.islicensed -eq $true) -and ($_.firstname -ne $null) }
#Begin foreach loop
foreach ($item in $mailboxlist)
{
#Create the forwarding address
$forwardingaddress = $item.firstname + '.' + $item.lastname + '#newdomain.com'
#Remove any spaces from the email address
$forwardingaddress = ($forwardingaddress -replace " ","").trim()
#Check for a contact, add if not present
If (!(Get-MailContact $forwardingaddress -ErrorAction silentlycontinue))
{
New-MailContact $forwardingaddress -ExternalEmailAddress $forwardingaddress
}
#assign forwarding address
Set-Mailbox -ForwardingAddress $forwardingaddress -DeliverToMailboxAndForward $true
}

try this:
$mailboxlist = Get-Mailbox | Get-MsolUser |
Where-Object { ($_.islicensed -eq $true) -and ($_.firstname -ne $null) }
the UserPrincipalName of get-Msoluser accepts pipeline input by propertyname so you should just pipe the output of get-mailbox to get-msoluser
select-object should be preferred over format-* commands because of the type of objects that are created.
Use format* when you want to show data on the console.
The where-object clause allows you to create complex conditions so try to combine them where you can. This should be the flow of commands:
cmdlet | where-object { some condition(s)} | select properties

Related

E3 license clean up in Disabled user AD

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.

Create csv file of all disabled AD users with mailboxes Output information from multiple cmdlets in powershell

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.

Powershell won't find equal for $var in csv file

I'm pretty new to powershell and I'm trying to assign Exchange-groups and shared mailboxes with an Powershell script. I have a .csv file with the job title, department and all the associated groups and mailboxes. I wrote the following script to achieve my goal but it doesn't work.
I have the feeling that the Where {$_.JobTitle -eq $JOBcsv -and $_.Department -eq $DEPcsv} part is making the script fail. If I put a text value like 'Accountmanager' instead of $JOBcsv all works fine. Thanks in advance!
Connect-ExchangeOnline -Credential $cred
Connect-AzureAD -Credential $cred
$User=Read-Host -Prompt 'Write UPN'
$DEPcsv=Get-AzureADUser -ObjectId $User | Select Department
$JOBcsv=Get-AzureADUser -ObjectId $User | Select JobTitle
$Groups = Import-CSV -Path "C:\PS Scripts\Groepen en Mailboxen.csv" -Delimiter ";" | Where {$_.JobTitle -eq $JOBcsv -and $_.Department -eq $DEPcsv} | Select Groepen
ForEach ($item in $Groups)
{Add-DistributiongroupMember $item -Member $User}
$Mailboxes = Import-CSV -Path "C:\PS Scripts\Groepen en Mailboxen.csv" -Delimiter ";" | Where {$_.JobTitle -eq $JOBcsv -and $_.Department -eq $DEPcsv} | Select Mailboxen
ForEach ($item in $Mailboxes)
{Add-MailboxPermission $item -user $User -AccessRights FullAccess -InheritanceType All}

Powershell - Need help exporting IP address from test-connection into CSV

I have a script to check active directory for windows 7 computers, ping them and report back the ip address.
The export-csv function writes the correct fields and data, except the IP address. The IP address shows as "Microsoft.ActiveDirectory.Management.ADPropertyValueCollection"
Copy of Script
Function Get-Win7 {
$Win7list = get-adcomputer -filter {(operatingsystem -like "Windows 7 Professional") -and (enabled -eq "True")} -properties operatingsystem, lastlogondate
foreach ($pc in $Win7list){
$pingtest = test-connection $pc.name -erroraction silentlycontinue -errorvariable pingfail
if (get-variable -name pingfail -erroraction silentlycontinue) {
if ($pingfail.exception -match "failed"){
$IP3 = "No IP"
$pingfall = $null
}
}
$pc.IP = New-Object -TypeName PSCustomObject -Property #{IPAddress = $pingtest.IPV4Address.ToString | select-object -first 1}
$PC |select-object name,operatingsystem, lastlogondate, IP |sort-object lastlogondate | export-csv -path c:\users\{user}\desktop\Win7-GSN.csv -notypeinfo -append
}
}
Any help is appreciated.
You can use a calculated property in Select-Object, which allows you to add a custom property and give it a custom value. Here we can add a custom property IP and give it the IPV4Address.
$PC | Select-Object name,operatingsystem, lastlogondate, #{n='IP';e={$pingtest[0].IPV4Address}}
As a result, you can remove the $pc.IP = ... line entirely.

Using Powershell with large O365 Tenants

I have been tasked with creating a powershell script that will crawl through one of our clients Office365 enviroments daily and disable POP/IMAP Access to anyone not in a specific security group.
I have written the code and it works, up until it gets about 75% of the way through our ~5000+ mailboxes, then it starts to fail with "Starting a command on the remote server failed with the following error message : The I/O operation has been aborted because of either a thread exit or an application request. For more"
I imagine it is somehow timing out due to there being so many mailboxes, but not sure how to more efficiently write my script? Any ideas?
Connect-EXOPSSession
Connect-MSOLService
$PopGroup = Get-MSOLGroup -All | Where-Object {$_.DisplayName -eq "POP Exception"}
$ImapGroup = Get-MSOLGroup -All | Where-Object {$_.DisplayName -eq "IMAP Exception"}
$EnablePOP = Get-MSOLGroupMember -GroupObjectId $PopGroup.ObjectId -All | Select-Object -ExpandProperty DisplayName
$EnableImap = Get-MSOLGroupMember -GroupObjectId $ImapGroup.ObjectId -All | Select-Object -ExpandProperty DisplayName
$Mailboxes = $Mailboxes = Get-Mailbox -ResultSize Unlimited
ForEach ($Mailbox in $Mailboxes) {
If ($EnablePop -Contains $Mailbox) {
$Mailbox | Set-CASMailbox -PopEnabled $True }
Else {
$Mailbox | Set-CASMailbox -PopEnabled $False }
If ($EnableImap -Contains $Mailbox) {
$Mailbox | Set-CASMailbox -ImapEnabled $True }
Else {
$Mailbox | Set-CASMailbox -ImapEnabled $False }}
That error message appears to be a performance limitation or I/O timeout (see this blog entry from MS for example of this issue). I have a couple of ideas to try:
Your Get-MSOLGroup -ALL commands are pulling the entire list of AD groups and then filtering, it would be better to specify the UPN or SearchString to filter your request. See this link for examples and common performance tips for PS. Try $PopGroup = Get-MSOLGroup -SearchString "POP Exception"
Try using Get-CASMailbox instead of getting all mailboxes with all of their data:
Get-CASMailbox -ResultSize Unlimited | foreach-object {
$upn = "$_#YOURDOMAIN.COM"
if($_.POPEnabled -eq $true -and $(!($EnablePop.EmailAddress -Contains $upn))){
Set-CASMailbox -Identity $upn -PopEnabled $false
} elseif ($_.POPEnabled -eq $false -and $EnablePop -Contains $upn){
Set-CASMailbox -Identity $upn -PopEnabled $true
}
if($_.ImapEnabled -eq $true -and $(!($EnableImap -Contains $upn))){
Set-CASMailbox -Identity $upn -ImapEnabled $false
} elseif($_.ImapEnabled -eq $false -and $EnablePop -Contains $upn){
Set-CASMailbox -Identity $upn -ImapEnabled $true
}
}