How to Expand a property in a variable - powershell

if I go
$c = Resolve-DnsName facebook.com -Type TXT -Server '8.8.8.8'
When I enter $c I get
Name Type TTL Section Strings
---- ---- --- ------- -------
facebook.com TXT 7200 Answer {v=spf1 redirect=_spf.facebook.com}
facebook.com TXT 7200 Answer {google-site-verification=A2WZWCNQHrGV_TW
wKh6KHY90tY0SHZo_RnyMJoDaG0s}
facebook.com TXT 7200 Answer {google-site-verification=wdH5DTJTc9AYNwV
unSVFeK0hYDGUIEOGb-RReU6pJlY}
How do I expand $c.strings ?
I know I can get the expanded strings and lose the rest with
Resolve-DnsName facebook.com -Type TXT -Server '8.8.8.8' | Select-Object -ExpandProperty strings
How do I get the entire answer expanded ?

You can use a calculated property to redefine the Strings property from string[] to string:
Resolve-DnsName google.com -Type TXT -Server '8.8.8.8' |
Select-Object Name, Type, TTL, Section, #{ N = 'Strings'; E = { [string] $_.Strings }} |
Format-Table
This would result in:
Name Type TTL Section Strings
---- ---- --- ------- -------
google.com TXT 3600 Answer docusign=05958488-....
google.com TXT 3600 Answer google-site-verifi....
google.com TXT 3600 Answer docusign=1b0a6754-....
google.com TXT 3600 Answer google-site-verifi....
google.com TXT 3600 Answer globalsign-smime-d....
google.com TXT 3600 Answer MS=E4A68B9AB2BB967....
google.com TXT 3600 Answer apple-domain-verif....
google.com TXT 3600 Answer v=spf1 include:_sp....
google.com TXT 3600 Answer facebook-domain-ve....
If there where more than one string in the Strings property, using above code would join the strings with $OFS (Out Field Separator), by default a space:
Name Type TTL Section Strings
---- ---- --- ------- -------
google.com TXT 3339 Answer docusign=4752-4e... docusign=4752-4e...
If you want a multi-line string instead, you could use Out-String, however that would require first to .Trim() the output and also use -Wrap on Format-Table to be displayed correctly.
An example of how the code would look like using a hardcoded value (docusign=05958488):
Resolve-DnsName google.com -Type TXT -Server '8.8.8.8' |
Select-Object Name, Type, TTL, Section, #{
Name = 'Strings'
Expression = { ('docusign=05958488', 'docusign=05958488' | Out-String).Trim() }
} | Format-Table -Wrap
You could also use the -join operator to concatenate the strings with a CRLF (`r`n) to get a multi-line string:
Resolve-DnsName google.com -Type TXT -Server '8.8.8.8' |
Select-Object Name, Type, TTL, Section, #{
Name = 'Strings'
Expression = { 'docusign=05958488', 'docusign=05958488' -join "`r`n" }
} | Format-Table -Wrap
Both examples result in:
Name Type TTL Section Strings
---- ---- --- ------- -------
google.com TXT 3574 Answer docusign=05958488
docusign=05958488
google.com TXT 3574 Answer docusign=05958488
docusign=05958488
google.com TXT 3574 Answer docusign=05958488
docusign=05958488
If you want a solution that could handle both cases, Strings having only one value and Strings having multiple values, you could use something like this:
$result = Resolve-DnsName google.com -Type TXT -Server '8.8.8.8'
# Add random values to Strings for testing
$result.ForEach({ $_.Strings += Get-Random })
# Code logic
$result = foreach($element in $result) {
$out = [ordered]#{
Name = $element.Name
Type = $element.Type
TTL = $element.TTL
Section = $element.Section
}
foreach($e in $element.Strings) {
$out.Strings = $e
# output one object per string
[pscustomobject] $out
}
}
$result | Format-Table
Above logic would be creating a new object per element in the Strings property. The output would be:
TTL Section Name Type Strings
--- ------- ---- ---- -------
3444 Answer google.com TXT apple-domain-verificatio...
3444 Answer google.com TXT 1419241945
3444 Answer google.com TXT MS=E4A68B9AB2BB9670BCE15...
3444 Answer google.com TXT 463070462
3444 Answer google.com TXT facebook-domain-verifica...
3444 Answer google.com TXT 958788674
3444 Answer google.com TXT google-site-verification...
3444 Answer google.com TXT 1623605637

Related

Count occurrences of a list of ip in a text file

I need to count occurrences in file text of a list ip.
8.8.8.8
8.8.8.8
8.8.8.8
8.8.8.8
8.8.8.8
8.8.8.8
8.8.8.8
8.8.8.8
8.8.8.8
1.1.1.1
1.1.1.1
1.1.1.1
1.1.1.1
I've tried:
Get-Content "C:\listip.txt" | Select-String -Pattern '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$' | measure
But I received the total and not the sum of each occurrence. On linux I would have simply used uniq -c
As suggested by Santiago Squarzon, simply pipe into Group-Object:
Get-Content "c:\listip.txt" |
Select-String -Pattern '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$' |
Group-Object -NoElement |
Select-Object Count, #{ n='IP'; e='Name' }
Output:
Count IP
----- --
4 1.1.1.1
9 8.8.8.8
The parameter -NoElement removes the Group property that is output by default by Group-Object, but is not needed for counting only.
I've added Select-Object to rename the Name property to IP, using a calculated property .
If you'd like to correctly sort the unique IPs (i. e. not string sort, but number by number), you might look at this answer.
The alternative to Group-Object can be using a hash table:
Get-Content C:\listip.txt | & {
begin { $out = #{} }
process { $out[$_.Trim()] += 1 }
end { $out }
}
Output from the anonymous function would be:
Name Value
---- -----
1.1.1.1 4
8.8.8.8 9
If you want to filter or target only the lines that match your pattern, you can add an if condition and use the Matching Operator -match:
Get-Content C:\listip.txt | & {
begin { $out = #{} }
process {
# if the line matches this pattern there is for sure no need to `.Trim()`
if($_ -match '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$') {
$out[$_] += 1
}
}
end { $out }
}

How to get one row of info from .Csv file with Powershell?

The powershell script:
$test = import-csv “C:\CSVFiles\test.csv”
ForEach ($item in $test)
{
$Name = $item.(“Name”)
$property = $item.("property")
$location = $item.(“location”)
Write-Output "$Name=$Name"
Write-Output "Property=$property"
Write-Output "Location=$location"
}
This script shows all the data for name,property and location for each row. I want the results to only show the data of one row;for example the row: n1;13;computer
The Cvs file =
Name;property;location
n1;13;computer
n2;65;computer
n3;12;tablet
n4;234;phone
n5;123;phone
n6;125;phone
What the current script spits out:
Name=n1
Property=13
Location=computer
Name=n2
Property=65
Location=computer
Name= n3
Property=12
Location=tablet
Name=n4
Property=234
Location=phone
Name=n5
Property=123
Location=phone
Name=n6
Property=125
Location=phone
There are many ways to select a Row of a csv and to present the data
For demonstration I use an inline csv with a here string.
$Test = #"
Name;property;location
n1;13;computer
n2;65;computer
n3;12;tablet
n4;234;phone
n5;123;phone
n6;125;phone
"# | ConvertFrom-Csv -delimiter ';'
> $test[0]
Name property location
---- -------- --------
n1 13 computer
> $test | where-object Name -eq 'n1'
Name property location
---- -------- --------
n1 13 computer
> $test | where-object Name -eq 'n1' | Select-Object Name,property
Name property
---- --------
n1 13
> $test | where-object Name -eq 'n1' | ForEach-Object {"Name:{0} has property: {1}" -f $_.Name,$_.property}
Name:n1 has property: 13
Once imported the csv rows contents are converted to objects
If you want to get the original row of the csv matching a criteria don't import but:
> Get-Content "C:\CSVFiles\test.csv" | Select-String '^n1'
n1;13;computer
^n1 is a regular expression anchoring the pattern at line begin.
Select-String -Path "C:\CSVFiles\test.csv" -Pattern '^n1'
Is the same without a pipe
So your current output is having 3 objects that are having 3 headers majorly.
One is Name; Second one is Property and the third one is Location.
As part of solution, you can either pull the records by specifying the index value or you can use the .Headername to pull all the sets of same object. Like:
Avoiding Foreach and accessing with $test[0] or $test[1]
Or you can use like: $test.Name directly to have all of the names from the csv

How to Get The Real RecordData from DnsServerResourceRecord Using Powershell?

I'm using PowerShell to extract information from an Active Directory DNS server and I'm having trouble getting to the data I want.
Specifically, I'm trying to get the names of hosts that belong to a particular subnet, 10.104.128.x.
When I use the following commands:
Get-DnsServerResourceRecord -ComputerName AD_DNS_SERVER -ZoneName 104.10.in-addr.arpa -RRType Ptr | Where-Object {$_.HostName -like '*.128'}`
I get output that looks like this:
HostName RecordType Timestamp TimeToLive RecordData
-------- ---------- --------- ---------- ----------
104.128 PTR 10/19/2015 3:00:0... 00:15:00 adl5c260a86ba79.XYZ.net.
11.128 PTR 12/29/2015 6:00:0... 00:15:00 adl3c970e8d7166.XYZ.net.
110.128 PTR 1/29/2012 11:00:0... 00:15:00 nroxitow7tst.ABC.com.
114.128 PTR 1/20/2012 7:00:00 AM 00:15:00 adl5c260a86c29e.ABC.com
What I really want are the first column, (HostName), which has the last two octets of the IP; and the fifth column, (RecordData), which has the name of the host the IP is assigned to.
The hostname is the data I really want/need. And I see it right there!
So I used the select command to pare down the output in the pipe train. New command looks like this:
Get-DnsServerResourceRecord -ComputerName AD_DNS_SERVER -ZoneName 104.10.in-addr.arpa -RRType Ptr | Where-Object {$_.HostName -like '*.128'} | select HostName, RecordData
But the output looks like this:
HostName RecordData
-------- ----------
104.128 DnsServerResourceRecordPtr
11.128 DnsServerResourceRecordPtr
110.128 DnsServerResourceRecordPtr
114.128 DnsServerResourceRecordPtr
Dosen't get me the hostname though. Just the type of object the RecordData is but not the data that the object contains, perhaps?
I also tried piping the output to CSV and got the same result.
Then I tried looking at the DnsServerResourceRecord object properties with Get-Member. That showed me the object had a property called PSComputerName. I thought maybe that would have the name of the host but that came up blank when I tried to select it.
I then Googled around a bit and found a few pages that recommended a few ways to use RecordData.ipv4address to coax the data out of the DnsServerResourceRecordPtr object but I haven't gotten any of them to work yet. Output still prints blanks.
So my question is: does a reliable method exist for getting the actual hostname from a PTR record?
To select the PtrDomainName property from the DnsServerResourceRecordPtr object, use a calculated property:
... |Select-Object HostName, #{Name='RecordData';Expression={$_.RecordData.PtrDomainName}}
Yes it's really weird that you can't just call ToString on the DNS record data, it's all formatted using the PowerShell formatters which you can only access with Format-List or Format-Table, rather than just calling $resourceRecord.RecordData.ToString().
I've added more data types than Krzysztof Madej by just hacking out the PowerShell formatters from the XML file, the details are here.
http://david-homer.blogspot.com/2020/10/getting-text-representation-of.html
$dnsserver = "yourowndnsserver"
$dnszones = Get-DnsServerZone -ComputerName $dnsserver | Select-Object ZoneName
ForEach ($zone in $dnszones) {
$data = New-Object System.Object
$ZoneName = $zone.ZoneName
$data = Get-DnsServerResourceRecord $ZoneName -ComputerName $dnsserver
foreach ($registros in $data) {
$data = $ZoneName
$data += ","
$data += $registros.hostname;
$data += ","
$data += $RecordType = $registros.recordType;
$data += ","
if ($RecordType -like "PTR") {
$data += $registros.RecordData.PtrDomainName
}
elseif ($RecordType -like "A") {
$data += $([system.version]($registros.RecordData.ipv4address.IPAddressToString));
}
elseif ($RecordType -like "CNAME") {
$data += $registros.RecordData.HostNameAlias;
}
elseif ($RecordType -like "NS") {
$data += $registros.RecordData.nameserver;
}
elseif ($RecordType -like "MX") {
$data += $registros.RecordData.MailExchange;
}
elseif ($RecordType -like "SOA") {
$data += $registros.RecordData.PrimaryServer;
}
elseif ($RecordType -like "SRV") {
$data += $registros.RecordData.DomainName;
}
$data | out-file -FilePath $env:TEMP\$(Get-Date -Format dd_MM_yyyy)_DNSRecords.csv -Append
}
}

Powershell to reformat the file content

I have a script which gets content from one file and checks for its ip. Then that is added to some other text file.
[System.Collections.ArrayList]$hlist1 = Get-Content -Path "C:\Timezone\Update\host.txt"
$hiplist = New-Object System.Collections.ArrayList
$hlist2 = New-Object System.Collections.ArrayList
ForEach ($h in $hlist1)
{
$hip = Resolve-DnsName $h
$hiplist.Add($hip)
}
$hiplist | Out-File "C:\Timezone\Update\hiplist.txt"
The file which is getting created is as shown below:
---- ---- --- ------- --------
WIN-JB2A2FS84MQ.domain.com A 1200 Answer 10.3.0.4
8
WIN-QP0BH4SD2H9.domain.com A 1200 Answer 10.3.1.1
9
I need to:
get rid of the first -------- lines.
get the entire ip in the same line (10.3.0.10)
Have tried Format-Table -Autosize, then Select -Skip 1 etc, but no luck.
How can this be achieved.? Please note that the code works fine as expected when it is ran manually, but throws this issue when executed using task scheduler.
Edit Based on Matt's answer
Now the text file contains:
"Address","IPAddress","QueryType","IP4Address","Name","Type","CharacterSet","Section","DataLength","TTL"
"10.3.0.48","10.3.0.48","A","10.3.0.48","WIN-JB2A2FS84MQ.domain.com","A","Unicode","Answer","4","1200"
"10.3.1.19","10.3.1.19","A","10.3.1.19","WIN-QP0BH4SD2H9.domain.com","A","Unicode","Answer","4","1200"
Peter-sal's reply output:
Name Type TTL Section IPAddress
---- ---- --- ------- ---------
WIN-JB2A2FS84MQ.domain.com A 1200 Answer 10.3.0.48
WIN-QP0BH4SD2H9.domain.com A 1200 Answer 10.3.1.19
But again on top of Name there's one space. I need to delete everything present before WIN-JB2.....
I cannot test perfectly but I would like to come back to an earlier comment of mine. Resolve-DNSName returns objects so their output is better destined for something object aware. Export-CSV should be preferable here.
$hlist1 = Get-Content -Path "C:\Timezone\Update\host.txt"
$hlist1 | ForEach-Object{Resolve-DnsName $_} |
Export-Csv "C:\Timezone\Update\hiplist.txt" -NoTypeInformation
I normally don't like this but if you prefer you should be able to use the Format-table output now. This seems to be more inline with what you are looking for.
$hlist1 = Get-Content -Path "C:\Timezone\Update\host.txt"
$hlist1 | ForEach-Object{Resolve-DnsName $_} |
Format-Table -HideTableHeaders | Select-Object -Skip 1 |
Out-File "C:\Timezone\Update\hiplist.txt" -Width 200
Perhaps you prefer that output. The header should be removed now as well as a blank line in the beginning.
That creates some white-space before and after the output. Simple solution is to wrap that up in a Trim()
$hlist1 = Get-Content -Path "C:\Timezone\Update\host.txt"
$results = ($hlist1 | ForEach-Object{Resolve-DnsName $_} |
Format-Table -HideTableHeaders |
Out-string).Trim()`
$results | Out-File "C:\Timezone\Update\hiplist.txt" -Width 200`

Resolving IP Address from hostname with PowerShell

I am trying to get the ipaddress from a hostname using Powershell, but I really can't figure out how.
Any help?
You can get all the IP addresses with GetHostAddresses like this:
$ips = [System.Net.Dns]::GetHostAddresses("yourhosthere")
You can iterate over them like so:
[System.Net.Dns]::GetHostAddresses("yourhosthere") | foreach {echo $_.IPAddressToString }
A server may have more than one IP, so this will return an array of IPs.
this is nice and simple and gets all the nodes.
$ip = Resolve-DNSName google.com
$ip
also try inputting an ip instead of a domain name and check out those results too!
Use Resolve-DnsName cmdlet.
Resolve-DnsName computername | FT Name, IPAddress -HideTableHeaders | Out-File -Append c:\filename.txt
PS C:\> Resolve-DnsName stackoverflow.com
Name Type TTL Section IPAddress
---- ---- --- ------- ---------
stackoverflow.com A 130 Answer 151.101.65.69
stackoverflow.com A 130 Answer 151.101.129.69
stackoverflow.com A 130 Answer 151.101.193.69
stackoverflow.com A 130 Answer 151.101.1.69
PS C:\> Resolve-DnsName stackoverflow.com | Format-Table Name, IPAddress -HideTableHeaders
stackoverflow.com 151.101.65.69
stackoverflow.com 151.101.1.69
stackoverflow.com 151.101.193.69
stackoverflow.com 151.101.129.69
PS C:\> Resolve-DnsName -Type A google.com
Name Type TTL Section IPAddress
---- ---- --- ------- ---------
google.com A 16 Answer 216.58.193.78
PS C:\> Resolve-DnsName -Type AAAA google.com
Name Type TTL Section IPAddress
---- ---- --- ------- ---------
google.com AAAA 223 Answer 2607:f8b0:400e:c04::64
You could use vcsjones's solution, but this might cause problems with further ping/tracert commands, since the result is an array of addresses and you need only one.
To select the proper address, Send an ICMP echo request and read the Address property of the echo reply:
$ping = New-Object System.Net.NetworkInformation.Ping
$ip = $($ping.Send("yourhosthere").Address).IPAddressToString
Though the remarks from the documentation say:
The Address returned by any of the Send overloads can originate from a malicious remote computer. Do not connect to the remote computer using this address. Use DNS to determine the IP address of the machine to which you want to connect.
Working one liner if you want a single result from the collection:
$ipAddy = [System.Net.Dns]::GetHostAddresses("yahoo.com")[0].IPAddressToString;
hth
If you know part of the subnet (i.e. 10.3 in this example), then this will grab any addresses that are in the given subnet:
PS C:\> [System.Net.Dns]::GetHostAddresses("MyPC") | foreach { $_.IPAddressToString | findstr "10.3."}
This worked well for my purpose
$ping = ping -4 $env:COMPUTERNAME
$ip = $ping.Item(2)
$ip = $ip.Substring(11,11)
$computername = $env:computername
[System.Net.Dns]::GetHostAddresses($computername) | where {$_.AddressFamily -notlike "InterNetworkV6"} | foreach {echo $_.IPAddressToString }
The Test-Connection command seems to be a useful alternative, and it can either provide either a Win32_PingStatus object, or a boolean value.
Documentation:
https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.management/test-connection
You can use this code if you have a bunch of hosts in text file
$a = get-content "C:\Users\host.txt"(file path)
foreach ($i in $a )
{
$i + "`n" + "==========================";[System.Net.Dns]::GetHostAddresses($i)
}
The simplest way:
ping hostname
e.g.
ping dynlab938.meng.auth.gr
it will print:
Pinging dynlab938.meng.auth.gr [155.207.29.38] with 32 bytes of data
try
$address = 'HOST NAME'
Resolve-DnsName $address | Select-Object Name, IPAddress | Export-csv "C:\Temp\CompleteNSLookup.csv" -append -NoType