How do I permanently set a static IP Address in Windows 10 using PowerShell for my automated OS build process? - powershell

When I started learning how to do this by watching videos, I learned about IP address InterfaceIndexes. I learned that I can't set an IP Address without knowing the IP Address's InterfaceIndex first. That seemed to be different on every computer I look at and seemed to be random. Then, I learned that you can use an IP Address Alias. On a fresh Windows install, it seemed that the IP Address Alias Ethernet0 was going to be a constant that I could rely on. So, with my primitive PowerShell skills, I thought I could reach out and grab the PC's IP Address and check to see if it matched what it was supposed to be. If it wasn't, wipe out whatever Ethernet0 is, and create a new IP Address with the alias of Ethernet0. Of course the first time I did this it worked perfectly and I moved on. I had a static IP address called Ethernet0 with the specified IP address. I just went in and looked and I have 2 available NICs. One is called "Ethernet" and the other is "Ethernet2". Nether of them have a static IP Address. I'm assuming the PC wants to set random alias names upon a restart? I'm a little confused on what happened. Of course when I run my method again, I get an error that says "No InterfaceAlias equal to ethernet0", so my code doesn't work. I'm obviously way off on how I should be approaching this. I want to do a fresh install and run a configuration script to set everything up without any GUI interaction. I don't work in an enterprise domain type of environment, and have to create my own process. Please help further my PowerShell wisdom, as only a Padawan I am.
function SetIp {
$ipv4 = (Test-Connection -ComputerName $env:COMPUTERNAME -Count 1) .IPV4Address.IpAddressToString
if($ipv4 -eq "my.ip.add.res") {
Write-Host "Do Nothing as the IP has already been set"
}
else {
Remove-NetIPAddress -InterfaceAlias ethernet0
New-NetIPAddress -IPAddress my.ip.add.res -InterfaceAlias ethernet0 -PrefixLength 16
Write-Host "IP Address has been set"
}
}

You can see all the available info about the NetIPInterface objects with Get-NetIPInterface | Select * -First 1. Some useful properties are ConnectionState,AddressFamily, or Dhcp. For example, try something like this to find valid ones:
Get-NetIPInterface | Where {
$_.ConnectionState -eq 'Connected' -and
$_.AddressFamily -eq 'IPV4' -and
$_.InterfaceAlias -like 'Eth*' -and
# check if in your local subnet
($_.DHCP -eq 'Enabled' -or ($_|Get-NetIPAddress).IPv4Address -like '1.2.3.*')
}
You can run into all sorts of things though, so it depends on how controlled your environment is:
Wifi and/or Ethernet are connected
Second Ethernet, or laptop dock creates new net interfaces
VPN software creates a new 'Ethernet' interface
If you need to ask a user for input, you could do it with gridview:
$Selected = Get-NetIPInterface |
? {$_.AddressFamily -eq 'IPV4' -and $_.InterfaceAlias -notlike 'Loopback*'} |
Select IFIndex,InterfaceAlias,ConnectionState |
# Ask the user to select the interface
Out-GridView -Title 'Please select the correct interface' -OutputMode Single
Set-NetIPInterface -InterfaceIndex $Selected.ifIndex -AddressFamily IPv4 ## etc...
That said, just setting up DHCP to handle this will almost always be easier. DHCP reservations are generally just as good as static IPs for user machines

Related

Getting interfaces and their DNS servers that are STATIC (not dhcp allocated)

I'm trying to ge the DNS servers of network interfaces via WMI that are static (placed by the user). I have this script that works, except for the static part of course:
Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object {$_.DNSServerSearchOrder -ne $null} | Select DnsServerSearchOrder,Index,InterfaceIndex
This leads to an output like so:
DnsServerSearchOrder Index InterfaceIndex
-------------------- ----- --------------
{192.168.122.1} 1 6
{1.1.1.1} 2 10
The interface with 192.168.122.1 has it's DNS setup to DHCP so that value is not good for me. How do I filter out interfaces where dns is not static? Any ideas?
netsh interface ip show config:
Configuration for interface "Ethernet"
DHCP enabled: Yes
IP Address: 192.168.122.130
Subnet Prefix: 192.168.122.0/24 (mask 255.255.255.0)
Default Gateway: 192.168.122.1
Gateway Metric: 0
InterfaceMetric: 35
DNS servers configured through DHCP: 192.168.122.1
Register with which suffix: Primary only
WINS servers configured through DHCP: None
Configuration for interface "Ethernet 2"
DHCP enabled: Yes
IP Address: 10.0.0.17
Subnet Prefix: 10.0.0.0/24 (mask 255.255.255.0)
Default Gateway: 10.0.0.1
Gateway Metric: 0
InterfaceMetric: 35
Statically Configured DNS Servers: 1.1.1.1
Register with which suffix: Primary only
WINS servers configured through DHCP: None
Notice the difference in terms between Statically Configured DNS Servers and DNS servers configured through DHCP. I figured I might parse this output but I'm not sure if I can rely on this text if windows language/locale is changed and I'd rather use the WMI interface if possible.
I thought this might be available in the System.Net.NetworkInformation namespace, but evidently not. I looked through a few lower-level Windows networking APIs thinking certainly it must exist somewhere in there, but no such luck. After running dumpbin on netsh.exe to see what kinds of libraries/functions it's consuming, I did get an idea of one other place to look: the registry.
As it happens, if you look in the registry under the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\ key you will see a key for each network interface with the name in GUID format. Within an interface's key you will find two values of interest: DhcpNameServer and NameServer. On my client system where the DNS server is set by DHCP, DhcpNameServer contains that DNS server's IP address and NameServer contains an empty [String]. If I manually set a DNS server while keeping the automatically-assigned address for the interface itself, NameServer then contains that manually-set DNS server address while DhcpNameServer still contains the same DNS server specified by DHCP.
Based on these observations, it would seem that...
The DhcpNameServer value always contains the DNS server(s) specified by DHCP.
The NameServer value always contains the DNS server(s) specified manually.
When you query the system for its nameservers (e.g. via the Win32_NetworkAdapterConfiguration.DNSServerSearchOrder property) the result will contain the value of NameServer, if provided, otherwise the value of DhcpNameServer, if provided. In other words, the system tells you which DNS servers are currently being used, but not how their addresses were specified.
To determine if an interface has manually-assigned DNS servers, check if NameServer has a non-empty value.
Thus, given an interface with ID $interfaceID, you can build a path to its registry key like this...
$interfaceKeyPath = "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\$interfaceID"
...and then retrieve the dynamically-assigned and manually-assigned nameserver values like this...
Get-ItemProperty -Path $interfaceKeyPath -Name 'DhcpNameServer', 'NameServer'
That just leaves the matter of from where you get the value for $interfaceID, and there are numerous sources although the trick will be excluding undesirable interfaces (for example, on my Windows 10 system I have a packet capture loopback adapter and a hypervisor adapter that I'd want to be excluded from such a query). The most compatible way (dating back to .NET 2.0) would be the Id property of the NetworkInterface class...
[System.Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces() `
| Select-Object -ExpandProperty 'Id'
...although the only useful properties on which to filter are Name and NetworkInterfaceType.
On Windows Vista and above the Win32_NetworkAdapter class provides a GUID property...
Get-WmiObject -Class 'Win32_NetworkAdapter' -Property 'GUID' -Filter 'PhysicalAdapter = true'
...although even when filtering on PhysicalAdapter it still returns the loopback and hypervisor adapters and I'm not seeing any definitive property or class relation that can be used to select only hardware adapters.
The Win32_NetworkAdapterConfiguration class is much the same...
Get-WmiObject -Class 'Win32_NetworkAdapterConfiguration' -Property 'SettingID'
...with no properties to filter out non-hardware or even non-physical adapters.
On (I think) Windows 8 and above there's the Get-NetConnectionProfile cmdlet...
Get-NetConnectionProfile | Select-Object -ExpandProperty 'InstanceID'
which is documented to get "a connection profile associated with one or more physical network adapters" and, on my system, it does only return my physical adapter.
There is also the Get-NetAdapter cmdlet...
Get-NetAdapter -Physical `
| Where-Object -Property 'EndPointInterface' -NE -Value $true `
| Select-Object -ExpandProperty 'InterfaceGuid'
I found that passing the -Physical parameter excluded the hypervisor adapter but not the loopback adapter, so filtering out where EndPointInterface is $true was necessary to eliminate that. The HardwareInterface and Virtual properties might also be of interest.
Another option would be to invoke the Get-NetAdapterHardwareInfo cmdlet, which seems to know how to distinguish true hardware adapters, and let that determine which adapters are retrieved by Get-NetAdapter...
Get-NetAdapterHardwareInfo `
| Get-NetAdapter `
| Select-Object -ExpandProperty 'InterfaceGuid'
The Get-Net* cmdlets above return CIM instances so, for example, instead of Get-NetAdapter -Physical you could use something like...
Get-WmiObject -Namespace 'Root\StandardCimv2' -Class 'MSFT_NetAdapter' `
-Property 'InterfaceGuid' -Filter 'HardwareInterface = true AND EndPointInterface = false'
to retrieve the MSFT_NetAdapter instances just the same. I'm not really sure what the guidance is on using one versus the other. It would seem like one should prefer the cmdlets, and yet, unlike WMI/CIM, they offer limited/no parameters for efficiently filtering the output or specifying which properties are desired so you have to do that in the pipeline. I think it's noteworthy, though, that I wasn't able to find any current documentation for these MSFT_* class; they all say they're no longer updated, except for the MSFT_NetConnectionProfile class for which I couldn't find any documentation page at all. That says to me Microsoft doesn't want you relying on any definite structure of these classes, and yet if the cmdlets just pass along those class instances...I'm not sure how can you meaningfully and reliably interact with them if nothing is documented.
Also, keep in mind that you'll want to prefer Get-CimInstance and its ilk over Get-WmiObject, where possible. I don't think I've yet encountered an instance where it was any more complicated than changing Get-WmiObject to Get-CimInstance, although there are more differences (not necessarily bad) than the name.
After enough bashing I found a solution but I'm not 100% positive is the right path. On all DHCP DNS servers the DNS values contain a single ip address and that IP address is equal to the Default Gateway value. When those values match we're dealing with a DHCP DNS server and not statically configured.

How do I completely wipe out NIC settings with Powershell?

Have a smidge of a problem. I am trying to completely blank out the IP address, subnet mask, and default gateway of a single NIC on one of my VMs.
I open up IPv4 Properties on that NIC and set it to DHCP (there is no DHCP server available to it and it isn't getting a Windows APIPA address) and then I look in Advanced and make sure there aren't alternate addresses assigned. I close out all of the windows. Then, I open up CMD and type ipconfig and it shows that it has an IP address, subnet mask, and a default gateway. I even tried Disabling and Enabling the NIC and typing Restart-NetAdapter -Name "Ethernet" and there are no changes.
In PS, I type Get-NetAdapterAdvancedProperty -DisplayName "Network Address" and it shows -- under the DisplayValue.
For some reason, and I'm not sure why (I didn't give it the ol' College Try), but when I type Set-NetIPAddress -InterfaceAlias "Ethernet" -IPAddress "0.0.0.0" it shows red. I try putting in a valid address to see if maybe the cmdlet won't take all zeros and it does the same thing. I checked the man page and I'm fairly sure that the format is correct (I tried $ip = #("0.0.0.0") and gave it $ip and $ip[0] but it still, no joy).
I just want all of the NIC settings wiped and it seems like it is but ipconfig and Get-NetIPAddress, and Get-NetIPConfiguration keep showing addresses whereas Get-NetAdapterAdvancedProperty -DisplayName "Network Address" show that it's blank.
Why won't it let me wipe the configs (without doing an OOBE SysPrep)? I feel like the answer is probably something simple that I'm just overlooking but I haven't really found anything online--it's mostly just ways to work with your NIC configurations within Powershell.
Could anyone help shine some light on what is actually going on?
Thanks.
If you have several NICs, Get-NetAdapter will list all adapters with their respective index, Get-NetAdapter -ifIndex $ | Get-NetIPAddress | Remove-NetIPAddress (substitute $ with desired adapter index) will wipe IP configuration.
In case of a vm with a single adapter you can omit the index:
Get-NetAdapter | Get-NetIPAddress | Remove-NetIPAddress

New-NetLbFoTeam: Unknown or Random InterfaceAlias names

I'm trying to automate the create of a NIC team during an unattended Windows Server 2012 R2 install.
I've got the following PowerShell code:
New-NetLbFoTeam -Name "LANTeam" -TeamMembers "Ethernet", "Ethernet 2" -TeamNicName "LAN" -TeamingMode SwitchIndependent -LoadBalancingAlgorithm TransportPorts -Confirm:$false -ErrorAction SilentlyContinue
That works well for my Dell servers, but the HP servers Windows randomly gives InterfaceAliases to. One install Ethernet 2 could be the Broadcom, the next it could be the NC373i card.
What I'm trying to accomplish is set the -TeamMembers parameter to be the two NICs that match "HP NC373i*" wildcard for the InterfaceDescription, or have a valid DHCP address. The other team I'll do something similar, but don't retrieve a valid IP address.
I've tried setting a hash table, but not getting it to stick in there correctly.
Any assistance would be greatly appreciated!
I was able to figure it out on my own. I output the get-netadapter output to a variable, and added that:
$adapters = Get-netAdapter –InterfaceDescription “HP NC*”
$nicList = #()
Foreach ($nic in $adapters) {$nicList += $nic.Name}
$team = New-NetLbfoTeam -Name “LANTeam” -TeamNicName “LAN” -TeamMembers ($nicList) -TeamingMode SwitchIndependent -LoadBalancingAlgorithm HyperVPort -Confirm:$false

How do I assign a vNIC to a distributed port group based on its current port group membership?

I have a VM with 3 network adapters:
vNIC1 : OldPortGroup1
vNIC2 : OldPortGroup2
vNIC3 : OldPortGroup3
I need to change the port group of these adapters to NewPortGroup1, NewPortGroup2, NewPortGroup3. I do not know which vNIC is currently assign to what port group but I do know the old port group names. I need to assign the New port group to the vNIC based on its membership to the old port group. The following code does not work:
Get-Datacenter MyDatcenter | Get-VM MyVM | Get-NetworkAdapter | Where-Object { $_.NetworkName -like "OldPortGroup1" } | Set-NetworkAdapter -NetworkName NewPortGroup1
This will return all the vNICs for all virtual machines that are on that network. It does not obey the -VM parameter on Get-VM. As far as I am concerned it is impossible to do what I am thinking. I have tried if statements, switch statements, etc. Any ideas?
Apparently it doesn't work right if you don't actually manually import the Vds plugin. This can be done using the following command:
Get-PSSnapin -Registered -Name VMware.VimAutomation.Vds

How to Wait till a DHCP server assign's IP to a first time boot VM with a Sysprepped vhd attached to it using PowerShell in Hyper-V version 3.0

I'm going through a scenario where i boot a Newly built VM with a sysprepped vhd attached, once the setup process completes with installing devices etc and the OS gets loaded i wanted to wait till this entire process finishes and the VM is assigned an IP address via DHCP.
PS C:\Users\Administrator> Start-VM -Name dv.VMWIN2K8R2-3.Hng
PS C:\Users\Administrator> while ((Get-VM -Name dv.VMWIN2K8R2-3.Hng | select -ExpandProperty networkadapters).ipaddress[0] -match $null)
{
Start-Sleep 3
Write-Host "Waiting to Acquire IP Address" -ForegroundColor green
}
$ipaddress=(Get-VM -Name dv.VMWIN2K8R2-2.Hng | select -ExpandProperty networkadapters).ipaddresses[0]
Write-Host "VM has acquired an IPAddress of $ipaddress"
I Tried the above snippet but the while loop never run's, i have noticed that while VM is shutdown the ip address parameter is blank so i thought to match it till it shows Null and when i boot up the VM and once the server gets an IP address by DHCP it should exit the while loop and print the IP address on console.
The IP is probably not null, so it's doing exactly what it should. The IP is probably 169.254.x.x, or at least that's what happens to me before I pick up DHCP. How about choosing the first octet of the address it should have after it picks up an address and using that?
EDIT: Maybe it's not 169 as I thought, after re-reading your post. My advice still applies. Try using something like this: While (!($ip -like "10.*")
If there is no network stack there are no addresses and I think you'll find the array is not there. Chris is on the right track. I think you'll need to not do what you're doing but first test to see if ipaddress is a property, is an array, and has at least 1 item in it before checking the value of that item.
Hi Guys i was able to solve the issue, i used the Get-VMNetworkAdapter Cmdlet and it solved the issue
while (((Get-VMNetworkAdapter $vmname | select -ExpandProperty ipaddresses) -eq $null -or ((Get-VMNetworkAdapter $vmname | select -ExpandProperty ipaddresses) -match "169.")))
{
Write-Progress -Activity "Waiting for VM to Aquire an IPAddress"
}