Powershell remote static IP via script

powershell, wmi

Solution

You might have more luck using Invoke-Command to run netsh on the remote computer, which sets the IP address, subnet mask, and gateway in one command. However, netsh uses a different name for the interface, which you can get from the NetConnectionID property of the Win32_NetworkAdapter class.

$InterfaceName = $Get-WmiObject Win32_NetworkAdapter | ?{$_.Description -eq $wmi.Description} | select -ExpandProperty NetConnectionID
Invoke-Command -ComputerName $ComputerName -Credential $Credential -ScriptBlock {netsh interface ip set address $InterfaceName static $IPAddress $SubnetMask $DefaultGateway 1}

You can wrap the second line in another `if ($Credential)` block.

However, I strongly recommend that you verify that the filter is returning one object rather than an array of objects, as suggested in my comments above. Or, to be safe, change

$wmi = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName -Filter "IPEnabled = 'True'" -Credential $Credential

to

$wmi = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName -Filter "IPEnabled = 'True'" -Credential $Credential | select -First 1

That will ensure you're getting only one object, but of course it can't ensure that it's necessarily the one you want if there's more than one with IPEnabled true.

Problem

I'm looking to write a Powershell function to assign a static IP address remotely to a computer specified at runtime. I've done some research and found the Win32_NetworkAdapterConfiguration class, which seems like exactly what I need. So I sat down and wrote myself a function: ``` Function Set-StaticIPAddress { param ( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [String] $ComputerName , [Parameter(Mandatory = $true, Position = 1)] [Alias("IPv4Address")] [String] $IPAddress , [Parameter(Position = 2)] [String] $SubnetMask = "none" , [Parameter(Position = 3)] [String] $DefaultGateway = "none" , [Parameter(Position = 4)] [String[]] $DNSServers = ("172.16.1.36","172.16.1.78") , [Parameter(Position = 5)] [PSCredential] $Credential ) process { # There's some error-checking here that I've snipped out for convenience Write-Verbose "Testing connection to $ComputerName" if (-not (Test-Connection $ComputerName)) { Write-Error "Unable to connect to $ComputerName." return } Write-Verbose "Obtaining remote WMI reference" if ($Credential) { $wmi = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName -Filter "IPEnabled = 'True'" -Credential $Credential } else { $wmi = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName -Filter "IPEnabled = 'True'" } Write-Verbose "Attempting to set DNS servers" $wmi.SetDNSServerSearchOrder($DNSServers) Write-Verbose "Attempting to set dynamic DNS registration" $wmi.SetDynamicDNSRegistration($true) Write-Verbose "Attempting to set static IP address and subnet mask" $wmi.EnableStatic($IPAddress, $SubnetMask) Clear-DnsClientCache #This may not be necessary; I added it as a troubleshooting step Write-Verbose "Attempting to set default gateway" $wmi.SetGateways($DefaultGateway, 1) Write-Output $wmi } } ``` The trouble is, the EnableStatic method never seems to return a value - either a success or failure code. I tested this function on a machine sitting right next to me, and while the script was still waiting at the "Attempting to set static IP address and subnet mask" stage, I pulled up the configuration on the machine and found a static IP and subnet mask set. There was no default gateway (which makes sense, since I didn't get that far in the script). The computer in question didn't have network access, because the default gateway was missing. I have also tried running the same commands from an interactive shell, and the same "freeze" happens on the same command: ``` $wmi.EnableStatic($IPAddress, $SubnetMask) ``` My best guess is that changing the network adapter configuration is breaking the remote WMI connection. Is there a way to make this work so I can script the assignment of a static IP address 100% remotely? Edit: I MacGyvered another attempt which creates a ScriptBlock object and sends it to the remote computer using Invoke-Command. I had to do some interesting footwork to get an array of IP addresses to turn into a String literal, including the quotes, but I can now confirm that the script block has correct syntax and all that. Unfortunately, doing it this way causes my PS window to complain that the network connection has been lost (since the IP address has changed) and the script block does not complete successfully. ``` $wmiLiteral = '$wmi' # used so the script block actually creates and references a variable, $wmi $script = "$wmiLiteral = Get-WmiObject Win32_NetworkAdapterConfiguration -Filter ""IPEnabled = 'True'""; $wmiLiteral.EnableStatic(""$IPAddress"", ""$SubnetMask""); $wmiLiteral.SetGateways(""$DefaultGateway"", 1); $wmiLiteral.SetDNSServerSearchOrder($DNSServersList); Write-Output $wmiLiteral" Write-Verbose "Script block:`n-------------`n$script`n---------------" $scriptBlock = [scriptblock]::Create($script) Write-Verbose "Testing connection to $ComputerName" if (-not (Test-Connection $ComputerName)) { Write-Error "Unable to connect to $ComputerName." return } Write-Verbose "Invoking scriptblock" if ($Credential) { $output = Invoke-Command -ComputerName $ComputerName -ScriptBlock $scriptBlock -Credential $Credential } else { $output = Invoke-Command -ComputerName $ComputerName -ScriptBlock $scriptBlock } ```

Original source