Send-MailMessage, state never when LastLogonDate = never? - powershell

Using the ps below I'm emailing specific personnel certain AD account properties including LastLogonDate. If the account was never used the email omits the value entirely. I'd like the message to include something like the following:
John Smith logged onto our systems a total of 0 times with the last successful log in posted on N/A.
How can I modify what I have to accomplish this? Thanks!
# List every active account with a "SACRequest Account" desctription that will expire in 0,7,14 days and inlcude the name and email address of the original account requester (extensionAttribute1,extensionAttribute2)
import-module activedirectory
$Today = Get-Date -Format 'MM-dd-yyy'
$Rightnow = Get-Date -Format o
$reportObject = #()
$userList = get-aduser -filter {Description -like "SACRequest Account" -and Enabled -eq $True} -Properties displayname, accountExpires, description, passwordexpired,"msDS-UserPasswordExpiryTimeComputed",enabled,AccountExpirationDate,LastLogonDate,logoncount,passwordlastset, badlogoncount,lastbadpasswordattempt,extensionAttribute1,extensionAttribute2,department |
select displayname, accountExpires, description, passwordexpired,"msDS-UserPasswordExpiryTimeComputed",enabled,AccountExpirationDate,LastLogonDate,logoncount,passwordlastset, badlogoncount,lastbadpasswordattempt,extensionAttribute1,extensionAttribute2,department |
sort-object msDS-UserPasswordExpiryTimeComputed -descending
$obj = new-object PSobject
foreach ($user in $userList)
{
$obj = new-object PSobject
$obj | add-member noteproperty Name($user.displayname)
$obj | add-member noteproperty Description($user.description)
$obj | add-member noteproperty 'Password Expired'($user.Passwordexpired)
$obj | add-member noteproperty 'Account is Enabled'($user.Enabled)
$obj | add-member noteproperty 'AccountExpirationDate'($user.AccountExpirationDate.ToString('MM-dd-yyyy'))
$obj | add-member noteproperty 'LastLogonDate'($user.LastLogonDate.ToString('MM-dd-yyyy'))
$obj | add-member noteproperty 'Password Last Set'($user.PasswordLastSet)
$obj | add-member noteproperty 'Failed Logon Attempt'($user.lastbadpasswordattempt)
$obj | add-member noteproperty 'TotalLogonCount'($user.logoncount)
$obj | add-member noteproperty 'Total Failed Logons'($user.badlogoncount)
$obj | add-member noteproperty 'SACSubmitter'($user.extensionAttribute1)
$obj | add-member noteproperty 'SACSubmitterEmail'($user.extensionAttribute2)
$obj | add-member noteproperty 'Department'($user.department)
$reportObject += $obj}
$from = "System Access Control <systems#organization.org>"
foreach ($user in $reportObject) {
if (([datetime]$user.AccountExpirationDate).AddDays(-0) -eq $TodayOnly)
{
$Name = $user.name
$to = $user.SACSubmitterEmail
$subject = "Your contractors's login account will expire today!"
$hello = $user.SACSubmitter
$AccountExpirationDate = $user.AccountExpirationDate # -as [datetime]
$TotalLogonCount = $user.TotalLogonCount
$LastLogonDate = $user.LastLogonDate
$body = "Hello $hello,<br><br>"
$body += "The login account you requested for <b>$Name</b> will expire in one week on <b> $AccountExpirationDate</b>.<br><br>"
$body += "$name logged onto our systems a total of <b>$TotalLogonCount</b> times with the last successful log in posted on <b> $LastLogonDate</b>.<br><br>"
$body += "<a href='http://intranet/form.cfm?id=100'>If this account needs to remain active please submit a new System Access Control Request by clicking here.</a><br><br>"
$body += "Kind Regards,<br>"
$body += "Your friends in IT<br><br><br>"
$body += "<i>Data generated $RightNow</i>"
$mail = New-Object System.Net.Mail.Mailmessage $from, $to, $subject, $body
$mail.IsBodyHTML=$true
$server = "mail.organization.org"
$port = 25
$Smtp = New-Object System.Net.Mail.SMTPClient $server,$port
$Smtp.Credentials = [system.Net.CredentialCache]::DefaultNetworkCredentials
$smtp.send($mail)
}
}
foreach ($user in $reportObject) {
if (([datetime]$user.AccountExpirationDate).AddDays(-7) -eq $TodayOnly)
{
$Name = $user.name
$to = $user.SACSubmitterEmail
$subject = "Your contractors's login account will expire in one week!"
$hello = $user.SACSubmitter
$AccountExpirationDate = $user.AccountExpirationDate # -as [datetime]
$TotalLogonCount = $user.TotalLogonCount
$LastLogonDate = $user.LastLogonDate
$body = "Hello $hello,<br><br>"
$body += "The login account you requested for <b>$Name</b> will expire in one week on <b> $AccountExpirationDate</b>.<br><br>"
$body += "$name logged onto our systems a total of <b>$TotalLogonCount</b> times with the last successful log in posted on <b> $LastLogonDate</b>.<br><br>"
$body += "<a href='http://intranet/form.cfm?id=100'>If this account needs to remain active please submit a new System Access Control Request by clicking here.</a><br><br>"
$body += "Kind Regards,<br>"
$body += "Your friends in IT<br><br><br>"
$body += "<i>Data generated $RightNow</i>"
$mail = New-Object System.Net.Mail.Mailmessage $from, $to, $subject, $body
$mail.IsBodyHTML=$true
$server = "mail.organization.org"
$port = 25
$Smtp = New-Object System.Net.Mail.SMTPClient $server,$port
$Smtp.Credentials = [system.Net.CredentialCache]::DefaultNetworkCredentials
$smtp.send($mail)
}
}
foreach ($user in $reportObject) {
if (([datetime]$user.AccountExpirationDate).AddDays(-14) -eq $TodayOnly)
{
$Name = $user.name
$to = $user.SACSubmitterEmail
$subject = "Your contractors's login account will expire in two weeks!"
$hello = $user.SACSubmitter
$AccountExpirationDate = $user.AccountExpirationDate # -as [datetime]
$TotalLogonCount = $user.TotalLogonCount
$LastLogonDate = $user.LastLogonDate
$body = "Hello $hello,<br><br>"
$body += "The login account you requested for <b>$Name</b> will expire in one week on <b> $AccountExpirationDate</b>.<br><br>"
$body += "$name logged onto our systems a total of <b>$TotalLogonCount</b> times with the last successful log in posted on <b> $LastLogonDate</b>.<br><br>"
$body += "<a href='http://intranet/form.cfm?id=100'>If this account needs to remain active please submit a new System Access Control Request by clicking here.</a><br><br>"
$body += "Kind Regards,<br>"
$body += "Your friends in IT<br><br><br>"
$body += "<i>Data generated $RightNow</i>"
$mail = New-Object System.Net.Mail.Mailmessage $from, $to, $subject, $body
$mail.IsBodyHTML=$true
$server = "mail.organization.org"
$port = 25
$Smtp = New-Object System.Net.Mail.SMTPClient $server,$port
$Smtp.Credentials = [system.Net.CredentialCache]::DefaultNetworkCredentials
$smtp.send($mail)
}
}

Are you looking for something like
if ($user.LastLogonDate){
#$user.LastLogonDate is not null, use the value
$obj | add-member noteproperty 'LastLogonDate'($user.LastLogonDate.ToString('MM-dd-yyyy'))
} else {
#$user.LastLogonDate is null, use never
$obj | add-member noteproperty 'LastLogonDate' 'Never'
}

1.) remove this first PSobject, it's not needed. replace with step 2
$obj = new-object PSobject
foreach ($user in $userList)
{
2.) split off the 0day users from the user list
$0dayUsers = $userList |Where-Object {$_.LastLogonDate -like ''}
3.) remove 0day users from the original list
$userList = $userList |Where-Object {$_.LastLogonDate -notlike ''}
3.) add this below your 14 day contractor notice at the bottom, I've padded around the one change. I've left it up to you on how to tailor the sample to your target audience
foreach ($user in $0dayUsers) {
$Name = $user.name
$to = $user.SACSubmitterEmail
$subject = "Notice regarding orphaned account!"
$hello = $user.SACSubmitter
$AccountExpirationDate = $user.AccountExpirationDate # -as [datetime]
$TotalLogonCount = $user.TotalLogonCount
$LastLogonDate = $user.LastLogonDate
$body = "Hello $hello,<br><br>"
$body += "The login account you requested for <b>$Name</b> will expire in one week on <b> $AccountExpirationDate</b>.<br><br>"
$body += "$name logged onto our systems a total of <b>$TotalLogonCount</b> times with the last successful log in posted on <b> </b>.<br><br>"
$body += "<a href='http://intranet/form.cfm?id=100'>If this account needs to remain active please submit a new System Access Control Request by clicking here.</a><br><br>"
$body += "Kind Regards,<br>"
$body += "Your friends in IT<br><br><br>"
$body += "<i>Data generated $RightNow</i>"
$mail = New-Object System.Net.Mail.Mailmessage $from, $to, $subject, $body
$mail.IsBodyHTML=$true
$server = "mail.organization.org"
$port = 25
$Smtp = New-Object System.Net.Mail.SMTPClient $server,$port
$Smtp.Credentials = [system.Net.CredentialCache]::DefaultNetworkCredentials
$smtp.send($mail)
}
### The single curly brace is intentional, the if statement was removed since Select-Object already handled it.

Related

Update PowerShell Script to Check Remote Services

I am working on a server validation script that runs via PowerShell, and reaches out to collect remote machine information (pulls the list of servers from a text file), such as server uptime and pending reboot. It takes the information, places it in a CSV file and posts it to a HTML (Results) document.
My ask: I'm trying to reach out to these servers (contained on the .txt file) to validate that certain services are in the running state, and if they are, post the status as 'Running' and if not (else), post as 'Not Running'.
Example of getting the list of servers:
$title = 'Important! Please Read'
$message = 'Is this validation going to run against production servers?'
$choice = #(
[System.Management.Automation.Host.ChoiceDescription]::new(
'&Yes', 'This will execute against Production servers' # => This is help message
)
[System.Management.Automation.Host.ChoiceDescription]::new(
'&No', 'This will execute against Non-Production servers' # => This is help message
)
)
$defaultCoice = 0 # => No
$userinput = $host.UI.PromptForChoice($title, $message, $choice, $defaultCoice)
$prodserverlist = if($userinput -eq 0) {
Get-Content '\\networkshare\PostPatchingValidation\ServerListProd.txt'
}
else {
Get-Content '\\networkshare\PostPatchingValidation\ServerListDev.txt'
}
Example of Check Uptime:
Function Uptime($comp){
function WMIDateStringToDate($Bootup) {
[System.Management.ManagementDateTimeconverter]::ToDateTime($Bootup)
}
$NameSpace = "Root\CIMV2"
$wmi = [WMISearcher]""
$wmi.options.timeout = '0:0:10' #set timeout to 10 seconds
$query = 'Select * from Win32_OperatingSystem'
$wmi.scope.path = "\\$comp\$NameSpace"
$wmi.query = $query
Try{
$wmiresult = $wmi.Get()
#$wmiresult
foreach ($wmioutput in $wmiresult){
$Bootup = $wmioutput.LastBootUpTime
$LastBootUpTime = WMIDateStringToDate($Bootup)
$now = Get-Date
$Reporttime = $now - $lastBootUpTime
$d = $Reporttime.Days
$h = $Reporttime.Hours
$m = $Reporttime.Minutes
$a = "Up for: {0} Days, {1} Hours, {2:N0} Minutes" -f $d,$h,$m
return $a
}
}
Example of Posting results to CSV:
foreach($comp in $prodserverlist){
$i++
$ErrorActionPreference = "SilentlyContinue"
Write-Progress -Activity "Server Health Check " -Status ("Checking Server : {0}" -f $comp) -PercentComplete ($i/$prodserverlist.count*100) -Id 0
$ErrorActionPreference = "Continue"
#region Var_Nulling :p
$autoservices= $null
$Reporttimestatus = $null
$service = $null;
$services = $null;
$totalfailednew = $null
#endregion
$Reporttimestatus = uptime -comp $comp
# $services = Get-Service -comp $comp
$pd = PendingReboot $comp
$newobj = $null
$newobj = new-object psobject
$newobj | add-member -membertype noteproperty -name "Server" -value $comp
$newobj | add-member -membertype noteproperty -name "Uptime" -value $Reporttimestatus #-PassThru
$newobj | add-member -membertype noteproperty -name "PendingReboot" -value $pd
$newobj | add-member -membertype noteproperty -name "ServiceCheck" -value $Reporttimestatus
$newobj | ConvertTo-Csv -NoTypeInformation | Out-File "\\networkshare\PostPatchingValidation\result.csv" -Append
$htmlserver = $newobj.Server
$htmluptime = $newobj.Uptime
$htmlpendingreboot = $newobj.PendingReboot
$htmlservicecheck = $newobj.ServiceCheck
$current = "
<tr bgcolor=#CCCCCC>
<td width='14%' align='center'>$htmlserver</td>
<td width='23%' align='center'>$htmluptime</td>
<td width='12%' align='center'>$htmlpendingreboot</td>
<td width='12%' align='center'></td>
</tr>
"
$total += $current
#$newobj | ConvertTo-html -Fragment
#$newobj | ConvertTo-html -Fragment -CssUri \\networkshare\PostPatchingValidation\Style.css | Out-File \\networkshare\PostPatchingValidation\result.html -Append
}
$HTMLEnd = #"
</div>
</body>
</html>
"#
$MainHtml= $html + $total + $HTMLEnd
$MainHtml | Out-File "\\networkshare\PostPatchingValidation\result.html"
Final Screenshot of HTML Document:

Powershell script to display a list of users and respective permissions of a shared mailbox

I thought I'd post this here just in case I'm barking up the wrong tree. I'm looking to put together a Powershell script that can list all of the members of a shared mailbox and their respective permissions (Limited to "UserName", "Name", "Mailbox", "Full Access", "Send As", "SOBO"). My plan is for the script to ask for an email address and output to look something like this:
User Name Mailbox Full Access Send As SOBO Success
---- ---- ------- ----------- ------- ----- --------
ACB123 Smith, James Examplebox Yes Yes No Success
ABC213 Smith, Pete Examplebox Yes No Yes Success
I was surprised when I couldn't find anything online that is even similar to this.
My script, so far, grabs a list of users that have Full Access (well, it's supposed to, it seems to grab the lesser permissions too, but this actually serves my purpose). The script then strips the collected info down to usernames, then runs a for each to gather information to complete the table above. It runs an AD query for the display names as running Get-ADPermission is not an option.
I haven't got as far as to do the Send As and SoBo parts of the table because I can't get the table to be bigger than 4 columns before it turns into a list, instead of a table. I know there's the Format-Table command but I can't seem to integrate it into my current pscustomobject setup - which is currently set up to split successful queries from failed ones.
This is what I have so far, it's pretty dirty, but this is just my best guess to how something like this should work:
import-moduleactivedirectory
Install-ModuleExchangeOnlineManagement
Connect-ExchangeOnline-ShowBanner:$false
Clear-Host
$ErrorActionPreference='Stop'
$status=[System.Collections.Generic.List[pscustomobject]]::new()
$Entered_email=$Entered_email.trim()
$Collect_SendAs=Get-Mailbox$Entered_email-resultsizeunlimited|Get-RecipientPermission|where {($_.trustee -ne"NT AUTHORITY\SELF")} |where {($_.trustee -match"#")} |selectTrustee
$Collect_users=Get-Mailbox-Identity$Entered_email-ResultSize:Unlimited|Get-MailboxPermission|?{($_.IsInherited -eq$False) -and-not ($_.User -match"NT AUTHORITY")} #|select -ExpandProperty user
$status=foreach($Aliasin$Collect_users)
{
try
{
$User= ($Alias.User.Split("#")[0])
$Access=$Alias.AccessRights
$User_name=Get-ADUser-identity$User-propertiesDisplayName|select-expandpropertyDisplayName
# $Has_SendAs = ($Collect_SendAs.Split("#")[0])
# if ($User -like "*Has_SendAs*") {$User_SendAs = "yes"
# }else{$User_SendAs = "No"}
[pscustomobject]#{
User =$user
Name =$user_name.Split(',')[1..0]-join' '
Mailbox =$Entered_email
'Access Rights'=$Access.Trim("{","}")
'Has Send As'=$User_SendAs
Status ='SUCCESS'
}
}
catch
{
[pscustomobject]#{
User =$user
Status ='FAILED'
Message =$_.Exception.Message
}
}
}
$success,$failed=$status.Where({$_.Status -eq'SUCCESS'},'Split')
$success|selectUser,Name,Mailbox,'Access Rights','Has Send As'|Format-Table|Out-String|Write-Host-ForegroundColorGreen
$failed |selectUser,Message|Out-String|Write-Host-ForegroundColorRed
$SoBo=Get-Mailbox$Entered_email|select #{l='SendOnBehalfOf';e={$_.GrantSendOnBehalfTo -join"`n"}}
$Sobo_Output=$SoBo-replace"#{SendOnBehalfOf=",''-replace"}",''
If ($Sobo_Output-ge1) {
Write-Host"Users With Send on Belhalf Permissions"-ForegroundColorGreen
Write-Host"--------------------------------------"-ForegroundColorGreen
Write-Host$SoBo_Output-ForegroundColorGreen
Write-Host""
}else{
Write-Host"Users With Send on Belhalf Permissions"-ForegroundColorGreen
Write-Host"--------------------------------------"-ForegroundColorGreen
Write-Host"No users found with this permission level"-ForegroundColorGreen
Write-Host""
}
Disconnect-ExchangeOnline-Confirm:$false-InformationActionIgnore-ErrorActionSilentlyContinue
Pause
Any advice would be appreciated at this stage, I definitely could use help with the table, I could probably figure out how to add the Send As and SoBo searches, but if anyone knows some really efficient ones please let me know.
Thanks in advance.
UPDATED
I've amended the script above, because I couldn't figure out how toadd another message.
I've taken on board the changes suggested by #TheMadTechnician, and abandoned the idea of adding SoBo to the table as the SoBo users information is saved as some weird string of names and usernames, so I've rigged it so that this information pops out on a separate table below the access level table.
I've added line 10 ($Collect_SendAs), this is a line that can pull the email addresses (username#domain.com) of all users that have Send As access to the mailbox, I'm looking to get this integrated into the access level table and have made a few wrong turns trying to do this (lines 22-24 are my latest failed attempts to do this).
What I would like to do with the info collected in line 10 is to strip out the #domain part, then compare it with the usernames extracted in line 11, if there match, add a "yes" to the Send As column for the user, and if there is no match, add a "No".
If anyone can help with this, that would be amazing.
UPDATE
Think I've got it:
Import-Module ActiveDirectory
Install-Module ExchangeOnlineManagement
Connect-ExchangeOnline -ShowBanner:$false
Clear-Host
$ErrorActionPreference = 'Stop'
$status = [System.Collections.Generic.List[pscustomobject]]::new()
$Entered_email = Read-host "Enter a mailbox address"
$Entered_email = $Entered_email.trim()
$Collect_SendAs = Get-Mailbox $Entered_email -resultsize:unlimited | Get-RecipientPermission | where {($_.trustee -ne "NT AUTHORITY\SELF")} | where {($_.trustee -match "#")} | select -ExpandProperty Trustee
$Collect_users = Get-Mailbox -Identity $Entered_email -ResultSize:Unlimited | Get-MailboxPermission | ?{($_.IsInherited -eq $False) -and -not ($_.User -match "NT AUTHORITY")}
$status = foreach ($Alias in $Collect_users)
{
try
{
$User = ($Alias.User.Split("#")[0])
$User_name = Get-ADUser -identity $User -properties DisplayName | select -expandproperty DisplayName
if ($Collect_SendAs -match $User) {$User_SendAs = "yes"
}else{$User_SendAs = "No"}
$Access = $Alias.AccessRights
[pscustomobject]#{
User = $user
Name = $user_name.Split(',')[1..0]-join' '
Mailbox = $Entered_email
'Access Rights' = $Access.Trim("{","}")
'Has Send As' = $User_SendAs
Status = 'SUCCESS'
}
}
catch
{
[pscustomobject]#{
User = $user
Status = 'FAILED'
Message = $_.Exception.Message
}
}
}
$success, $failed = $status.Where({$_.Status -eq 'SUCCESS'},'Split')
$success | select User, Name, Mailbox,'Access Rights','Has Send As' | Format-Table | Out-String | Write-Host -ForegroundColor Green
$failed | select User, Message | Out-String | Write-Host -ForegroundColor Red
$SoBo = Get-Mailbox $Entered_email |select #{l='SendOnBehalfOf';e={$_.GrantSendOnBehalfTo -join"`n"}}
$Sobo_Output = $SoBo -replace "#{SendOnBehalfOf=",'' -replace"}",''
If ($Sobo_Output -ge 1) {
Write-Host "Users With Send on Behalf Permissions" -ForegroundColor Green
Write-Host "--------------------------------------" -ForegroundColor Green
Write-Host $SoBo_Output -ForegroundColor Green
Write-Host ""
}else{
Write-Host "Users With Send on Behalf Permissions" -ForegroundColor Green
Write-Host "--------------------------------------" -ForegroundColor Green
Write-Host "No users found with this permission level" -ForegroundColor Green
Write-Host ""
}
Disconnect-ExchangeOnline -Confirm:$false -InformationAction Ignore -ErrorAction SilentlyContinue
Pause
Thanks a lot to everyone who posted.
You are duplicating efforts a LOT with this. Line 9 would return you all the users that have access and the access they have, but you discard everything but the user's account name, and then later loop through those users and get their access one at a time. Here I keep that info, then use it inside the loop to reduce calls to Exchange to get perms again and again. I also changed a variable name since you re-used $User for different things which can be very confusing.
import-module activedirectory
Install-Module ExchangeOnlineManagement
Connect-ExchangeOnline -ShowBanner:$false
Clear-Host
$ErrorActionPreference='Stop'
$status=[System.Collections.Generic.List[pscustomobject]]::new()
$Entered_email = Read-host "Enter a mailbox address"
$Collect_users = Get-Mailbox -Identity $Entered_email -ResultSize:Unlimited|Get-MailboxPermission|?{($_.IsInherited -eq $False) -and -not ($_.User -match"NT AUTHORITY")} #|select -ExpandProperty user
$status=foreach($Alias in $Collect_users)
{
try
{
$User= ($Alias.User.Split("#")[0])
$Access=$Alias.AccessRights
if ($Access -like "*FullAccess*") {$Access_Result="yes"
}else{$Access_Result="No"}
$User_name = Get-ADUser -identity $User -properties DisplayName|select -expandproperty DisplayName
[pscustomobject]#{
User = $user
Name = $user_name
Mailbox = $Entered_email.Split("#")[0]
'Full Access'= $Access_Result
Status ='SUCCESS'
}
}
catch
{
[pscustomobject]#{
User = $user.user
Status ='FAILED'
Message = $_.Exception.Message
}
}
}
$success,$failed=$status.Where({$_.Status -eq'SUCCESS'},'Split')
$success|Out-String|Write-Host-ForegroundColorGreen
$failed |Out-String|Write-Host-ForegroundColorRed
Pause
I started making a "mailbox manager" gui last year and never got around to finishing it, but maybe there's some useful stuff you could pull from it. The last thing I was trying to add was who has access/sendas TO the selected account (bottom part of the gui), which isn't quite working...but the first part (see what accounts/sendas an account has permission for) is working.
The eventual idea was to add a "save" button in so you could check/uncheck the tickboxes as you'd like in the gui and it'd adjust the permissions.
#Init
$logpath = "C:\Scripts\Logs\MailboxPermissions.log"
#Create session on 365 Exchange server
if ((Get-PSSession).Computername -notmatch "outlook.office365.com"){Connect-365}#or: Connect-ExchangeOnline -ShowBanner:$false
$UPNs = Get-Mailbox -Identity * | select -ExpandProperty UserPrincipalName
$AccToDatasource = [System.Collections.ArrayList]::new()
$BS1 = [System.Windows.Forms.BindingSource]::new()
$BS1.DataSource = $AccToDatasource
$AccByDatasource = [System.Collections.ArrayList]::new()
$BS2 = [System.Windows.Forms.BindingSource]::new()
$BS2.DataSource = $AccByDatasource
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
$get_permissions={
$AccToDatasource.Clear()
$AccByDatasource.Clear()
$user = $ComboBox1.Text
write-host "Checking $($user)"
Get-EXOMailboxPermission -Identity $user | ?{$_.User -ne "NT AUTHORITY\SELF"} | %{
$tablerow = New-Object psobject
$data = #{Email="$($_.User)";Inbox=1;SendAs=0}
$tablerow | Add-Member -NotePropertyMembers $data -TypeName tablerow
$AccToDatasource.Add($tablerow)
}
Get-EXORecipientPermission -Identity $user | ?{$_.Trustee -ne "NT AUTHORITY\SELF"} | %{
$indx = [array]::IndexOf($AccToDatasource.Email,$_.Trustee)
if($indx -ne -1){
$AccToDatasource[$indx].SendAs = 1
}else{
$tablerow = New-Object psobject
$data = #{Email="$($_.Trustee)";SendAs=1}
$tablerow | Add-Member -NotePropertyMembers $data -TypeName tablerow
$AccToDatasource.Add($tablerow)
}
}
$BS1.ResetBindings($true)
<##Attempt 1
Get-EXOMailbox -MailboxPlan "ExchangeOnlineEnterprise" -Properties UserPrincipalName | select -ExpandProperty UserPrincipalName | %{
Start-ThreadJob {
Get-EXOMailboxPermission -Identity $using:_ -User $using:user -ErrorAction SilentlyContinue
} | Wait-Job | Receive-Job | %{
$tablerow = New-Object psobject
$data = #{Email="$($_.Trustee)";Inbox=1;SendAs=0}
$tablerow | Add-Member -NotePropertyMembers $data -TypeName tablerow
$AccByDatasource.Add($tablerow)
}
}
$BS2.ResetBindings($true)
#>
#Attempt 2
Get-EXOMailbox -MailboxPlan "ExchangeOnlineEnterprise" -Properties UserPrincipalName | select -ExpandProperty UserPrincipalName | %{Start-ThreadJob {Get-EXOMailboxPermission -Identity $using:_ -User $using:user -ErrorAction SilentlyContinue}} | Wait-Job | Receive-Job | %{
$tablerow = New-Object psobject
$data = #{Email="$($_.Trustee)";Inbox=1;SendAs=0}
$tablerow | Add-Member -NotePropertyMembers $data -TypeName tablerow
$AccByDatasource.Add($tablerow)
}
$BS2.ResetBindings($true)
}
#Form Init
$Form = New-Object system.Windows.Forms.Form
$Form.ClientSize = New-Object System.Drawing.Point(600,650)
$Form.text = "Mailbox Manager"
$Form.TopMost = $false
$ComboBox1 = New-Object system.Windows.Forms.ComboBox
$ComboBox1.width = 370
$ComboBox1.height = 30
$ComboBox1.location = New-Object System.Drawing.Point(137,25)
$ComboBox1.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10)
$ComboBox1.Items.AddRange($UPNs)
$ComboBox1.AutoCompleteSource = "ListItems"
$ComboBox1.AutoCompleteMode = "SuggestAppend"
#$ComboBox1.add_SelectedIndexChanged({
# if ($ComboBox1.Text.Length -gt 10){
# get-permissions -user $ComboBox1.Text
# }
#})
$Label1 = New-Object system.Windows.Forms.Label
$Label1.text = "Select 365 User:"
$Label1.AutoSize = $true
$Label1.width = 25
$Label1.height = 30
$Label1.location = New-Object System.Drawing.Point(14,25)
$Label1.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10)
$Label2 = New-Object system.Windows.Forms.Label
$Label2.text = "Has access to:"
$Label2.AutoSize = $true
$Label2.width = 25
$Label2.height = 30
$Label2.location = New-Object System.Drawing.Point(14,55)
$Label2.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10)
$Label3 = New-Object system.Windows.Forms.Label
$Label3.text = "Accessible by:"
$Label3.AutoSize = $true
$Label3.width = 25
$Label3.height = 30
$Label3.location = New-Object System.Drawing.Point(14,358)
$Label3.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10)
$DataGridView1 = New-Object system.Windows.Forms.DataGridView
$DataGridView1.text = "Emails"
$DataGridView1.width = 560
$DataGridView1.height = 250
$DataGridView1.AutoGenerateColumns = $false
$DataGridView1.Columns.Add((new-object -TypeName System.Windows.Forms.DataGridViewTextBoxColumn -Property #{"Name"="Email"})) | Out-Null
$DataGridView1.Columns['Email'].DataPropertyName = "Email"
$DataGridView1.Columns.Add((new-object -TypeName System.Windows.Forms.DataGridViewCheckBoxColumn -Property #{"Name"="Inbox"})) | Out-Null
$DataGridView1.Columns['Inbox'].DataPropertyName = "Inbox"
$DataGridView1.Columns.Add((new-object -TypeName System.Windows.Forms.DataGridViewCheckBoxColumn -Property #{"Name"="SendAs"})) | Out-Null
$DataGridView1.Columns['SendAs'].DataPropertyName = "SendAs"
$DataGridView1.Columns.Add((new-object -TypeName System.Windows.Forms.DataGridViewTextBoxColumn -Property #{"Name"="Start"})) | Out-Null
$DataGridView1.Columns['Start'].DataPropertyName = "Start"
$DataGridView1.Columns.Add((new-object -TypeName System.Windows.Forms.DataGridViewTextBoxColumn -Property #{"Name"="End"})) | Out-Null
$DataGridView1.Columns['End'].DataPropertyName = "End"
$DataGridView1.ColumnHeadersVisible = $true
$DataGridView1.AutoSizeColumnsMode = 10
$DataGridView1.DataSource = $BS1
$DataGridView1.location = New-Object System.Drawing.Point(11,82)
$DataGridView1.BackColor = [System.Drawing.ColorTranslator]::FromHtml("#e0dede")
$DataGridView1.add_DataError({write-host "hit error"})
$DataGridView2 = New-Object system.Windows.Forms.DataGridView
$DataGridView2.width = 560
$DataGridView2.height = 250
$DataGridView2.location = New-Object System.Drawing.Point(9,383)
$DataGridView2.AutoGenerateColumns = $false
$DataGridView2.Columns.Add((new-object -TypeName System.Windows.Forms.DataGridViewTextBoxColumn -Property #{"Name"="Email"})) | Out-Null
$DataGridView2.Columns['Email'].DataPropertyName = "Email"
$DataGridView2.Columns.Add((new-object -TypeName System.Windows.Forms.DataGridViewCheckBoxColumn -Property #{"Name"="Inbox"})) | Out-Null
$DataGridView2.Columns['Inbox'].DataPropertyName = "Inbox"
$DataGridView2.Columns.Add((new-object -TypeName System.Windows.Forms.DataGridViewCheckBoxColumn -Property #{"Name"="SendAs"})) | Out-Null
$DataGridView2.Columns['SendAs'].DataPropertyName = "SendAs"
$DataGridView2.Columns.Add((new-object -TypeName System.Windows.Forms.DataGridViewTextBoxColumn -Property #{"Name"="Start"})) | Out-Null
$DataGridView2.Columns['Start'].DataPropertyName = "Start"
$DataGridView2.Columns.Add((new-object -TypeName System.Windows.Forms.DataGridViewTextBoxColumn -Property #{"Name"="End"})) | Out-Null
$DataGridView2.Columns['End'].DataPropertyName = "End"
$DataGridView2.ColumnHeadersVisible = $true
$DataGridView2.AutoSizeColumnsMode = 10
$DataGridView2.DataSource = $BS2
$DataGridView2.BackColor = [System.Drawing.ColorTranslator]::FromHtml("#e0dede")
$loadButton = New-Object system.Windows.Forms.Button
$loadButton.text = "Load"
$loadButton.width = 60
$loadButton.height = 30
$loadButton.location = New-Object System.Drawing.Point(509,25)
$loadButton.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10)
$loadButton.Add_Click($get_permissions)
$saveButton = New-Object system.Windows.Forms.Button
$saveButton.text = "Save"
$saveButton.width = 60
$saveButton.height = 30
$saveButton.location = New-Object System.Drawing.Point(509,341)
$saveButton.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',10)
$Form.controls.AddRange(#($Label1,$Label2,$Label3,$ComboBox1,$DataGridView1,$DataGridView2,$saveButton, $loadButton))
[void]$Form.ShowDialog()

Powershell - Reading CSV File as Individual Lines

I have this powershell script to get some email counts which works fine if I only have one user in the csv file but when I put two or more it reads it all as one line and then I get an invalid SMTP address error. I can't for the life of me figure out how to get it to read each line individually. Could someone take a look at this powershell script and help me out?
############ Start Import the Exchange 2010 modules if available, otherwise import 2007.
if (Get-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -Registered -ErrorAction SilentlyContinue) {
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
} else {
Add-PSSnapin -Name Microsoft.Exchange.Management.PowerShell.Admin
}
############ Start Variables
[Int] $intSent = $intRec = 0
$emails = Get-Content "C:\Test.csv"
$dt = (get-date).adddays(-1)
$tab2 = #()
$tabInfo = #()
############ End variables
############ Start HTML Style
$head = #'
<style>
body { background-color:#FFFFFF;
font-family:Tahoma;
font-size:11pt; }
td, th { border:1px solid black;
border-collapse:collapse;
text-align:center;
background+color:#e0e0e0;
width:300px;}
th { color:#ffffff;
background-color:#20a000;
text-align:center;}
table, tr, td, th { padding: 1px; margin: 0px }
table { margin-left:15px; }
</style>
'#
############ End HTML Style
############ Start retrieve email address + NB sent/received mails
foreach ($i in $emails) {
$intRec = 0 #Number of received mails
$intSent = 0 #Number of sent mails
$intTotalSentInt = 0 #Number of sent internal mails
$intTotalSentExt = 0 #Number of sent external mails
$intTotalRecInt = 0 #Number of received internal mails
$intTotalRecExt = 0 #Number of received external mails
$address = $emails #Email address
$object = new-object Psobject #Create the object
$objectInfo = new-object Psobject #Create the object info
############ Sent mails
Get-TransportService | Get-MessageTrackingLog -ResultSize Unlimited -Start $dt -Sender $emails -EventID RECEIVE | ? {$_.Source -eq "STOREDRIVER"} | ForEach {
If ($_.Recipients -match "domain.com") {
$intTotalSentInt++
}
If ($_.Recipients -notmatch "domain.com") {
$intTotalSentExt++
}
}
############ Received mails
Get-TransportService | Get-MessageTrackingLog -ResultSize Unlimited -Start $dt -Recipients $emails -EventID DELIVER | ForEach {
If ($_.Sender -match "domain.com") {
$intTotalRecInt += [Int] $_.RecipientCount
} Else {
# From an external sender
$intTotalRecExt += [Int] $_.RecipientCount
}
}
############ Insert address + number of sent/received mails
$object | Add-member -Name "User" -Membertype "Noteproperty" -Value $emails
$object | Add-member -Name "Internal Emails Sent" -Membertype "Noteproperty" -Value $IntTotalSentInt
$object | Add-member -Name "External Emails Sent" -Membertype "Noteproperty" -Value $IntTotalSentExt
$object | Add-member -Name "Internal Emails Received" -Membertype "Noteproperty" -Value $intTotalRecInt
$object | Add-member -Name "External Emails Received" -Membertype "Noteproperty" -Value $intTotalRecExt
$tab2 += $object
}
############ Sort by number of sent emails
$tab2 = $tab2 | Sort-Object Sent -descending
############ ConvertTo-HTML
$body = $tabInfo | ConvertTo-HTML -head $head
$body += $tab2 | ConvertTo-HTML -head $head
############ Send emails with results
send-mailmessage -to "email#domain.com" -from "email#domain.com" -subject "Emails Sent and Received from $dt" -body ($body | out-string) -BodyAsHTML -SmtpServer "x.x.x.x"
############ end of Script
Sample CSV file that just contains email addresses
Line 45, inside the foreach ($i in $emails), you're doing $address = $emails which puts the entire list of emails in $address. I assume you meant $address = $i ?
Edit: and I missed the one which is probably the problematic one, line 50, you're passing $emails which is an array whereas -Sender takes a string.

PowerShell multiple email recipients (attachment) from csv / empty cell issue

I recently started to work on PS script for email automation.
Manage to put something together where I have CSV file from where PowerShell is extracting data (multiple recipients, attachment, etc).
The problem is, when some of the cells are empty, script won`t work.
There is one similar question, but I am just not sure how to implement solution on my case:
$importFile = "Users.csv"
$users = import-csv $importFile | select *
foreach($user in $users)
{
$Name = $user.'Name'
$to = $user.'To'
$to2 = $user.'To2'
$Attachment = $user.'Attachment'
$Attachment2 = $user.'Attachment2'
$write = "Emailing account " + $to + " ..."
Write-Host $write
$body = [string]::join([environment]::newline, (Get-Content -path $emailFile))
$body = $body.Replace('[Name]', $Name)
$mail = New-Object System.Net.Mail.MailMessage
$mail.From = $emailFrom
$mail.To.Add($to)
$mail.To.Add($to2)
$mail.Subject = $emailSubject
$mail.IsBodyHtml = $true
$mail.Body = $body
$mail.Attachments.Add($Attachment)
$mail.Attachments.Add($Attachment2)
$smtp = New-Object System.Net.Mail.SmtpClient
$smtp.Host = $smtpServerHost
$smtp.Port = $smtpServerPort
$smtp.EnableSsl = $smtpServerSsl
$smtp.UseDefaultCredentials = $false
$smtp.Credentials = $credentials
$smtp.Send($mail)
This is how looks CSV file
Any suggestion is more than welcome :)
Try Where-Object to filter out rows.
$users = Import-Csv $importFile |
Where-Object {$_.Name -ne ""} |
Select-Object *
For what it is worth: if the whole "row" is blank you can shortcut this to simply be
...
Where-Object {$_} |
...
Implementing IF function resolved the case. For example if ($to2 -ne '') is checking if $to2 cell is empty. If no, then $mail.To.Add($to2). The same situation for $Attachment. Here is the code:
$mail = New-Object System.Net.Mail.MailMessage
$mail.From = $emailFrom
$mail.To.Add($to)
if ($to2 -ne '') {
$mail.To.Add($to2)
}
$mail.Subject = $emailSubject
$mail.IsBodyHtml = $true
$mail.Body = $body
$mail.Attachments.Add($Attachment)
if ($Attachment2 -ne '') {
$mail.Attachments.Add($Attachment2)
}

Getting Office 365 groups in sharepoint CSOM with powershell

I've created an security group through Sharepoint Administrator portal, let's name it "group1". and I have a website, with a list and in that list there is a person/group column field, let's name it "PersonGroupColumn".
When I add a new item to my list, i can find "group1" when I type into "PersongroupColumn". Although, what I want to do is to set up a powershell script that updates all the items of my list with "group1" in "PersonGroupColumn"
Here my starting script:
# Get Start Time
$startDTM = (Get-Date)
# Global variables
$User = ""
$Pwd = ""
$SiteURL = ""
# Functions
function addUser
{
param([string]$DisplayName,[string]$Group)
$d=New-Object PSObject
$d | Add-Member -Name DisplayName -MemberType NoteProperty -Value $DisplayName
$d | Add-Member -Name Group -MemberType NoteProperty -Value $Group
return $d
}
#Libraries
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SharePoint.Client') > $null
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SharePoint') > $null
[System.Reflection.Assembly]::LoadWithPartialName('MsOnline') > $null
# Password Init
$Password = ConvertTo-SecureString $Pwd -AsPlainText -Force
# Connection to Office 365
$Creds = New-Object System.Management.Automation.PSCredential($User, $Password)
connect-msolservice -credential $Creds
# Gathering groups and members
$array = #()
$Groups = Get-MsolGroup
foreach($Group in $Groups)
{
$Members = Get-MsolGroupMember -GroupObjectId $Group.ObjectId
$line = New-Object psobject
foreach($Member in $Members)
{
$array += AddUser $Member.DisplayName $Group.DisplayName
}
}
# Connection to sharepoint Online
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User, $Password)
$Context.Credentials = $Creds
# gathering the list
$Web = $Context.Web
$List = $Web.Lists.GetByTitle('Rapport de visite')
$Context.Load($Web)
$Context.Load($List)
$Context.ExecuteQuery()
$Query = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery()
$Items = $List.GetItems($Query)
$Context.Load($Items)
foreach($Item in $Items)
{
$AffectedGroup = ""
$Item['Groupes'] = ""
foreach($Member in $array)
{
if($Item['Author'].LookupValue -eq $Member.DisplayName) {
$AffectedGroup = $Member.Group
}
}
if($Item["Groupes"] -ne $AffectedGroup) {
$Item['Groupes'] = $AffectedGroup + ";"
$Item.Update()
$Context.ExecuteQuery()
}
}
# Get End Time
$endDTM = (Get-Date)
# Echo Time elapsed
"Elapsed Time: $(($endDTM-$startDTM).totalseconds) seconds"
It seems like I need to create a fieldUserValue object and push it into the item's field, but I need the LookupId of the group and I don't know where to get it.
Some help would be really appreciated.
Thanks!