6

Using powershell I have to enable SMTP and

  • Add relay Ip
  • Add connection IPs
  • Set Access Control Authentication

I found following code for the above operation

$GetSMTP = Get-CimInstance -Namespace "root\MicrosoftIISv2" -Class "IISSMTPServerSetting" -Filter "Name ='SmtpSvc/1'"
$RelayIps =  @(10,92,32,83,127,0,0,1)
$GetSMTP.RelayIpList = $RelayIps
Set-CimInstance -InputObject $GetSMTP

$GetSMTP
$GetSMTP = Get-CimInstance -Namespace "root\MicrosoftIISv2" -Class "IIsIPSecuritySetting" -Filter "Name ='SmtpSvc/1'"

$NewConnectionIps = @(
                     "10.92.32.80, 10.92.32.81";
                     "10.92.32.83,127.0.0.1";
                      )
$GetSMTP.ipgrant += $NewConnectionIps
Set-CimInstance -InputObject $GetSMTP

$GetSMTP

The above powershell code executed successfully and it list as it is added.

But when i connect to smtp server, the following error is throwing

enter image description here

I have a found a solution to solve the above issue, To delete the folders inside "C:\inetpub\mailroot" and where i am able to start the default Smtp Virtual Server, but again facing an issue while click smtp vitrual server properties

enter image description here

Fermin
  • 34,961
  • 21
  • 83
  • 129
PonVimal
  • 223
  • 1
  • 4
  • 16

4 Answers4

9

Loading Feature Installation Modules

Import-Module ServerManager 

Installing Features

Add-WindowsFeature SMTP-Server,Web-Mgmt-Console,WEB-WMI

Adding Relay , connection IPs and Authentication Basic for SMTP

$Networkip =@()
$Networks = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName    localhost | ? {$_.IPEnabled}
foreach($Network in $Networks)  {  $Networkip = $Network.IpAddress[0]  }

Adding Relay and Authentication Basic for SMTP

$ipblock= @(24,0,0,128,
32,0,0,128,
60,0,0,128,
68,0,0,128,
1,0,0,0,
76,0,0,0,
0,0,0,0,
0,0,0,0,
1,0,0,0,
0,0,0,0,
2,0,0,0,
1,0,0,0,
4,0,0,0,
0,0,0,0,
76,0,0,128,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
255,255,255,255)

$ipList = @()
$octet = @()
$connectionips=$arg[0]       
$ipList = "127.0.0.1"
$octet += $ipList.Split(".")
$octet += $Networkip.Split(".")

$ipblock[36] +=2 
$ipblock[44] +=2;
$smtpserversetting = get-wmiobject -namespace root\MicrosoftIISv2 -computername localhost -Query "Select * from IIsSmtpServerSetting"
$ipblock += $octet
$smtpserversetting.AuthBasic=1
$smtpserversetting.RelayIpList = $ipblock
$smtpserversetting.put()

Adding Connection for SMTP

$connectionips="10.10.10.10"      

$checkArray =$connectionips.split(",") 
if($checkArray -notcontains $Networkip)
{
 $connectionips += ","+$Networkip
}

$connectionipbuild=@()
$ipArray=$connectionips.split(",")
foreach ($ip in $ipArray)
{   
  $connectionipbuild +=$ip+",255.255.255.255;"     
}

$iisObject = new-object System.DirectoryServices.DirectoryEntry("IIS://localhost/SmtpSvc/1")
$ipSec = $iisObject.Properties["IPSecurity"].Value

# We need to pass values as one element object arrays
[Object[]] $grantByDefault = @()
$grantByDefault += , $false            # <<< We're setting it to false

$ipSec.GetType().InvokeMember("GrantByDefault", $bindingFlags, $null, $ipSec, $grantByDefault);

$iisObject.Properties["IPSecurity"].Value = $ipSec
$iisObject.CommitChanges()

$iisObject = new-object System.DirectoryServices.DirectoryEntry("IIS://localhost/SmtpSvc/1")
$ipSec = $iisObject.Properties["IPSecurity"].Value
$bindingFlags = [Reflection.BindingFlags] "Public, Instance, GetProperty"
$isGrantByDefault = $ipSec.GetType().InvokeMember("GrantByDefault", $bindingFlags, $null, $ipSec, $null);

# to set an iplist we need to get it first
if($isGrantByDefault)
{
    $ipList = $ipSec.GetType().InvokeMember("IPDeny", $bindingFlags, $null, $ipSec, $null);
}
else
{
    $ipList = $ipSec.GetType().InvokeMember("IPGrant", $bindingFlags, $null, $ipSec, $null);
}

# Add a single computer to the list:
$ipList = $ipList + $connectionipbuild

# This is important, we need to pass an object array of one element containing our ipList array
[Object[]] $ipArray = @()
$ipArray += , $ipList

# Now update
$bindingFlags = [Reflection.BindingFlags] "Public, Instance, SetProperty"
if($isGrantByDefault)
{
    $ipList = $ipSec.GetType().InvokeMember("IPDeny", $bindingFlags, $null, $ipSec, $ipArray);
}
else
{
    $ipList = $ipSec.GetType().InvokeMember("IPGrant", $bindingFlags, $null, $ipSec, $ipArray);
}

$iisObject.Properties["IPSecurity"].Value = $ipSec
$iisObject.CommitChanges()
PonVimal
  • 223
  • 1
  • 4
  • 16
  • Hi, could you include the relevant parts from your link in your answer please? That way, if the link goes dead, your answer is still useful. Many thanks. – Wai Ha Lee May 08 '15 at 22:24
  • What does the $ipblock array represent? I've seen it in multiple examples without any explanation – Fermin Apr 28 '17 at 13:38
  • The script on this page https://social.technet.microsoft.com/Forums/ie/en-US/ee211ac0-a2d0-4c93-900b-ceb1d10dd554/powershell-script-to-change-smtp-configuration?forum=winserverpowershell does `+=1` on element 36 and 44. The unedited answer above had `$connectionipbuild="10.10.10.10,11.11.11.11"` ie, adding 2 hardcoded addresses, and therefore would need doing `+=2`. I believe, maybe, the script above should be doing `+=1` for each of the `$ipList` or `$Networkip` it adds. – Thierry_S Dec 19 '17 at 13:48
  • Have the IP addresses in `$ipblock` got a special meaning, but are not real IP addresses? The elements at 36 and 44 seem to reflect the number of IP in the dialog box. I have tried to set it random values and then tried to click "Apply" in the smtp Relay dialog box to overwrite them and got an mmc crash accessing memory. – Thierry_S Dec 19 '17 at 13:56
0

In addition to PonVimal's answer (accepted):

This solution uses Get-NetworkAddress function from Indented.NetworkTools

If you would like to specify relay for a group of computers instead of single address you can use System.DirectoryServices in a following manner (thanks to this answer as well):

$IpRelayList = @("192.168.1.0, 255.255.0.0", 
                "127.3.4.0, 255.255.255.192")

#adding relays
$iisObject = new-object System.DirectoryServices.DirectoryEntry("IIS://localhost/smtpsvc/1")
$relays = $iisObject.Properties["RelayIpList"].Value
$bindingFlags = [Reflection.BindingFlags] "Public, Instance, GetProperty"
$ipList = $relays.GetType().InvokeMember("IPGrant", $bindingFlags, $null, $relays, $null);

#if relay list is empty we are retrieving host subnets and adding to relay
$Networkip =@()
if($IpRelayList.Count -eq 0)
{
    $Networks = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName localhost | ? {$_.IPEnabled}
    foreach($Network in $Networks)  
    {   
        $line = Get-NetworkAddress $Network.IpAddress[0] $Network.IpSubnet[0]
        $line = $line + ", " + $Network.IpSubnet[0]
        $Networkip += $line
    }
}

$ipList = $Networkip + $IpRelayList

# This is important, we need to pass an object array of one element containing our ipList array
[Object[]] $ipArray = @()
$ipArray += , $ipList

# Now update
$bindingFlags = [Reflection.BindingFlags] "Public, Instance, SetProperty"
$ipList = $relays.GetType().InvokeMember("IPGrant", $bindingFlags, $null, $relays, $ipArray);

$iisObject.Properties["RelayIpList"].Value = $relays
$iisObject.CommitChanges()
Community
  • 1
  • 1
Sergey Nikitin
  • 845
  • 2
  • 13
  • 25
0

In addition to PonVimal's answer (accepted):

I also wanted the SMTPSVC service to be automatic and came up with an idempotent script that ensures that the service is not only installed but also set to automatic and started so that any subsequent machine restarts does not require me to manually start the service.

# ----- Converting service: "Simple Mail Transfer Protocol" to be automatic from manual ------
$ServiceName= "SMTPSVC"

    If (Get-Service $ServiceName -ErrorAction SilentlyContinue) {
        If ((Get-Service $ServiceName).StartType -ne "Automatic") {
            If ((Get-Service $ServiceName).Status -eq 'Running') {
                Stop-Service $ServiceName
                "Stopping $ServiceName"
            } Else {
                        "ServiceName found, and it is stopped."
                    }
            Set-Service -Name $ServiceName -StartupType "Automatic"
            Do{
            "Starting service: $ServiceName"
            sc.exe start "$ServiceName"
            start-sleep -s 5
            $ServiceStatus = (get-service -name $ServiceName)
            } 
            Until ($ServiceStatus.Status -eq "running")
            "Service Started: $ServiceName"
        }

        If ((Get-Service $ServiceName).Status -eq 'Running') {
            "`n$ServiceName configured as automatic and running`n"
        } Else {
            Do{
            "Starting service: $ServiceName"
            sc.exe start "$ServiceName"
            start-sleep -s 5
              $ServiceStatus = (get-service -name $ServiceName)
            } 
            Until ($ServiceStatus.Status -eq "running")
            "Service Started: $ServiceName"
          }
        } Else {
        "$ServiceName not found"
    }

# Test to check if the service is configured correctly and is running
If (Get-Service $ServiceName) {

    If ((Get-Service $ServiceName).StartType -ne "Automatic") {
        throw "$ServiceName is not configured as automatic"

    }
    If ((Get-Service $ServiceName).Status -ne 'Running') {
        throw "$ServiceName is not running"

    }
    "`n$ServiceName configured as automatic and running`n"
}
Sourav Kundu
  • 408
  • 2
  • 14
0

This is actually possible, and more complicated than one might think. This magical relay IP list object has some collection lengths hard-coded into it.

Here's part of my script that I used after I figured out that oddity.

param(
    [Parameter(ValueFromRemainingArguments=$true)][object[]]$AllowedIPs
)

$SMTPServerWmi = Get-WmiObject IISSmtpServerSetting -namespace "ROOT\MicrosoftIISv2" | Where-Object { $_.name -like "SmtpSVC/1" }
$SMTPServerWmi.RelayIpList = @(24,0,0,128,
32,0,0,128,
60,0,0,128,
68,0,0,128,
1,0,0,0,
76,0,0,0,
0,0,0,0,
0,0,0,0,
1,0,0,0,
$AllowedIPs.Count,0,0,0,
2,0,0,0,
($AllowedIPs.Count + 1),0,0,0,
4,0,0,0,
0,0,0,0,
76,0,0,128,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
255,255,255,255) + $AllowedIPs.ForEach({ $_.Split(".")})

$SMTPServerWmi.Put()

If those values aren't correct, the UI may show your IPs and a lot of random junk, crash, or become broken such that you cannot use it to remove the items from the list using the UI.