I am completely stumped. I am trying to add an embedded image to a notification email. The only scripts i can find are using .net to create a new email object.Can this only be done using .net to create an email object? Any Ideas
#################################################
# Configure the following variables….
# expireindays1 + 2 = At what count of days left on a password do you want a notification?
$smtpServer=”smtprelay.domain.com”
$expireindays1 = 5
#$expireindays2 = 1
$from = “Technology Helpdesk <technologyhelpdesk#domain.com>”
#################################################
#Get Users From AD who are enabled
Import-Module ActiveDirectory
$users = get-aduser -filter * -Properties enabled, GivenName, passwordneverexpires, passwordexpired, emailaddress, passwordlastset |where {$_.Enabled -eq “True”} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
foreach ($user in $users)
{
$Name = (Get-ADUser $user | foreach { $_.Name})
$UserID = (Get-ADUser $user -Properties *).Samaccountname
$emailaddress = $user.emailaddress
$passwordSetDate = (get-aduser $user -properties passwordlastset | foreach { $_.PasswordLastSet })
$PasswordPol = (Get-AduserResultantPasswordPolicy $user)
# Check for Fine Grained Password
if (($PasswordPol) -ne $null)
{
$maxPasswordAge = ($PasswordPol).MaxPasswordAge
}
else
{
$maxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
}
$expireson = $passwordsetdate + $maxPasswordAge
$today = (get-date)
$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
#$subject=
$body = #'
#<html>
<body>
<img src="cid:image1"><br>
<b>$UserID : Your password will expire soon</b>
<br>
<br>
<br>
Dear $name,<br>
Your password will expire in $daystoexpire days. Please change your password before it expires to avoid password related problems. .<br>
<br>
<br>
<b>Password complexity rules:<br>
<br>
- Must be 7 or 8 characters long<br>
- Must contain at least 1 uppercase letter<br>
- Must contain at least 1 lowercase letter<br>
- Must contain at least 1 number<br>
- Must NOT contain repeating characters (e.g., aa, 11)</b><br>
<br>
<br>
Please use the following steps to change your password:<br>
- Press CTRL+ALT+DEL<br>
- Click Change a password…<br>
- Verify your User ID is correct, then type in your old and new passwords (you cannot use previously used passwords)<br>
- After the change is complete, you will be prompted that your password has been changed<br>
- If you have a Blackberry, iPhone, or iPad, those devices will need your new password as soon as your password has been changed<br>
<br>
If you have questions, or need assistance updating your passwords, please contact the Technology Help Desk. <br>
</body>
#</html>
'#
if (($daystoexpire -eq $expireindays1))
# -or ($daystoexpire -eq $expireindays2))
{
#Send-Mailmessage -smtpServer $smtpServer -from $from -to user#domain.com -subject $subject -body $body -bodyasHTML -priority High
####################################################################################################################
$images = #{
image1 = "c:\temp\action needed.png"
}
$params = #{
InlineAttachments = $images
#Attachments = 'C:\temp\action needed.png'
Body = $body
BodyAsHtml = $true
Subject = ”Your password will expire in $daystoExpire days”
From = "Technology Helpdesk <technologyhelpdesk#domain.com>"
To = 'user#domain.com'
#Cc = 'recipient2#domain.com', 'recipient3#domain.com'
SmtpServer = 'smtprelay.domain.com'
}
Send-MailMessage #params
}
}
This code does not use the dot net classes. I hope it helps.
$images = #{
image1 = 'c:\temp\test.jpg'
image2 = 'C:\temp\test2.png'
}
$body = #'
<html>
<body>
<img src="cid:image1"><br>
<img src="cid:image2">
</body>
</html>
'#
$params = #{
InlineAttachments = $images
Attachments = 'C:\temp\attachment1.txt', 'C:\temp\attachment2.txt'
Body = $body
BodyAsHtml = $true
Subject = 'Test email'
From = 'username#gmail.com'
To = 'recipient#domain.com'
Cc = 'recipient2#domain.com', 'recipient3#domain.com'
SmtpServer = 'smtp.gmail.com'
Port = 587
Credential = (Get-Credential)
UseSsl = $true
}
Send-MailMessage #params
BTW all credit to David Wyatt who created the code. He seems to be a good resource on powershell script.
Related
I found a tutorial to send an email when a certain event occurs. The code is this:
$EventId = 4771
$A = Get-WinEvent -MaxEvents 1 -FilterHashTable #{Logname = "System" ; ID = $EventId}
$Message = $A.Message
$EventID = $A.Id
$MachineName = $A.MachineName
$Source = $A.ProviderName
$EmailFrom = "email#domain.com"
$EmailTo = "email#domain.com"
$Subject ="Alert From $MachineQ"
$Body = "EventID: $EventIDnSource: $SourcenMachineQ: $MachineQ `nMessage: $Message"
$SMTPServer = "smtp.server"
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Send($EmailFrom, $EmailTo, $Subject, $Body)
The problem is that I would also like to receive the date/time of the event in the email but I don't know how to add that parameter. Currently the email looks like this:
EventID: 4771
Source: Microsoft-Windows-Security-Auditing
MachineName: server.domain
Message: user blocked.
I would like something like:
EventID: 4771
Source: Microsoft-Windows-Security-Auditing
**Date: 25/11/2022 10:02**
MachineName: server.domain
Message: user blocked.
Could someone tell me how to modify the code to add this parameter?
I am trying to obtain the difference in time between each start and stop action in the following output:
User Computer Time Event Action
---- -------- ---- ----- ------
TEST\me TEST-DC-01 27/05/2020 14:45:06 Logoff Stop
TEST\me TEST-DC-01 27/05/2020 14:44:56 Unlock Start
TEST\me TEST-DC-01 27/05/2020 14:44:49 Lock Stop
TEST\me TEST-DC-01 27/05/2020 14:44:40 Reconnect Start
TEST\me TEST-DC-01 27/05/2020 14:43:17 Disconnect Stop
TEST\me TEST-DC-01 27/05/2020 14:43:07 Logon Start
I've been playing with the New-Timespan cmdlet but seem to be going round and round in circles when trying to integrate it with the script (below) which the above output is derived from.
Ideally, I'd like to see the following appended to it:
Total active time: 00:00:29
Can anyone advise on the best approach (either by fully integrating with the existing script or by importing the output in CSV format).
Any guidance most appreciated.
#
# GROUP POLICY (TO ENABLE 480x AND 477x EVENTS):
#
# COMPUTER CONFIGURATION
# - WINDOWS SETTINGS
# - SECURITY SETTINGS
# - ADVANCED AUDIT POLICY CONFIGURATION
# - SYSTEM AUDIT POLICIES - LOCAL GROUP POLICY OBJECT
# - LOGON/LOGOFF
# - AUDIT OTHER LOGON/LOGOFF EVENTS
# - SUCCESS
#
$OU = "OU=Domain Controllers,DC=test,DC=local"
# WHERE TO SEARCH FOR COMPUTERS IN ACTIVE DIRECTORY
$days = "-1"
# HOW MANY DAYS TO SEARCH BACK THROUGH
$directory = "C:\"
# LOCATION OF FAILED CONNECTIONS FILE
$computers = Get-ADComputer -Filter * -SearchBase $OU
$logs = #()
$timestamp = ((Get-Date).ToString("yyyyMMdd_HHmmss"))
$output = ForEach ($computer in $computers){
try{
$logs += get-eventlog `
-LogName system `
-ComputerName $computer.Name `
-After (Get-Date).AddDays($days)
$logs += get-eventlog `
-LogName security `
-ComputerName $computer.Name `
-After (Get-Date).AddDays($days)
$res = #()
ForEach ($log in $logs){
if($log.instanceid -eq 7001){
$type = "Logon"
$user =
try{
(New-Object System.Security.Principal.SecurityIdentifier(
$log.ReplacementStrings[1])).Translate(
[System.Security.Principal.NTAccount]).value
}
catch{
$log.ReplacementStrings[1]
}
$action = "Start"
}
Elseif ($log.instanceid -eq 7002){
$type = "Logoff"
$user =
try{
(New-Object System.Security.Principal.SecurityIdentifier(
$log.ReplacementStrings[1])).Translate(
[System.Security.Principal.NTAccount]).value
}
catch{
$log.ReplacementStrings[1]
}
$action = "Stop"
}
Elseif ($log.instanceid -eq 4800){
$type = "Lock"
$user = $log.ReplacementStrings[2] + "\" +
$log.ReplacementStrings[1]
$action = "Stop"
}
Elseif ($log.instanceid -eq 4801){
$type = "Unlock"
$user = $log.ReplacementStrings[2] + "\" +
$log.ReplacementStrings[1]
$action = "Start"
}
Elseif ($log.instanceid -eq 4778){
$type = "Reconnect"
$user = $log.ReplacementStrings[1] + "\" +
$log.ReplacementStrings[0]
$action = "Start"
}
Elseif ($log.instanceid -eq 4779){
$type = "Disconnect"
$user = $log.ReplacementStrings[1] + "\" +
$log.ReplacementStrings[0]
$action = "Stop"
}
Else {
Continue
}
$hash = [ordered]#{
"User" = $user
"Computer" = $computer.Name
"Time" = $log.TimeWritten
"Event" = $type
"Action" = $action
}
$res += New-Object PSObject -Property $hash
}
$res
}
Catch {
Add-Content -Path "${directory}${timestamp}_failed.txt" $computer.Name
}
}
$TimeDescending = #{
Expression = 'Time'
Descending = $true
}
$EventDescending = #{
Expression = 'Event'
Descending = $true
}
$output |
sort User,Computer,$TimeDescending,$EventDescending |
? User -like "*me" |
ft
You could use the New-TimeSpan cmdlet:
$start = Get-Date
# Do some stuff here
$end = Get-Date
$timeTaken = (New-TimeSpan -Start $start -End $end).TotalSeconds
I'm using this code in 2012 server but unable to run in windows 2008, i'm new to powershell script which tried to search online but unable to find an answer.
The error come from -property, which i tried -properties and pipe before -property also can't.
$OS = Get-WmiObject Win32_OperatingSystem | Select-Object Caption,Version,ServicePackMajorVersion,OSArchitecture,CSName,WindowsDirectory
$HostName = [System.Net.Dns]::GetHostName()
$TargetPath = Get-Location
$ExportPath = $TargetPath.Path + "\" + $HostName + "_" + $OS.Caption + ".csv"
$UserAccount = Get-WmiObject -Class Win32_UserAccount -Filter "LocalAccount='True'"
$NetworkLoginProfile = Get-WmiObject -Class Win32_NetworkLoginProfile
$GroupUser = Get-WmiObject -Class Win32_GroupUser
if (Test-Path $ExportPath)
{
Remove-Item $ExportPath
}
Foreach($Account in $UserAccount){
$Description = $Account.Description
$Description = $Description.replace("`r`n","_")
$Description = $Description.TrimEnd()
$Profile = #{
HostName = $HostName
Domain = $Account.Domain
LocalAccount = $Account.LocalAccount
SID = $Account.SID
Name = $Account.Name
Caption = $Account.Caption
Status = $Account.Status
Disabled = $Account.Disabled
Lockout = $Account.Lockout
FullName = $Account.FullName
Description = $Description
AccountType = $Account.AccountType
PasswordRequired = $Account.PasswordRequired
PasswordExpires = $Account.PasswordExpires
PasswordChangeable = $Account.PasswordChangeable
NumberOfLogons = ""
LastLogon = ""
UserComment = ""
UserId = ""
UserType = ""
Workstations = ""
BadPasswordCount = ""
GroupMemberShip = ""
}
Foreach ($NetworkProfile in $NetworkLoginProfile)
{
If ($Account.Caption -eq $NetworkProfile.Name)
{
$Profile.NumberOfLogons = $NetworkProfile.NumberOfLogons
$Profile.LastLogon = $NetworkProfile.LastLogon
$Profile.UserComment = $NetworkProfile.UserComment
$Profile.UserID = $NetworkProfile.UserId
$Profile.UserType = $NetworkProfile.UserType
$Profile.Workstations = $NetworkProfile.Workstations
$Profile.BadPasswordCount = $NetworkProfile.BadPasswordCount
}
}
$Groups = New-Object System.Collections.ArrayList
Foreach ($User in $GroupUser)
{
$PartComponent = $User.PartComponent
$Index1 = $PartComponent.indexOf("Name=")
$MemberName = $PartComponent.substring($Index1)
$MemberName = $MemberName.substring(6)
$MemberName = $MemberName.subString(0, $MemberName.indexOf("`""))
$Index2 = $PartComponent.indexOf("Domain=")
$MemberDomain = $PartComponent.subString($Index2)
$MemberDomain = $MemberDomain.substring(8)
$MemberDomain = $MemberDomain.substring(0, $MemberDomain.indexOf("`""))
if (($MemberDomain -eq $Account.Domain) -and ($MemberName -eq $Account.Name))
{
$GroupComponent = $User.GroupComponent
$Index3 = $GroupComponent.indexOf("Name=")
$MemberGroup = $GroupComponent.substring($Index3)
$MemberGroup = $MemberGroup.substring(6)
$MemberGroup = $MemberGroup.subString(0, $MemberGroup.indexOf("`""))
if($MemberGroup)
{
$Groups.Add($MemberGroup)
}
}
}
$count = 0
Foreach ($Group in $Groups)
{
$count++
if($count -lt $Groups.Count){
$Profile.GroupMemberShip += $Group + '|'
}
else{
$Profile.GroupMemberShip += $Group
}
}
$Csv = New-Object psobject -Property $Profile
$Csv | Select-Object -Property Hostname,Domain,LocalAccount,SID,Name,Caption,Status,Disabled,Lockout,FullName,Description,AccountType,PasswordRequired,PasswordExpires,PasswordChangeable,NumberOfLogons,LastLogon,UserComment,UserId,UserType,Workstations,BadPasswordCount,GroupMemberShip | Export-Csv $ExportPath -Append -Delimiter ',' -NoTypeInformation
}
Error I receive:
Since it's no longer supported, it's tough to find documentation this far back, but I found mention of New-Object -Property being used in Windows Powershell 2.0. In the comments under your question, you state that you are running Powershell 1.0. I am fairly confident that -Property did not exist on New-Object in v1.0, so you likely need to update your Windows Management Framework to get Powershell 2.0 or later.
Note that 2.0 is no longer supported so I would recommend going with a more recent verison of Windows Powershell, at least 4.0 if not 5.1. If you can, Powershell Core (v6) would give you the most modern Powershell experience, and will work with most Windows Powershell cmdlets on Windows systems if you install the WindowsCompatibility PowerShell module.
On my venture in learning PowerShell, I have hit into another issue which I would like to get your help in this.
I have a code below inside a try-catch but when an error occurs inside the try block it does not seem to send it to catch block.
The Code:
try{
if ($isFileAvailable -gt 0){
$hashArgumentWithAttachment = #{
From = $From
To = $To
Subject = $Subject
Body = $Body
SmtpServer = $SMTPServer
Port = $SMTPPort
UseSsl = $true
Credential = $smtpCredential
Attachments = $filePath
}
Send-MailMessage #hashArgumentWithAttachment
}
Else {
$hashArgumentWithOutAttachment = #{
From = $From
To = $To
Subject = $Subject
Body = $Body
SmtpServer = $SMTPServer
Port = $SMTPPort
UseSsl = $true
Credential = $smtpCredential
}
Send-MailMessage #hashArgumentWithoutAttachment
}
Write-Output "Emailed"
break
}catch {
Write-Output "Error Occured, No of Attempts So far: " + $attempts.ToString()
}
On an instance where there is a Server connectivity error I expect to hit the catch block but instead it throws an error like this:
Add ErrrorAction to the CMDLet:
Send-MailMessage #hashArgumentWithoutAttachment -ErrorAction Stop
Cheers!
In the following script, it will print all the users of the groups. However, the domain name is missing (Some users are in different Windows domain)?
$computer = [ADSI]"WinNT://$server,computer"
$computer.psbase.children | ? {
$_.psbase.schemaClassName -eq 'group'
} | % {
$gn = $_.name.ToString()
write-host $gn
write-host "------"
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") | % {
$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
}
}
Try fetching the SID instead of the name and translate that back to a username:
$computer.psbase.children | ? {
$_.psbase.schemaClassName -eq 'group'
} | % {
$gn = $_.name.ToString()
write-host $gn
write-host "------"
$group =[ADSI]$_.psbase.Path
$group.psbase.Invoke("Members") | % {
$bytes = $_.GetType().InvokeMember('objectSid', 'GetProperty', $null, $_, $null)
$sid = New-Object Security.Principal.SecurityIdentifier ($bytes, 0)
$sid.Translate([Security.Principal.NTAccount])
}
}
The result should include the computer or domain name.
We have a similar issue where there are accounts from different domains on the computers and we need the domain back. Unfortunately the SID fetch doesn't work I think for local accounts and the domains the computer used to be joined to in some cases, so it didn't return all results.
This was the best solution I found for us:
Admin = $_.GetType().InvokeMember("AdsPath", 'GetProperty', $null, $_, $null)
will return results like
WinNT://#domain#/#account#
or WinNT://#domain of computer#/#computer-name#/#account#
for local accounts
$servers= get-content 'C:\temp\work\localadmins\serverlist_in.txt'
$output = 'C:\temp\work\localadmins\serverlist_out.csv'
$results = #()
foreach($server in $servers)
{
$admins = #()
$group =[ADSI]"WinNT://$server/Administrators"
$members = #($group.psbase.Invoke("Members"))
$members | foreach {
$obj = new-object psobject -Property #{
Server = $Server
Admin = $_.GetType().InvokeMember("AdsPath", 'GetProperty', $null, $_, $null)
}
$admins += $obj
}
$results += $admins
}
$results | Export-csv $Output -NoTypeInformation