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:
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()
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.
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)
}
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!