Set-IpAddress.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
<#
.SYNOPSIS
Set-IPAddress allows you to set an IP address, subnet mask, gateway,
and DNS servers for a network adapter.
 
.DESCRIPTION
Set-IPAddress allows you to set an IP address, subnet mask, gateway,
and DNS servers for a network adapter.
 
Windows 8/2012 and above have built-in cmdlets for Set-NetIPAddress, but any downlevel
clients and servers are stuck with netsh. This script can still be used for Windows 8/2012
and above since the WMI methods are still available.
 
Requires:
* Write-Log - https://gallery.technet.microsoft.com/scriptcenter/Write-Log-PowerShell-999c32d0
* Send-Log - https://gallery.technet.microsoft.com/scriptcenter/Send-Log-PowerShell-f4de1581
 
.NOTES
 
Created by: Jason Wasser
Modified: 11/23/2015 01:47:23 PM
 
Changelog:
* Set $PSDefaultParameterValues for Write-Log
* Moved sleep to the End section to save time.
 
TODO:
* Do we even want to attempt to feed computer names or just assume locally?
This would require more testing and working with remote wmi. Plus changing
an IP address of a remote computer during the script would not work well.
* Re-enable DHCP
.EXAMPLE
Set-IPAddress -NetworkAdapterName "Local Area Connection" -IPAddress 192.168.1.50 -SubnetMask 255.255.255.0 -Gateway 192.168.1.1 -DNSServers 192.168.1.1,8.8.8.8
Sets the IP address, subnet mask, gateway, and DNS servers for Local Area Connection.
.EXAMPLE
Set-IPAddress -NetworkAdapterName "Local Area Connection" -IPAddress 192.168.1.50 -SubnetMask 255.255.255.0
Sets the IP address and subnet mask for Local Area Connection.
.EXAMPLE
Set-IPAddress -NetworkAdapterName "Local Area Connection" -IPAddress 192.168.1.50 -SubnetMask 255.255.255.0 -ReplaceExisting $false
Adds the IP address and subnet mask to Local Area Connection keeping the existing IP configuration.
#>

function Set-IPAddress {
    [CmdletBinding()]
    #[OutputType([int])]
    Param
    (
        # Network Interface Name
        [Parameter(Mandatory = $true,
            ValueFromPipelineByPropertyName = $true,
            Position = 0)]
        [Alias("NIC")]
        [string]$NetworkAdapterName,

        # IP address
        [Parameter(Mandatory = $false,
            ValueFromPipelineByPropertyName = $true,
            Position = 1)]
        [ipaddress[]]$IPAddress,

        # Subnet Mask
        [Parameter(Mandatory = $false,
            ValueFromPipelineByPropertyName = $true,
            Position = 2)]
        [Alias('Netmask')]
        [ipaddress[]]$SubnetMask,

        # Gateway
        [Parameter(Mandatory = $false, Position = 3)]
        [ipaddress]$Gateway,

        # DNS Server(s)
        [Parameter(Mandatory = $false, Position = 4)]
        [ipaddress[]]$DNSServers,

        # Default to replace existing IP configuration.
        [Parameter(Mandatory = $false)]
        [bool]$ReplaceExisting = $true,

        # Path to log file
        [Parameter(Mandatory = $false)]
        [String]$LogFileName = "C:\Logs\SetIPAddress.log",
        
        # Include to send copy of log via email
        [Parameter(Mandatory = $false)]
        [switch]$SendLog,

        # Email Parameters
        [string]$SmtpServer = "smtp.domain.com",
        [string]$ToAddress = "it.distro@domain.com",
        [string]$FromAddress = "automaton@domain.com",
        [string]$Subject = "Automaton Alert $(get-date -Format "MM/dd/yyyy HH:mm") - Set-StaticIPAddress for $($env:COMPUTERNAME)",
        [string]$MessageBody = "Please see attached.`n`nSincerely,`nYour friendly AutoMaton.",
        [int]$Port = 25,
        [System.Management.Automation.PSCredential]$Credential = [System.Management.Automation.PSCredential]::Empty
        
    )
    Begin {
        # Set Default Log Path for Write-Log
        $PSDefaultParameterValues = @{"Write-Log:Path" = "C:\Logs\SetIPAddress.log"}

    
        # Worker Function that actually changes the IP configuration.
        function Set-IP {
            # IP Address and Subnet Mask
            if ($IPAddress) {
                if (!$SubnetMask) {
                    Write-Log "Subnet Mask was not provided." -LogPath $LogFileName -Level Error
                    return
                }
                else {
                    Write-Log "Setting IP Address(es) for $($NetworkAdapter.NetConnectionID)`: $IPAddress" -LogPath $LogFileName
                    Write-Log "Subnet Mask(s): $SubnetMask" -LogPath $LogFileName
                
                    $StaticIPResult = $NetworkConfig.EnableStatic($IPAddress, $SubnetMask)
                    if ($StaticIPResult.ReturnValue -ne 0) {
                        Write-Log "Error setting IP: $($StaticIPResult.ReturnValue)" -Level Error
                    }    
                }
            }
            else {
                # No IP address specified.
                Write-Log "No IP address specified." 
            }
            
            # Gateway
            if ($Gateway) {
                Write-Log "Setting Gateway: $Gateway" 
                $GatewayResult = $NetworkConfig.SetGateways($Gateway, 1)
                if ($GatewayResult.ReturnValue -ne 0) {
                    Write-Log  "Error setting gateway: $($GatewayResult.ReturnValue)"  -Level Error
                }
            }
            else {
                # No gateway specified
                Write-Log "No gateway specified." 
            }

            # DNS
            if ($DNSServers) {
                Write-Log "Setting DNS: $DNSServers" 
                $DNSResult = $NetworkConfig.SetDNSServerSearchOrder(@($DNSServers))
                if ($DNSResult.ReturnValue -ne 0) {
                    Write-Log "Error setting DNS: $($DNSResult.ReturnValue)"  -Level Error
                }
            }
            else {
                # No DNS Specified
                Write-Log "No DNS specified." 
            }

            # After making the change we should log the new configuration.
            $NetworkConfig = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Index = $($NetworkAdapter.Index)"

            Write-Log "New IP Configuration: $($NetworkConfig.IPAddress)" 
            Write-Log "New Subnet Configuration: $($NetworkConfig.IPSubnet)" 
            Write-Log "New Gateway Configuration: $($NetworkConfig.DefaultIPGateway)" 
            Write-Log "New DNS Configuration: $($NetworkConfig.DNSServerSearchOrder)" 
        }

        # Begin Logging
        Write-Log "--------------------------------------------" 
        Write-Log "Beginning $($MyInvocation.InvocationName) on $($env:COMPUTERNAME) by $env:USERDOMAIN\$env:USERNAME"
    }
    Process {
    
        # Get the network adapter that matches the provided name. Wildcards are supported, but for safety we can only match one adapter.
        # Although it is better to filter left, I chose to use Where to filter the network adapter name
        # to be able to use standard wildcards for quicker shorthand (i.e. -NIC *local*).
        #$NetworkAdapter = Get-WmiObject -Class win32_NetworkAdapter -Filter "NetConnectionID like '$NetworkAdapterName'" -ErrorAction Stop
        $NetworkAdapter = Get-WmiObject -Class win32_NetworkAdapter -ErrorAction Stop | Where-Object -FilterScript {$_.NetConnectionID -like "$NetworkAdapterName"}
        if ($NetworkAdapter) {
            if ($NetworkAdapter.Count -gt 1) {
                Write-Log "More than one network adapter matches $NetworkAdapterName"  -Level Error
            }
            else {
                #$NetworkConfig = Get-WmiObject -class Win32_NetworkAdapterConfiguration -Filter "IpEnabled = 'True' and Index = $($NetworkAdapter.Index)"
                $NetworkConfig = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Index = $($NetworkAdapter.Index)"
                
                # By default we will replace the existing IP configuration with what was supplied.
                if ($ReplaceExisting) {
                    Set-IP
                }
                else {
                    # If we want to keep the existing IP address configuration, the $ReplaceExisting must be false.
                    # This would be used if the user wished to add an additional IP address to an adapter.
                    # We have to read the current IP address and subnet mask and then add it.
                    # Reading the current IP address(es) may return a IPv6 which cannot be assigned through
                    # the current WMI method. We need to strip out any IPv6 addresses and their corresponding
                    # subnet masks.
                    $CurrentIPAddress = @()
                    $CurrentSubnet = @()
                    $CurrentIPAddress += $NetworkConfig.IPAddress | Where-Object {($_ -as [ipaddress]).AddressFamily -eq "InterNetwork"}
                    Write-Log "Current IP Address(es): $CurrentIPAddress" 
                    foreach ($Address in $CurrentIPAddress) {
                        $CurrentSubnet += $NetworkConfig.IPSubnet[[array]::IndexOf($NetworkConfig.IPAddress, $Address)]
                    }
                    Write-Log "Current Subnet(s): $CurrentSubnet" 
                    
                    # Composite arrays of existing IP address(es) and additional IP address(es).
                    $IPAddress = $CurrentIPAddress + $IPAddress
                    $SubnetMask = $CurrentSubnet + $SubnetMask
                    Set-IP
                }
            }
        }
        # No matching network adapter found.
        else {
            Write-Log "Unable to find a network adapter named $NetworkAdapterName"  -Level Error
        }   
    }
    End {
        # Adding a pause to allow the network card to apply the new settings.
        Write-Log "Pausing to allow the network card to apply the new settings." 
        Start-Sleep -Seconds 5

        # Clean up
        Write-Log "$($MyInvocation.InvocationName) complete." 
        Write-Log "--------------------------------------------" 
        # Send the user a copy of the log if requested.
        if ($SendLog) {
            # Creating anonymous credential
            if ($Credential.Username -eq $null) {
                $Credential = New-Object -TypeName System.Management.Automation.PSCredential('anonymous', (New-Object -TypeName System.Security.SecureString))
            }
            Send-Log -Path $LogFileName -SmtpServer $SmtpServer -ToAddress $ToAddress -FromAddress $FromAddress -Subject $Subject -Username $Username -Password $Password -Port $Port
        }
        # Rotate Log file
        if (Test-Path $LogFileName) {
            $TimeStamp = Get-Date -Format "yyyyMMddhhmmss"
            $LogFilePath = Get-ChildItem -Path $LogFileName
            Rename-Item $LogFileName -NewName "$($LogFilePath.BaseName)-$TimeStamp.log"
        }
    }
}