Strange DNS record duplication with Powershell? - powershell

While recently working with the native Powershell DNS commandlets, specifically Get-DNSServerResourceRecord, I noticed something strange that does not make sense to me.
When I look into my zone using native DNS tools, LDAP query tools, or even ADSIedit, I see only a single DNS object representing a given hostname.
However, when I do the same with Powershell, I instead get two objects for a given host, one for the NETBIOS name, and the other for the FQDN. All other attributes are the same, including the IP.
For example, if I had a computer named computer1: This is what I see.
PS C:\> Get-DnsServerResourceRecord -ZoneName 'mydomain.local' -RRType A -ComputerName 'DNSServer1' | Where-Object {$_.hostname -like "Computer1*"} | fl *
DistinguishedName : DC=computer1.mydomain.local,DC=mydomain.local,cn=MicrosoftDNS,DC=DomainDnsZones,DC=mydomain,DC=local
HostName : COMPUTER1.mydomain.local
RecordClass : IN
RecordData : DnsServerResourceRecordA
RecordType : A
Timestamp :
TimeToLive : 01:00:00
Type : 1
PSComputerName :
CimClass : root/Microsoft/Windows/DNS:DnsServerResourceRecord
CimInstanceProperties : {DistinguishedName, HostName, RecordClass, RecordData...}
CimSystemProperties : Microsoft.Management.Infrastructure.CimSystemProperties
DistinguishedName : DC=computer1,DC=mydomain.local,cn=MicrosoftDNS,DC=DomainDnsZones,dc=mydomain,dc=local
HostName : COMPUTER1
RecordClass : IN
RecordData : DnsServerResourceRecordA
RecordType : A
Timestamp :
TimeToLive : 01:00:00
Type : 1
PSComputerName :
CimClass : root/Microsoft/Windows/DNS:DnsServerResourceRecord
CimInstanceProperties : {DistinguishedName, HostName, RecordClass, RecordData...}
CimSystemProperties : Microsoft.Management.Infrastructure.CimSystemProperties
I'm so confused at why Powershell is showing this and where it's actually pulling it from. I cannot locate those FQDN objects using native LDAP tools, even ADFind.
Is this some weird artifact/bug of the Powershell DNS cmdlets? Or does DNS records store dual entries for a given host, but only display one using native tools?
Neither make sense to me, as I would not expect a cmdlet to just make up DN values on the fly, and this doesn't occur for all host records.The latter does not seem possible as this is not occurring for all records in the zone. I have about 100 more records without the fqdn than with (10926 vs 10824).
EDIT If it helps, here is an ADFind query for the same object (and wildcard).
C:\temp>adfind -h dnsserver1 -domaindns -f "(&(name=computer1*))" name
AdFind V01.57.00cpp Joe Richards (support#joeware.net) November 2021
Using server: dnsserver1.mydomain.local:389
Directory: Windows Server 2016
Base DN: DC=DomainDnsZones,DC=ad,DC=ewsad,DC=net
dn:DC=computer1,DC=mydomain.local,CN=MicrosoftDNS,DC=DomainDnsZones,DC=mydomain,DC=local
>name: computer1
1 Objects returned

I can confirm this behavior.
In powershell, this returns 2 results for many of the computers (maybe all, I didn't check)
Get-DnsServerResourceRecord -ZoneName 'domain.com' -RRType A -ComputerName dnserver1 | where hostname -like Computer1*
DistinguishedName : DC=Computer1.domain.com,DC=domain.com,cn=MicrosoftDNS,DC=DomainDnsZones,DC=domain,DC=com
HostName : Computer1.domain.com
RecordClass : IN
RecordData : DnsServerResourceRecordA
RecordType : A
Timestamp : 12/8/2022 9:00:00 AM
TimeToLive : 00:20:00
Type : 1
PSComputerName :
CimClass : root/Microsoft/Windows/DNS:DnsServerResourceRecord
CimInstanceProperties : {DistinguishedName, HostName, RecordClass, RecordData...}
CimSystemProperties : Microsoft.Management.Infrastructure.CimSystemProperties
DistinguishedName : DC=Computer1,DC=domain.com,cn=MicrosoftDNS,DC=DomainDnsZones,DC=domain,DC=com
HostName : Computer1
RecordClass : IN
RecordData : DnsServerResourceRecordA
RecordType : A
Timestamp : 12/8/2022 9:00:00 AM
TimeToLive : 00:20:00
Type : 1
PSComputerName :
CimClass : root/Microsoft/Windows/DNS:DnsServerResourceRecord
CimInstanceProperties : {DistinguishedName, HostName, RecordClass, RecordData...}
CimSystemProperties : Microsoft.Management.Infrastructure.CimSystemProperties
But a dsquery results in one record.
dsquery computer -name computer1* -s dnsserver1
"CN=Computer1,OU=Computers,DC=domain,DC=com"
You can confirm only one of these is a real AD object.
$recordlist = Get-DnsServerResourceRecord -ZoneName 'domain.com' -RRType A -ComputerName dnserver1 | where hostname -like Computer1*
foreach($record in $recordlist){
Write-Host "Checking DN $($record.DistinguishedName)" -ForegroundColor Cyan
$found = $record.DistinguishedName |
Get-ADObject -ErrorAction SilentlyContinue
if($found){
Write-Host "Record found in AD" -ForegroundColor Green
}
else{
Write-Host "Record not in AD" -ForegroundColor DarkGray
}
}
So I must conclude thus far the evidence does indicate the Get-DnsServerResourceRecord is adding a duplicated record with the FQDN as well. Hopefully someone can find or knows why it was implemented in this manner.

Related

PowerShell 5.1 using ExpandedProperty but not getting desired output

Given:
PowerShell 5.1
If I run the following:
Get-Service -ComputerName WKSP000D1E3F -DisplayName *bit*
I get this:
Status Name DisplayName
------ ---- -----------
Stopped BDESVC BitLocker Drive Encryption Service
Stopped Check Point Bit... Check Point Endpoint Security Bitlo...
But I want to expand both Name and DisplayName, so I do this:
Get-Service -ComputerName WKSP000D1E3F -DisplayName *bit* | Select -ExpandProperty Name
and get this:
BDESVC
Check Point Bitlocker Management
How do I get all the columns with column headers, like the first output above except without ellipses?
Status Name DisplayName
------ ---- -----------
Stopped BDESVC BitLocker Drive Encryption Service
Stopped Check Point Bit... Check Point Endpoint Security Bitlo...
Get-Service -DisplayName *wmi*
Status Name DisplayName
------ ---- -----------
Stopped wmiApSrv WMI Performance Adapter
Running WMIRegistrationSe… Intel(R) Management Engine WMI Provid…
I find myself using | Out-GridView if desired output isn't being shown.
Get-Service -DisplayName *wmi* |
Out-GridView
Out-GridView Result
Alternatively, you could use | Format-List if you're not set on using Table View
Get-Service -DisplayName *wmi* |
Format-List
Name : wmiApSrv
DisplayName : WMI Performance Adapter
Status : Stopped
DependentServices : {}
ServicesDependedOn : {}
CanPauseAndContinue : False
CanShutdown : False
CanStop : False
ServiceType : Win32OwnProcess
Name : WMIRegistrationService
DisplayName : Intel(R) Management Engine WMI Provider Registration
Status : Running
DependentServices : {}
ServicesDependedOn : {}
CanPauseAndContinue : False
CanShutdown : False
CanStop : True
ServiceType : Win32OwnProcess
If you only want Status,Name,DisplayName headers,
Get-Service -DisplayName *wmi* |
Select-Object -Property Status, Name, DisplayName |
Format-List
Status : Stopped
Name : wmiApSrv
DisplayName : WMI Performance Adapter
Status : Running
Name : WMIRegistrationService
DisplayName : Intel(R) Management Engine WMI Provider Registration
The ... are just a display problem (the data is there in full).
If you use Select-Object's -ExpandProperty parameter, you by definition only get property values, and since these values are strings in your case, that's all you get (albeit without truncation).
To prevent the for-display truncation, pipe to Format-Table -AutoSize, though note that this requires PowerShell to collect all output from the input command first, before starting to display output (see next section for alternatives).
Get-Service -ComputerName WKSP000D1E3F -DisplayName *bit* | Format-Table AutoSize
Note: Since the console (terminal) window width is always the limiting factor, -AutoSize can result in fewer columns getting displayed.
If possible, you can exclude columns that aren't of interest, by specifying only those that are, via -Property (you may omit this parameter name, becasue it is positionally implied); e.g.:
Get-Service -ComputerName WKSP000D1E3F -DisplayName *bit* |
Format-Table -Property Status, Name -AutoSize
Alternatives that avoid -AutoSize and its collect-everything-first behavior:
Use -Wrap, which doesn't truncate, but uses (artificial) line breaks to spread values that don't fit into the column across multiple lines.
Get-Service -ComputerName WKSP000D1E3F -DisplayName *bit* | Format-Table -Wrap
If you know the maximum width of a column of interest ahead of time, you can use a calculated property to prescribe a column's width; e.g.:
Get-Service -ComputerName WKSP000D1E3F -DisplayName *bit* |
Format-Table Status,
#{ Expression='Name'; Width=40 },
DisplayName

powershell cmdlet doesn't return output properties stated in documentation

I try to write a PowerShell script that outputs open SMB connections on a server so that I can see who's working with the server and with which directory. For that, I found cmdlet get-smbopenfile which looks pretty handy.
The documentation https://learn.microsoft.com/de-de/powershell/module/smbshare/Get-SmbOpenFile?view=windowsserver2022-ps says that the get-smbopenfile output contains properties ClientComputerName and ClientUserName but on my box (Windows Server 2022) the only properties returned are FileId, SessionId and Path. I can't make it return any additional properties.
The documentation seems to be crystal clear on that. What am I missing?
get-smbopenfile | fl * to see everything, otherwise powershell commands use a format file with a default view. All commands are like this. You can still reference any property, even without fl or format-list.
get-smbopenfile | select -first 1 | fl *
SmbInstance : Default
ClientComputerName : [::1]
ClientUserName : AD\SERVER$
ClusterNodeName :
ContinuouslyAvailable : False
Encrypted : False
FileId : 1546188227134
Locks : 0
Path : \eventlog
Permissions : 1180064
ScopeName : *
SessionId : 1546188226562
ShareRelativePath : eventlog
Signed : False
PSComputerName :
CimClass : ROOT/Microsoft/Windows/SMB:MSFT_SmbOpenFile
CimInstanceProperties : {ClientComputerName, ClientUserName, ClusterNodeName, ContinuouslyAvailable...}
CimSystemProperties : Microsoft.Management.Infrastructure.CimSystemProperties

Obtain display name with spaces from powershell or cmd - AzuredAD only

I am try to pull just the display name (first and last name) from cmd or powershell. (AzureAD - not on-prem AD)
I have gotten a couple of different commands but all of them keep the name together.
Examples:
$env:UserName = jatonjustice
[System.Security.Principal.WindowsIdentity]::GetCurrent().Name = azureAD\jatonjustice
I am trying to find a way where the result has the first and last name separated or maybe just the first and just the last name as an alternate idea.(Like: `Jaton Justice') I can't parse it myself as I don't know what the display name will be upfront. (AzureAD - not on-prem AD)
Any ideas for this?
research:
How do I get the current username in Windows PowerShell?
How to get an Azure Active Directory username in Windows Powershell?
Thanks
$env:UserName should return SamAccountName, rather than user's name.
'Get-ADUser -Property *' should show you all info about the user you are querying, you should be able to find a property called GivenName and Surname.
$search = [adsisearcher]"(SamAccountName=$env:USERNAME)"
$search.PropertiesToLoad.AddRange(#('givenname','sn'))
$adAccount = $search.FindOne()
$firstName = $adAccount.Properties.givenname
$lastName = $adAccount.Properties.sn
$fullname = "$firstName $lastName"
All you are after is explained and detailed by examples in the PowerShell help files. More on that later.
As for ...
'but all of them keep the name together. Examples:'
...and they are supposed to, by design.
Using those, you are asking for the local logged-on username (SamAccountName, which is a short name defined in the user profile on the localhost and in ADDS/AAD - for the UPN, SamAccountName#DomainName.com) with those, not ADDS/AAD name specifics.
If you want First and last from the locally logged-on user, then you have to have that populated in the account, or you have to ask for it from ADDS/AAD. What is your use case?
If you are on PSv5x and higher there is this module:
# Results
<#
Get-Module -Name '*local*'
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Binary 1.0.0.0 Microsoft.PowerShell.LocalAccounts {Add-LocalGroupMember, Disable-LocalUser, Enable-LocalUser, Get-LocalGroup...}
#>
You get local user details this way.
Get-LocalUser | Select-Object -Property '*' -First 1
# Results
<#
AccountExpires :
Description : Built-in account for administering the computer/domain
Enabled : False
FullName :
PasswordChangeableDate :
PasswordExpires :
UserMayChangePassword : True
PasswordRequired : True
PasswordLastSet :
LastLogon :
Name : Administrator
SID : S-1-5-21-2047949552-857980807-821054962-500
PrincipalSource : Local
ObjectClass : User
#>
Note that on his local account, Fullname is not populated. So, obviously, you can't use that, nor can you extrapolate from the name/SamAccoutnName property.
So, you can ask for the locally logged on username in a number of ways,...
# Get loggedon users
$env:UserName
[System.Environment]::UserName
[System.Security.Principal.WindowsIdentity]::GetCurrent().Name
(Invoke-CimMethod -InputObject $(
Get-CimInstance Win32_Process -Filter "name = 'explorer.exe'"
) -MethodName GetOwner).User
Get-WmiObject Win32_Process -Filter "name='explorer.exe'" |
Select Name, #{
Name = 'UserName'
Expression = {"$($PSItem.GetOwner().Domain)\$($PSItem.GetOwner().User)"}
} |
Sort-Object UserName, Name
(Get-Process -Name 'explorer' -IncludeUserName).UserName
(
Get-WMIObject -ClassName Win32_ComputerSystem |
Select-Object -Property Username
).username
[adsisearcher]"(SamAccountName=$env:USERNAME)"
whoami
... then use that Name/SamAccountName to ask ADDS/AAD what the user FullName or whatever you wish is.
If you are on an earlier version, you need to install one of these modules from Microsofts' powershelgallery.com...
Find-Module -Name '*local*'
# Results
<#
Version Name Repository Description
------- ---- ---------- -----------
...
1.6 localaccount PSGallery A Simple module to allow the management of local users and groups on a computer
1.0.0.0 Microsoft.PowerShell.LocalAccounts PSGallery Provides cmdlets to work with local users and local groups
3.0 LocalUserManagement PSGallery a module that performs various local user management functions
...
0.1.1 LocalAccountManagement PSGallery Manage local and remote user accounts and profiles
...
#>
... and do the same thing or use WMI, ADSI, etc.
[adsisearcher]"(SamAccountName=$env:USERNAME)"
# Results
<#
CacheResults : True
ClientTimeout : -00:00:01
PropertyNamesOnly : False
Filter : (SamAccountName=TestUser)
PageSize : 0
PropertiesToLoad : {}
ReferralChasing : External
SearchScope : Subtree
ServerPageTimeLimit : -00:00:01
ServerTimeLimit : -00:00:01
SizeLimit : 0
SearchRoot :
Sort : System.DirectoryServices.SortOption
Asynchronous : False
Tombstone : False
AttributeScopeQuery :
DerefAlias : Never
SecurityMasks : None
ExtendedDN : None
DirectorySynchronization :
VirtualListView :
Site :
Container :
#>
Now, back to my 'read the help file comment.'
Get-ADUser | MS DOcs
https://learn.microsoft.com/en-us/powershell/module/activedirectory/get-aduser?view=windowsserver2019-ps
# Example 3: Get all of the properties for a specified user
Get-ADUser -Identity $env:USERNAME -Properties '*'
# Results
<#
Surname : David
Name : Chew David
UserPrincipalName :
GivenName : David
Enabled : False
SamAccountName : ChewDavid
ObjectClass : user
SID : S-1-5-21-2889043008-4136710315-2444824263-3544
ObjectGUID : e1418d64-096c-4cb0-b903-ebb66562d99d
DistinguishedName : CN=Chew David,OU=NorthAmerica,OU=Sales,OU=UserAccounts,DC=FABRIKAM,DC=COM
#>

Resolve IP address from CNAME record with Powershell

My servers have recently moved from a simple www.example.com A 10.10.10.10 type structure to using CNAME abstraction....
www.example.com CNAME www1.example.com
www1.example.com A 10.10.10.10
Previously I could do a DNS lookup to get the A record using:
$myHostIp = Resolve-DnsName "www.example.com" A -DnsOnly | Select-Object -first 1
$myHostIp = $myHostIp.IP4Address
(this doesn't work with the CNAME records).
How do I get the (first) IP address associated with a CNAME record?
I tried:
$myHostIp = Resolve-DnsName "www.example.com" A -DnsOnly | Select-Object -first 1 -Property IP4Address
But I just get null.
When you query a CNAME with Resolve-DnsName -Type A, you get two responses. The first is the CNAME response, and the second is the A.
You can see clearly what happens like so:
PS> Resolve-DnsName -Name 'www.google.com' -Type A -DnsOnly | Format-List -Property *
QueryType : CNAME
Server : forcesafesearch.google.com
NameHost : forcesafesearch.google.com
Name : www.google.com
Type : CNAME
CharacterSet : Unicode
Section : Answer
DataLength : 8
TTL : 228
Address : 216.239.38.120
IPAddress : 216.239.38.120
QueryType : A
IP4Address : 216.239.38.120
Name : forcesafesearch.google.com
Type : A
CharacterSet : Unicode
Section : Answer
DataLength : 4
TTL : 228
You're getting a null because the first object does not contain a property called "IP4Address", and the value of properties which do not exist is null.
Try:
$myHostIp = Resolve-DnsName -Name 'www.example.com' -Type A -DnsOnly |
Where-Object QueryType -eq 'A' |
Select-Object -First 1 -ExpandProperty IP4Address
I found a solution.
Resolve-DnsName was returning two records in place of the 1 it had done previously - the first was for the CNAME record with a null IP address property, but the second was correctly populated, so I changed Select-Object -first for Select-Object -last.
I'll leave the question open to see if someone else has a smarter solution.

How to get/set/update registry value through group policy cmdlet of Windows PowerShell?

I have configured the EventForwarding Manually but I was wondeing If I could do it programmatically and I came across the Group Policy Cmdlets which seems to be the solution. Here is what I am trying to configure manually in the image below.
When I run the Get-GPO -all cmdlet I don't see any GPOs related to Event Forwarding. However when I ran the Get-GPResultantSetOfPolicy with the specified path of an XML file, I got to see my configuration of the Subscription manager of the Event Forwarding.
Question 1: Why isn't the event forwarding policy shown in Get-GPO -all result?
Question 2: How to find out the GUID of the policy I need so I can use the Get-GPRegistryValue? besides providing the Key (which I was able to find and verfiy that it has my configuration that I have done through the gpedit.msc UI.
Question 3: How to figure out the display name of the policy in question? I tried the following:
PS C:\Windows\PolicyDefinitions> Get-GPRegistryValue -Name SubscriptionManager -Key HKEY_LOCAL_MACHINE\SOFTWARE\Policies
\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager
Where I tried for the Name attribute different things like : "EventForwarding", "EventForward", "SubscriptionManager" and even "Configure target Subscription Manager".
And here is what I got :
***Get-GPRegistryValue : The command cannot be completed because a GPO that is named "SubscriptionManager" was not found
in the nfstest.stbtest.microsoft.com domain. Make sure that the GPO that is specified by the Name parameter exists in
the domain that is specified for the cmdlet. Then, run the command again.
Parameter name: Name
At line:1 char:1
+ Get-GPRegistryValue -Name SubscriptionManager -Key HKEY_LOCAL_MACHINE\SOFTWARE\P ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Microsoft.Group...tryValueCommand:GetGPRegistryValueCommand) [Get-GPReg
istryValue], ArgumentException
+ FullyQualifiedErrorId : GpoWithNameNotFound,Microsoft.GroupPolicy.Commands.GetGPRegistryValueCommand***
Any Help regarding any of the three related questions would be appreciated.
EDIT 1:
As you can see in the image below, when I manually configure taregt subscription manager, I get the key HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager in the registry. My question for now is simple, how can I do that with cmdlets? All what I tried so far didn't create that key for me in the registry , NOT the AD.
Thanks
Sorry not sure to understand what you do. Here is a full example :
PS C:\silogix> Import-Module grouppolicy
PS C:\silogix> New-GPO -Name "MyGPO" | New-GPLink -target "OU=SousMonou,OU=MonOu,DC=dom,DC=fr" `
-linkenabled yes
GpoId : f31df409-ca35-47cd-b699-52426e2bd196
DisplayName : MyGPO
Enabled : True
Enforced : False
Target : OU=SousMonou,OU=MonOu,DC=dom,DC=fr
Order : 1
PS C:\silogix> get-gpo -all
DisplayName : Default Domain Policy
DomainName : dom.fr
Owner : DOM\Admins du domaine
Id : 31b2f340-016d-11d2-945f-00c04fb984f9
GpoStatus : AllSettingsEnabled
Description :
CreationTime : 16/09/2010 21:07:03
ModificationTime : 09/09/2011 21:04:06
UserVersion : AD Version: 0, SysVol Version: 0
ComputerVersion : AD Version: 11, SysVol Version: 11
WmiFilter :
DisplayName : Default Domain Controllers Policy
DomainName : dom.fr
Owner : DOM\Admins du domaine
Id : 6ac1786c-016f-11d2-945f-00c04fb984f9
GpoStatus : AllSettingsEnabled
Description :
CreationTime : 16/09/2010 21:07:03
ModificationTime : 06/06/2012 17:58:00
UserVersion : AD Version: 0, SysVol Version: 0
ComputerVersion : AD Version: 4, SysVol Version: 4
WmiFilter :
DisplayName : MyGPO
DomainName : dom.fr
Owner : DOM\Admins du domaine
Id : f31df409-ca35-47cd-b699-52426e2bd196
GpoStatus : AllSettingsEnabled
Description :
CreationTime : 08/06/2012 07:04:16
ModificationTime : 08/06/2012 07:04:16
UserVersion : AD Version: 0, SysVol Version: 0
ComputerVersion : AD Version: 0, SysVol Version: 0
PS C:\silogix> Set-GPRegistryValue -Name "MyGPO" -Key HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager -value "Server=https://EVTCPT:5986/wsman/SubscriptionManager/WEC" -t
ype String
PS C:\silogix> Get-GPRegistryValue -name "MyGPO" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager"
KeyPath : SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager
FullKeyPath : HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager
Hive : LocalMachine
PolicyState : Set
Value : Server=https://EVTCPT:5986/wsman/SubscriptionManager/WEC
Type : String
ValueName : 1
HasValue : True
So you can see it in GPMC.MSC.