I need assistance creating a PowerShell script to expire a users account and add an Out of Office Message to Exchange for 30 days after the expiration date. Below is what I have so far:
Param(
$mailbox = $(Read-Host "you must enter the first part of the email address"),
$StartTime = $(Read-Host "Please enter the start date and time of account expiration in MM/DD/YYYY HH:MM:SS"),
$Username = $(Read-Host "please enter the AS400 username"),
$EndTime = $StartTime.AddDays(30)
)
Set-ADAccountExpiration -Identity $Username -DateTime $StartTime;
Set-MailboxAutoReplyConfiguration -Identity $mailbox -AutoReplyState Scheduled -StartTime $StartTime -EndTime $EndTime -ExternalMessage "The Person you are trying to contact is no longer employed by the Company" -InternalMessage "The Person you are trying to contact is no longer employed by Company XYZ for further assistance please contact the your local Store."
Method invocation failed because [System.String] does not contain a method named 'AddDays'.
How do I create the methods or is there an easier way?
Read-Host returns a string. String objects don't have a method AddDays(). You need to make $StartTime a DateTime value.
Change this:
Param(
...
$StartTime = $(Read-Host "..."),
...
)
into this:
Param(
...
[DateTime]$StartTime = $(Read-Host "..."),
...
)
Note that this only works, because input strings in the format you're asking for can be cast to DateTime. Otherwise you'd need to actually parse the string.
I had some surprisingly similar code written for something a while back, I can't remember if this worked fully and I am unable to test right now, but you should at least be able to get an idea of how parsing the inputs and ensuring everything is valid is done here.
I've changed it around a bit to fit your use better, if the SamAccountName in AD is the same as the Email Alias then you just need to specify Mailbox and StartTime at minimum, it will "autodiscover" the AD account.
Any questions please let me know - and if there's an issue running i'll take a look tomorrow when i'm back in work.
Function Set-LeaverAccount {
Param(
[string]$MailBox = $null,
[string]$StartTime = $null,
[string]$UserName = $null,
[string]$ExternalMessage = "The person you are emailing has left the company, please contact admin#company.com for more details",
[string]$InternalMessage = $null,
[uint16]$OutOfOfficeDays = 30
)
#region Parse Mailbox
$MailBoxAlias = $MailBox
if (!(Get-Mailbox $MailBox -EA SilentlyContinue)){
do {
$Input = Read-Host "Email Alias"
$MailBox = Get-Mailbox $Input -EA SilentlyContinue
} while (!$MailBox)
Write-Host "Mailbox of $($MailBox.Name) Selected"
} else { $Mailbox = Get-Mailbox }
#endregion
#region Parse DateTime
if (![DateTime]::Parse($StartTime)){
do {
$Input = Read-Host "Date/Time of Expiration"
[DateTime]$StartTime = [datetime]::MaxValue
} while (![DateTime]::TryParse($Input,[ref]$StartTime))
Write-Host "Start Time Set To $($StartTime.ToString())"
}
$EndTime = $StartTime.AddDays($OutOfOfficeDays)
#endregion
#region Parse AD Username
if ($UserName -eq $null){
$UserName = $MailBoxAlias #If not set use alias as AD Name
}
if (!(Get-AdUser $UserName -EA SilentlyContinue)){
do {
$Input = Read-Host "AD Username"
$User = Get-AdUser $Input -EA SilentlyContinue
} while ($User.count -ne 1)
Write-Host "User $($User.Name) Selected"
} else {
$User = Get-AdUser $UserName
}
#endregion
if ($InternalMessage -eq $null) { $InternalMessage = $ExternalMessage }
Set-ADAccountExpiration -Identity $User -DateTime $StartTime
Set-MailboxAutoReplyConfiguration -Identity $Mailbox -AutoReplyState Scheduled -StartTime $StartTime -EndTime $EndTime -ExternalMessage $ExternalMessage -InternalMessage $InternalMessage
}
Set-LeaverAccount -MailBox "User01" -StartTime "12/02/16" -UserName "User_1" `
-ExternalMessage "The Person you are trying to contact is no longer employed by the Company" `
-InternalMessage "The Person you are trying to contact is no longer employed by Company XYZ for further assistance please contact the your local Store."
Related
Hello everyone i need this script to work and i'm stuck with a error.
I need to have a dynamic script with user choice and linking the mailbox we enter in first step to the HR choice.
In the csv part we have a group distribution list
Error says that i can not do the add-distributiongroupmember and i don't know why
can someone help me on this one ?
(I just do the 0 part choice because i need this one to work before doing the other choice)
code below
Connect-ExchangeOnline
$User = Read-Host "Enter Name of the mailbox to add"
Try {
$Mbx = Get-Mailbox -Identity $User -ErrorAction Stop | Select -ExpandProperty PrimarySmtpAddress}
Catch {
Write-Host "No mailbox can be found called" $User; break }
$Services = [System.Management.Automation.Host.ChoiceDescription]::new('&Services')
$Services.HelpMessage = 'Get running services'
$HR = New-Object System.Management.Automation.Host.ChoiceDescription '&HR', 'Get running HRDL'
$Legal = New-Object System.Management.Automation.Host.ChoiceDescription '&Legal', 'Get running LegalDL'
$Quit = New-Object System.Management.Automation.Host.ChoiceDescription '&Quit', 'Quit menu'
$options = [System.Management.Automation.Host.ChoiceDescription[]]($HR, $Legal, $Quit)
$Result = $host.UI.PromptForChoice('Task menu', 'Select a Department', $options , 0 )
$DLs = Import-Csv -Path "C:\Users\GregorySemedo\Desktop\Script\DL\DL-HR.csv"
switch($Result)
{
0 { ForEach ($DL in $DLs) {
Try {
Add-DistributionGroupMember -Identity $DL."HR" -Member $Mbx -ErrorAction Continue }
Catch {
Write-Host "Couldn't add" $Mbx "to DL" (Get-DistributionGroup -Identity $DL."HR").DisplayName }
If($?)
{
Write-Host $User Succesfully added -ForegroundColor Green
}
Else
{
Write-Host $User - Error occurred -ForegroundColor Red
}}
}
}
I wrote out a PowerShell Script to rename my computer, add it to specific OU's and join it to the domain. My question is we have two types of computer Desktop (DT) and Laptop (LT) and we give it an asset tag and I would like for it to ask me to select if it is a desktop or laptop and then ask for the asset tag number and then add the DT or LT in front of the asset tag number as the computer name (sorry if confused) example: DT01234 or LT01235. I will post my code below and bold the area that renames the computer. Any and all help would be greatly appreciated.
Write-Host "Select Desktop or Laptop [1-2] [Default 1]:
1. Desktop
2. Laptop"
$computertype = Read-Host
Write-Host "Please Enter Asset Tag"
$NewCompName = Read-Host
$renamecomputer = $true
if ($NewCompName -eq "" -or $NewCompName -eq $env:COMPUTERNAME) {$NewCompName = $env:COMPUTERNAME; $renamecomputer = $false}
Write-Host "Please enter your desired location [1-7] [Default 1]:
1. Test
2. Compliance Stations
3. Controls Stations
4. Processing Stations
5. QC Stations
6. Receiving Stations
7. Shipping Stations"
$ou = Read-Host
#$creds = Get-Credential
function Test-ADCrential{
[CmdletBinding()]
param(
[pscredential]$Credential
)
try {
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
if(!$Credential) {
$Credential = Get-Credential -EA Stop
}
if($Credential.username.split("\").count -ne 2) {
throw "You haven't entered credentials in DOMAIN\USERNAME format. Given value : $($Credential.Username)"
}
$DomainName = $Credential.username.Split("\")[0]
$UserName = $Credential.username.Split("\")[1]
$Password = $Credential.GetNetworkCredential().Password
$PC = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Domain, $DomainName)
if($PC.ValidateCredentials($UserName,$Password)) {
Write-Verbose "Credential validation successful for $($Credential.Username)"
return $True
} else {
throw "Credential validation failed for $($Credential.Username)"
}
} catch {
Write-Verbose "Error occurred while performing credential validation. $_"
return $False
}
}
$mycreds = Get-Credential
Write-Host "Adding $NewCompName to the domain"
Read-Host "Press enter to change computer name"
if ($renamecomputer -eq $true)
{Rename-Computer -NewName $NewCompName -DomainCredential $mycreds}
Read-Host "Press enter to restart computer"
Restart-Computer
Looks like you want something like this
if ($NewCompName -eq "" -or $NewCompName -eq $env:COMPUTERNAME)
{
$NewCompName = $env:COMPUTERNAME; $renamecomputer = $false
}
elseif($NewCompName -inotmatch "^DT|^LT")
{
switch($computertype )
{
1{$NewCompNamePrefix = "DT"}
2{$NewCompNamePrefix = "LT"}
default{}
}
$NewCompName = $NewCompNamePrefix + $NewCompName
}
the -inotmatch is just making sure that if a $newcompname is inputted that already looks like DTwhatever or LTwhatever, it won't append an extra LT or DT
Unrelated (just me being a bit nitpicky):
Look into Read-host -Prompt and nest the prompts into do while loops, so you can validate that the input is what you're expecting.
something like this
$properChoices = #("a","b","c")
do
{
$choice = (Read-Host -Prompt "pick a, b, or c").ToLower()
switch($choice)
{
"a"{"You picked $choice"}
"b"{"You picked $choice"}
"c"{"You picked $choice"}
default{Write-Warning "Invalid Input"}
}
}
while($choice -notin $properChoices)
In PowerShell Exchange-online you can get the mailbox of a user from Get-Mailbox
If i then have the following user input.
$email = Read-Host -Prompt 'what email is it?'
How can i check the user input and see if it matches an existing mailbox and say "mailbox exists" if it exists, else the script should just stop running. How could this be done ?
There are a number of ways to approach this. One way it to store the mailbox search result into a variable. Then simply check if the variable actually stored anything.
$email = Read-Host -Prompt 'what email is it?'
$mailbox = Get-Mailbox $email -ErrorAction SilentlyContinue
if ($mailbox) {
"Mailbox exists"
} else {
Exit
}
-ErrorAction SilentlyContinue is used to suppress the error that would be returned when the mailbox is not found.
A more sophisticated approach would be to catch the exception and take action accordingly.
$email = Read-Host -Prompt 'what email is it?'
try {
$mailbox = Get-Mailbox $email -ErrorAction Stop
"Mailbox Exists"
} catch [System.Management.Automation.RemoteException] {
Exit
}
So, I we have a few users that their computers are not on the domain. One of the annoying things about that is windows will not notify them that their domain password is expired obviously. So I decided I was going to put together a little script using powershell in windows that checks AD to see when their password expires and then if it's about to expire in 3 days to send the user an email to notify them that they should change their password.
I have it set up right now to look at the users distinguished name to pull all the necessary information. but I can only do that for one person, I need to look at two user's distinguished names and send each of them an email when their password is about to expire. I tried creating another $DN variable that I could put the other Distinguished name into and put get-aduser -searchbase $DN, $DN2 but that didn't work for me. Probably was a dumb thing to try, but not sure the syntax needed to accomplish this. Below is my code.
$smtpServer="smtp.office365.com" # Office 365 official smtp server
$expireindays = 100 # number of days for password to expire
$from = # email from
#$logging = "$true" # Set to Disabled to Disable Logging
$logFile = "c:\Scripts\PasswordChangeNotification.csv" # ie. c:\Scripts\PasswordChangeNotification.csv
#$testing = "Disabled" # Set to Disabled to Email Users
$testRecipient =
$date = Get-Date -format ddMMyyyy
$DN = "Distinguished name here"
# Add EMAIL Function
Function EMAIL{
Param(
$emailSmtpServer = $smtpServer, #change to your SMTP server
$emailSmtpServerPort = 587,
$emailSmtpUser = "User"
$emailSmtpPass = "Password", #Password for Send from email account
$emailFrom = "email#domain.com", #Email account you want to send from
$emailTo,
$emailAttachment,
$emailSubject,
$emailBody
)
Process{
$emailMessage = New-Object System.Net.Mail.MailMessage( $emailFrom , $emailTo )
$emailMessage.Subject = $emailSubject
$emailMessage.IsBodyHtml = $true
$emailMessage.Priority = [System.Net.Mail.MailPriority]::High
$emailMessage.Body = $emailBody
$SMTPClient = New-Object System.Net.Mail.SmtpClient( $emailSmtpServer , $emailSmtpServerPort )
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential( $emailSmtpUser , $emailSmtpPass );
$SMTPClient.Send( $emailMessage )
}
}
# Get Users From AD who are Enabled, Passwords Expire and are Not Currently Expired
Import-Module ActiveDirectory
$users = get-aduser -SearchBase $DN -filter * -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress |where {$_.Enabled -eq "True"} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
$DefaultmaxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
# Process Each User for Password Expiry
foreach ($user in $users)
{
$Name = $user.Name
$emailaddress = $user.emailaddress
$passwordSetDate = $user.PasswordLastSet
$PasswordPol = (Get-AduserResultantPasswordPolicy $user)
# Check for Fine Grained Password
if (($PasswordPol) -ne $null)
{
$maxPasswordAge = ($PasswordPol).MaxPasswordAge
}
else
{
# No FGP set to Domain Default
$maxPasswordAge = $DefaultmaxPasswordAge
}
$expireson = $passwordsetdate + $maxPasswordAge
$today = (get-date)
$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
# Set Greeting based on Number of Days to Expiry.
# Check Number of Days to Expiry
$messageDays = $daystoexpire
if (($messageDays) -ge "1")
{
$messageDays = "in " + "$daystoexpire" + " days."
}
else
{
$messageDays = "today."
}
# Email Subject Set Here
$subject="Your password will expire $messageDays"
# Email Body Set Here, Note You can use HTML, including Images.
$body ="
<p>Dear $name,<br></P><br>
<p>Your domain password will expire $messageDays<br><br>
Please change your password before it expires.<br></P><br><br>
<p>Thanks, <br>
} # End Send Message
} # End User Processing
# End
I am just trying to get some insight on how I could modify my code to use two Distinguished names instead of just the one. I'm sure this isn't the best way to do this, but I'm not too good with coding yet. Hopefully this all makes sense, I appreciate the help!
As you have discovered, you can store the DN values in an array $DNs and process each element of the array. The two expressions inside of the parentheses differ by only the $DN variables that you supply. Using a Foreach loop slightly performs better than piping to ForEach-Object, but in your case it will be negligible.
$users = Foreach ($DN in $DNs) {
get-aduser -SearchBase $DN -filter {
Enabled -eq "True" -and
PasswordNeverExpires -eq "False" -and
passwordexpired -eq "False"
} -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress)
There are added benefits of doing it this way:
Removal of the Where-Object: Get-ADUser has its own filter as a parameter that can dramatically increase performance over using where in certain queries. It should be faster for you here as the number of returned users from the Get-ADUser query increases.
Got it!!
I changed $DN to:
$DN = "Distinguished name","Distinguished name"
then changed my get-aduser code to:
$users= $DN | ForEach-Objects {get-aduser -SearchBase $PSItem -filter * .....
thanks,
I have a script for automaticaly notifying users about AD password expiration. It needed for VPN users. But I can't find a way to solve a problem with $msg.to field. It can't accept, for example, "$msg.to = ''" and works only by $msg.to.add method. It makes not so good situation, when user, who was notified first - will recieve all next e-mails because they will be just added at the end of string, but not replacing all of data in $msg.to
There is a code:
Import-Module ActiveDirectory
#SMTP server name
$smtpServer = "mail.domain.local"
#Creating a Mail object
$msg = new-object Net.Mail.MailMessage
$msgr = new-object Net.Mail.MailMessage
#Creating SMTP server object
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
#E-mail structure
Function EmailStructure($to,$expiryDate,$upn)
{
$msg.IsBodyHtml = $true
$msg.From = "notification#domain.com"
$msg.To.Add($to)
$msg.Subject = "Password expiration notice"
$msg.Body = "<html><body><font face='Arial'>This is an automatically generated message from Exchange service.<br><br><b>Please note that the password for your account <i><u>Domain\$upn</u></i> will expire on $expiryDate.</b><br><br>Please change your password immediately or at least before this date as you will be unable to access the service without contacting your administrator.</font></body></html>"
}
Function EmailStructureReport($to)
{
$msgr.IsBodyHtml = $true
$msgr.From = "notification#domain.com"
$msgr.To.Add($to)
$msgr.Subject = "Script running report"
$msgr.Body = "<html><body><font face='Arial'><pre><b>This is a daily report.<br><br>Script has successfully completed its work.<br>$NotificationCounter users have recieved notifications:<br><br>$ListOfAccounts<br><br></b></pre></font></body></html>"
}
#Set the target OU that will be searched for user accounts
$OU = "OU=Organisation,DC=domain,DC=local"
$ADAccounts = Get-ADUser -LDAPFilter "(objectClass=user)" -searchbase $OU -properties PasswordExpired, extensionAttribute15, PasswordNeverExpires, PasswordLastSet, Mail, Enabled | Where-object {$_.Enabled -eq $true -and $_.PasswordNeverExpires -eq $false}
$NotificationCounter = 0
$ListOfAccounts = ""
Foreach ($ADAccount in $ADAccounts)
{
$accountFGPP = Get-ADUserResultantPasswordPolicy $ADAccount
if ($accountFGPP -ne $null)
{
$maxPasswordAgeTimeSpan = $accountFGPP.MaxPasswordAge
}
else
{
$maxPasswordAgeTimeSpan = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
}
#Fill in the user variables
$samAccountName = $ADAccount.samAccountName
$userEmailAddress = $ADAccount.ExtensionAttribute15
$userPrincipalName = $ADAccount.UserPrincipalName
if ($ADAccount.PasswordExpired)
{
Write-host "The password for account $samAccountName has expired!"
}
else
{
$ExpiryDate = $ADAccount.PasswordLastSet + $maxPasswordAgeTimeSpan
$TodaysDate = Get-Date
$DaysToExpire = $ExpiryDate - $TodaysDate
$DaysToExpireDD = $DaysToExpire.ToString() -Split ("\S{17}$")
Write-host "The password for account $samAccountName expires on: $ExpiryDate. Days left: $DaysToExpireDD"
if (($DaysToExpire.Days -eq 15) -or ($DaysToExpire.Days -eq 7) -or ($DaysToExpire.Days -le 3))
{
$expiryDate = $expiryDate.ToString("d",$ci)
#Generate e-mail structure and send message
if ($userEmailAddress)
{
EmailStructure $userEmailAddress $expiryDate $samAccountName
$smtp.Send($msg)
Write-Host "NOTIFICATION - $samAccountName :: e-mail was sent to $userEmailAddress"
$NotificationCounter = $NotificationCounter + 1
$ListOfAccounts = $ListOfAccounts + $samAccountName + " - $DaysToExpireDD days left.<br>"
}
}
}
}
Write-Host "SENDING REPORT TO IT DEPARTMENT"
EmailStructureReport("itdepartment#domain.com")
$smtp.Send($msgr)
How can I drop string in $msg.to after each sent e-mail?
If you want to reuse the same message but change the address and send several times to different addresses, use the clear method on the MailAddressCollection.
So your code will look something like this:
$msg.To.Clear()
$msg.To.Add($to)