Monthly Archive


Modifying MAC address


Another question on the forum brought up an interesting point. User want adapter name and mac address

PS> Get-NetAdapter | select Name, MacAddress

Name                         MacAddress
----                         ----------
WiFi                         28-18-78-D0-05-11
Bluetooth Network Connection 28-18-78-D0-05-12


but wanted to remove the hyphens in the mac address so tried

PS> Get-NetAdapter | select Name, MacAddress | foreach {$_.MacAddress -replace '-',''}


This doesn’t work because the foreach cmldet only knows to put put the new string when the hyphens have been replaced in the mac address. The name is effectively filtered out.


The answer is to use a calculated field in select-object like this

PS> Get-NetAdapter | select Name, @{N='MacAddress'; E={$_.MacAddress -replace '-',''}}

Name                         MacAddress
----                         ----------
WiFi                         281878D00511
Bluetooth Network Connection 281878D00512


N = Name and E= Expression though they are usually shorten for brevity as shown

Parsing ipconfig /displaydns with regular expressions

In yesterdays post I used a series of split operations to parse the strings produced by ipconfig /displaydns


Regular expressions should give a more power full way to perform this task. Not being a big fan of regular expressions I tend not to use them but for the sake of experimentation I thought I’d try and figure out a set of regex to use.


This is as far as I’ve got


$props = [ordered]@{
  RecordName = ""
  RecordType = ""
  Section    = ""
  TimeToLive = 0
  DataLength = 0
  Data       = ""

$recs = @()

$cache = ipconfig /displaydns
for($i=0; $i -le ($cache.Count -1); $i++) {
if ($cache[$i] -like '*Record Name*'){
    $rec = New-Object -TypeName psobject -Property $props
    $rec.RecordName = $cache[$i] -replace "(\s*\w*){2}(\s\.){5}(\s\:\s)", ""
    $rec.Section = $cache[$i+4] -replace "\s*\w*(\s\.){7}(\s\:\s)", ""
    $rec.TimeToLive = $cache[$i+2] -replace "(\s*\w*){3}\s(\s\.){4}(\s\:\s)", ""
    $rec.DataLength = $cache[$i+3] -replace "(\s*\w*){2}(\s\.){5}(\s\:\s)", ""
    $irec = ($cache[$i+5] -split ": ")
    $rec.RecordType = ($irec[0].TrimStart() -split ' ')[0]
    $rec.Data = $irec[1]

    $recs += $rec
else {

$recs | Format-Table –AutoSize


I still need to work out how to process the data and record type using regular expressions

Parsing ipconfig /displaydns


A recent question on the forum asked how you could get the contents on Windows 7 machines and earlier.

On later machines – Windows 8 and above -  its easy because you can use Get-DnsClientCache from the DnsClient module. This module is based on CIM classes that aren’t present on Windows 7 and earlier systems.


You can use ipconfig /displaydns to display the data but it looks like this

Record Name . . . . . :
Record Type . . . . . : 1
Time To Live  . . . . : 81966
Data Length . . . . . : 4
Section . . . . . . . : Additional
A (Host) Record . . . :


so you need to parse the strings into a format that you can work with. 


This is one solution


$props = [ordered]@{
  RecordName = ""
  RecordType = ""
  Section    = ""
  TimeToLive = 0
  DataLength = 0
  Data       = ""

$recs = @()

$cache = ipconfig /displaydns
for($i=0; $i -le ($cache.Count -1); $i++) {
if ($cache[$i] -like '*Record Name*'){
    $rec = New-Object -TypeName psobject -Property $props
    $rec.RecordName = ($cache[$i] -split -split ": ")[1]
    $rec.Section = ($cache[$i+4] -split -split ": ")[1]
    $rec.TimeToLive = ($cache[$i+2] -split -split ": ")[1]
    $rec.DataLength = ($cache[$i+3] -split -split ": ")[1]
    $irec = ($cache[$i+5] -split ": ")
    $rec.RecordType = ($irec[0].TrimStart() -split ' ')[0]
    $rec.Data = $irec[1]

    $recs += $rec
else {

$recs | Format-Table –AutoSize

Create an ordered hash table of output properties and an empty array to hold the results.


Get the output of  ipconfig /displaydns into $cache which will be an array of strings

Loop through $cache


if the record is like *Record Name*' then process that record and the next five records to give the results.  The actual data record is split twice to give the record type and the data – otherwise you’ll have to translate the numeric values in the Record Type line.


The results are put into an object which is added to the output array.


Continue looping through $cache until you meet the next line with a Record Name or end of file.


Finally display the results.


This works but is messy – I’m going to investigate alternatives

IPAM: 2 Reading data

Once you have your IPAM server configured you can start to read the data its collected.

If you are working against a remote IPAM server than you need to create a CIM session to that machine before doing anything else.

$cs = New-CimSession -ComputerName W12R2SUS


You can discover the domain you’re working against

£> Get-IpamDiscoveryDomain -CimSession $cs | fl

Name           :
DiscoverDc     : True
DiscoverDns    : True
DiscoverDhcp   : True
PSComputerName : W12R2SUS

The IPAM server configuration

£> Get-IpamConfiguration -CimSession $cs | fl

Version            :
Port               : 48885
ProvisioningMethod : Manual
GpoPrefix          :
HMACKey            : System.Security.SecureString
PSComputerName     : W12R2SUS


The servers – DHCP, DNS and DCs that IPAM is aware of:

£> Get-IpamServerInventory -CimSession $cs

RecommendedAction   : IPAM Access Unblocked
ManageabilityStatus : Managed
IPAMAccessStatus    : Unblocked
ServerType          : {DC, DNS, DHCP}
ServerName          : server02
Name                :
DnsSuffix           :
DomainName          :
ServerStatus        : NoChange
DataRetrievalStatus : Completed
IPv4Address         : {}
IPv6Address         :
PSComputerName      : W12R2SUS


The address space

£> Get-IpamAddressSpace -CimSession $cs

Name                           : Default
Type                           : ProviderAddressSpace
Owner                          :
Description                    : Default Provider IP Address Space
AssociatedProviderAddressSpace :
Tenant                         :
VMNetwork                      :
IsolationMethod                :
Ipv4PercentageUtilized         : 3.44827586206896
Ipv6PercentageUtilized         : 0
CustomConfiguration            :
PSComputerName                 : W12R2SUS


Individual subnets

£> Get-IpamSubnet -CimSession $cs -AddressFamily IPv4

Name                 :
NetworkId            :
NetworkType          : NonVirtualized
Overlapping          : False
NetworkSite          :
VmmLogicalNetwork    :
ProviderAddressSpace : Default
CustomerAddressSpace :
VlanId               :
Owner                :
PSComputerName       : W12R2SUS


and the address ranges for those subnets

£> Get-IpamRange -CimSession $cs -AddressFamily IPv4

Overlapping      : False
NetworkID        :
StartIPAddress   :
EndIPAddress     :
ManagedByService : MS DHCP
ServiceInstance  :
NetworkType      : NonVirtualized
Owner            :
PSComputerName   : W12R2SUS

IPAM: 1 Installation and configuration

IPAM stands for IP Address Management. It’s a feature in Windows Server 2012 R2 that enables you manage your DHCP and DNS servers as a whole rather than at the individual service or server level.


Installation of IPAM follows the standard approach for any Windows feature. Note that you can install IPAM on a Domain Controller but it won’t configure. IPAM is designed to be installed on a member server.

Full details on deploying IPAM server are available from here


I’m not going to run through the full deployment and configuration – just point out some issues and where you can use PowerShell to make things easier.


Once the IPAM feature is installed you have to provision the IPAM server. There isn’t a separate MMC for IPAM admin – you use Server Manager.  Provisioning an IPAM server can be done manually or by GPO.  Manual seemed best for lab/experiment/initial set up as can't swap from GPO to manual. You can use Windows Internal Database (WID) or SQL Server – I used WID.


You then need to configure your DHCP servers, DNS servers and domain controllers. This involves a number of group membership changes, firewall rule changes and a registry setting.


Create a group called IPAMUG and add the IPAN server into it.

New-ADGroup -Name IPAMUG -DisplayName IPAMUG -SamAccountName IPAMUG    -Description 'IPAM management group' -GroupCategory Security -GroupScope Universal

Add-ADGroupMember -Identity IPAMUG -Members (Get-ADComputer -Identity W12R2SUS)


Add IPAMUG to a number of groups

Add-ADGroupMember -Identity 'Event Log Readers' -Members (Get-ADGroup -Identity IPAMUG)

Add-ADGroupMember -Identity 'DHCP Users' -Members (Get-ADGroup -Identity IPAMUG)

Add-ADGroupMember -Identity 'DNSAdmins' -Members (Get-ADGroup -Identity IPAMUG)


I also found I had to add the IPAM server to the domain Administrators group to get the DNS data to come through.


Modify some firewall rules

$cs = New-CimSession -ComputerName W12R2SCDC01

Enable-NetFirewallRule  -DisplayName 'Remote Service Management (RPC)' -CimSession $cs -PassThru
Enable-NetFirewallRule  -DisplayName 'Remote Service Management (NP-In)' -CimSession $cs -PassThru
Enable-NetFirewallRule  -DisplayName 'Remote Service Management (RPC-EPMAP)' -CimSession $cs -PassThru

Get-NetFirewallRule -DisplayGroup 'Remote Service Management' -CimSession $cs |
ft  DisplayName, Enabled, Direction,Profile –a


There are a bunch of firewall rules that need setting. You can find the full list in the TechNet documentation.

For DHCP servers create an audit share


New-SmbShare -Name dhcpaudit -Path 'C:\Windows\System32\dhcp' -ReadAccess 'manticore\IPAMUG'
Set-SmbShare -Name dhcpaudit -Description 'DHCP audit share for IPAM' -Force

## restart DHCP service
Get-Service -Name DHCPServer | Restart-Service -PassThru


Enable event log monitoring on the DNS servers

$csd = Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\DNS Server' -Name CustomSD |
select -ExpandProperty CustomSD
$ipamsid = (Get-ADComputer -Identity W12R2SUS | select -ExpandProperty SID).value
$csd = $csd + "(A;;0x1;;;$ipamsid)"
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\DNS Server' -Name CustomSD -Value $csd –PassThru


I also had to manually add the IPAMUG group into the security permissions for the DNS servers. Didin’t seem to be a way to automate that bit.


IPAM has a PowerShell module – IpamServer – which contains lots of cmdlets:


Now I’ve got my IPAM server up and running its time to see what I can do with it

Creating NIC team without knowing the team members

I was asked how to create a NIC team only using the 1GB adapters without knowing how many 1gb NICs were on the server.


I think this should solve the problem


New-NetLbfoTeam -TeamMembers (Get-NetAdapter | where Speed -ge 1gb | select -ExpandProperty Name) -Name MyTeam


Use New-NetLbfoTeam to create the team. The team member names are generated by


Get-NetAdapter | where Speed -ge 1gb | select -ExpandProperty Name


By putting that statement in parentheses as the value for the –TeamMembers parameter the results are used as the value for the parameter.  Shouldn’t matter now how many NICs or what they are called.  You can modify the filter criteria as required.

DNS client settings

Following yesterdays post there are a couple of other cmdlets worth looking at if you want to dig into the DNS settings on your client machines.

Get-DnsClient wil show you the DNS relsted settings for all of your network interfaces by default.  To investigate a single interface


£> Get-DnsClient -InterfaceAlias vEthernet* | fl

InterfaceAlias                     : vEthernet (External01)
InterfaceIndex                     : 20
ConnectionSpecificSuffix           :
ConnectionSpecificSuffixSearchList : {}
RegisterThisConnectionsAddress     : True
UseSuffixWhenRegistering           : False

InterfaceAlias                     : vEthernet (Internal01)
InterfaceIndex                     : 16
ConnectionSpecificSuffix           :
ConnectionSpecificSuffixSearchList : {}
RegisterThisConnectionsAddress     : True
UseSuffixWhenRegistering           : False


You can also see the DNS servers a particular interface will use:

£> Get-DnsClientServerAddress -InterfaceAlias vEthernet*

InterfaceAlias               Interface Address ServerAddresses
                             Index     Family
--------------               --------- ------- ---------------
vEthernet (External01)              20 IPv4    {}
vEthernet (External01)              20 IPv6    {}
vEthernet (Internal01)              16 IPv4    {}
vEthernet (Internal01)              16 IPv6    {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}

Have you been talking to strangers?

Want to know the machines to which your machine has been connecting?


Try looking in the client DNS cache:




will show a wealth of useful data.  All in the form:

£> Get-DnsClientCache | where Entry -like '**' | fl *

TTL                   : 39
Caption               :
Description           :
ElementName           :
InstanceID            :
Data                  :
DataLength            : 8
Entry                 :
Name                  :
Section               : 1
Status                : 0
TimeToLive            : 39
Type                  : 5
PSComputerName        :
CimClass              : ROOT/StandardCimv2:MSFT_DNSClientCache
CimInstanceProperties : {Caption, Description, ElementName, InstanceID...}
CimSystemProperties   : Microsoft.Management.Infrastructure.CimSystemProperties

TTL                   : 39
Caption               :
Description           :
ElementName           :
InstanceID            :
Data                  :
DataLength            : 4
Entry                 :
Name                  :
Section               : 1
Status                : 0
TimeToLive            : 39
Type                  : 1
PSComputerName        :
CimClass              : ROOT/StandardCimv2:MSFT_DNSClientCache
CimInstanceProperties : {Caption, Description, ElementName, InstanceID...}
CimSystemProperties   : Microsoft.Management.Infrastructure.CimSystemProperties



What is interesting is the Time To Live settings on some of the records:

£> Get-DnsClientCache | sort TTL -Descending | group TTL -NoElement

Count Name
----- ----
    7 74538
    1 70203
    1 64639
    1 53300
    1 53299
    1 16441
    2 9308
    1 2579
    1 2573
    3 2475
    6 2469
    2 2327
    2 1986
    1 1890
    1 1089
    1 999
    2 899
    2 891
    2 878
    3 728
    1 724
    6 711
    1 631
    1 458
    1 412
    1 363
    1 133
   15 0


Some of those records will be around for a long time!

Working with Server Core–setting IP addresses

When you create a new Windows machine it defaults to using DHCP to get an IP address. While that is fine for client machines most people apply a static address to their servers. Up until Windows 2012 you had 2 choices – use the GUI or use PowerShell and WMI.

Server 2012 introduced a host of cmdlets for administering your network settings.  Setting an IP address is simple as this:

New-NetIPAddress -InterfaceIndex 12 -IPAddress '' -AddressFamily IPv4 -PrefixLength 24


I haven’t used it but you can also set the default gateway which would make the command

New-NetIPAddress -InterfaceIndex 12 -IPAddress '' -AddressFamily IPv4 -PrefixLength 24 -DefaultGateway ''


The DNS server addresses can be set like this

Set-DnsClientServerAddress -InterfaceIndex 12 -ServerAddresses ''


The cmdlets are from the NetTCPIP and DnsClient modules respectively.


Subnets and prefixes

Sounds a bit like an old time role playing game but is actually a useful piece of knowledge.

You can define a subnet mask in 2 ways. Either use  the full mask e.g.  or define the number of bits in the mask 21 which is known as the prefixlength in the PowerShell networking cmdlets.

But can you relate a full subnet mask to the number of bits.  Some are obvious but the others I need to work out. 

Time for a quick PowerShell function:

function show-subnetmask{
  foreach ($prefixlength in  8..30) {
    switch ($prefixlength){
   {$_ -gt 24}
                  $bin = ('1' * ($prefixlength - 24)).PadRight(8, '0')
                  $o4 = [convert]::ToInt32($bin.Trim(),2)
                  $mask = "255.255.255.$o4"

    {$_ -eq 24}
                  $mask = ''

    {$_ -gt 16 -and $_ -lt 24}
                  $bin = ('1' * ($prefixlength - 16)).PadRight(8, '0')
                  $o3 = [convert]::ToInt32($bin.Trim(),2)
                  $mask = "255.255.$o3.0"

    {$_ -eq 16}
                  $mask = ''
    {$_ -gt 8 -and $_ -lt 16}
                  $bin = ('1' * ($prefixlength - 8)).PadRight(8, '0')
                  $o2 = [convert]::ToInt32($bin.Trim(),2)
                  $mask = "255.$o2.0.0"

    {$_ -eq 8} 
                  $mask = ''
                  $mask = ''

    New-Object -TypeName psobject -Property @{
      PrefixLength = $prefixlength
      Subnetmask = $mask

Most people will be using subnets between 8 and 30 bits in length so start with that range and for each value work through the switch statement.  If the value is 8,16 or 24 the subnet mask can be set directly. Otherwise it needs to be calculated. The calculations are the same – the difference is which octet of the subnet mask is affected.

For instance if the prefix length is between 16 and 24 (exclusive)

$bin = ('1' * ($prefixlength - 16)).PadRight(8, '0')
$o3 = [convert]::ToInt32($bin.Trim(),2)

$mask = "255.255.$o3.0"

Convert the number to a binary representation – the amount you need to subtract depends on the octet with which you are working

Convert the binary to an integer and insert into the subnet mask string.

An object is output that has the subnet mask and prefix length as properties.

Put the function in a module on your module path and you’ll be able to use it as a quick lookup when you need to convert subnet masks to prefix lengths or vice versa