1

I just want to get the hostname of IP 192.168.1.10, using [System.Net.Dns]::BeginGetHostEntry(), like the code example of Microsoft on C#, but on Powershell.

I've done this in the file getlan.ps1:

#
$GetHostEntryFinished = [System.Threading.ManualResetEvent]::new($false);
    
class ResolveState
{
  hidden $hostname;
  hidden $resolvedIPs;
    
  ResolveState($host1)
  {
    $this.hostname = $host1;

    #
    # add getter and setter for the member IPs:
    #
    $this | Add-Member -Name IPs -MemberType ScriptProperty -Value {
    # This is the getter
      return $this.resolvedIPs
    } -SecondValue {
      param($value)
      # This is the setter
      $this.resolvedIPs = $value
    }

    #
    # add getter and setter for the member host:
    #
    $this | Add-Member -Name host -MemberType ScriptProperty -Value {
    # This is the getter
      return $this.hostname
    } -SecondValue {
      param($value)
      # This is the setter
      $this.hostname = $value
    }
  }
}

#
# Record the IPs in the state object for later use.
#
function GetHostEntryCallback($ar)
{
  $ioContext = $ar.AsyncState;
  $ioContext.IPs = [System.Net.Dns]::EndGetHostEntry($ar);
  $GetHostEntryFinished.Set();
}

#
# Determine the Internet Protocol (IP) addresses for
# this host asynchronously.
#
function DoGetHostEntryAsync($hostname)
{
  #
  $ioContext = [ResolveState]::new($hostname)
  #

  #
  $GetHostEntryFinished.Reset();
  #
  [System.Net.Dns]::BeginGetHostEntry($ioContext.host, `
    [AsyncCallback]$function:GetHostEntryCallback, $ioContext);

  #
  # Wait here until the resolve completes (the callback
  # calls .Set())
  #
  $GetHostEntryFinished.WaitOne();
  #

  Write-Output("EndGetHostEntry($($ioContext.host)) returns:");

  foreach ($address in $ioContext.IPs.AddressList)
  {
    Write-Output($address);
  }
}

#
# main():
#
DoGetHostEntryAsync "192.168.1.10"

But I've gotten this error: enter image description here

Powershell console was even killed.

What's wrong in the code? It seems I've some memory access error. I need your help.

I cite a part of text message to be clearer:

An error has occurred that was not properly handled. Additional information is shown below. The PowerShell process will exit. Unhandled exception. System.Management.Automation.PSInvalidOperationException: There is no Runspace available to run scripts in this thread. You can provide one in the DefaultRunspace property of the System.Management.Automation.Runspaces.Runspace type. The script block you attempted to invoke was: param($ar)

jacouh
  • 8,473
  • 5
  • 32
  • 43
  • 1
    While PowerShell script blocks (`{ ... }`) and even custom-class methods generally _can_ be used as .NET delegates, their _invocation_ only succeeds if the calling thread has a PowerShell runspace associated with it. This condition is met when the foreground thread is the caller, such as when WinForms event delegates are called, but not generally in callback scenarios. [This answer](https://stackoverflow.com/a/53789011/45375) shows a complex workaround based on ad-hoc compilation of C# code with `Add-Type`. – mklement0 Mar 24 '23 at 20:17
  • 1
    Consider using the TPL (`Task`-returning) methods instead, with this approach: https://blog.ironmansoftware.com/powershell-async-method/ – Dai Mar 24 '23 at 20:20
  • 1
    You would be definitely fighting the language trying to do this. Even tho PowerShell can do multithreading, the solution is often cumbersome as mklement0 points out. you could use `GetHostEntryAsync(...)` instead of `BeginGetHostEntry(...)` then await the task / tasks. That would simplify it. – Santiago Squarzon Mar 24 '23 at 21:10
  • Thank you very much for your comments. I've tried @mklement0 method, without success. – jacouh Mar 26 '23 at 20:52
  • @jacouh - you say you want to do this "on powershell", but really you're just calling DotNet. Is the goal to specifically use System.net.dns, or is the goal to do a reverse lookup (get the hostname) from powershell? – Orangutech Mar 31 '23 at 23:25
  • @Orangutech, thank for your comment. My real goal is to list all hosts in my LAN using Powershell. As `net view` does no more work since Windows 10 for some security reason. Then copy to them my last db Accessing tool if they are computer. – jacouh Apr 01 '23 at 14:07
  • @jaco Sorry for the delay – Orangutech Apr 13 '23 at 23:09
  • @jacouh (Ah, editing time limit!) It really feels like you're trying to force a bunch of .NET from powershell, the hard way. If you want to get all the computers in an AD domain, use `Get-ADComputer`. (The syntax on that can be confusing, use `get-help Get-ADComputer` or add `-online` to get to the online reference. ) If you want to resolve those hostnames to IP addresses (or the reverse) from AD DNS, use `get-dnsserverresourcerecord` . If you want to get IP addresses via ping, use `test-netconnection`. Stay away from manually threaded stuff. Learn to use the PS pipeline. – Orangutech Apr 13 '23 at 23:34

1 Answers1

0

This won't help you if you're dead-set on calling the [System.net.dns] directly (See my comments above), but a much simpler/powershell-native way would be something like:

$AllTheComps = Get-ADComputer -Filter *

$AllTheComps.Count
7178
#(Just to sanity check)

$AllTheComps | foreach { get-dnsServerResourceRecord -ComputerName 'dchostname'  -ZoneName 'my.zone.name'  -Name $_.Name}

$AllTheComps | foreach { Test-NetConnection -ComputerName $_.name | select Computername,RemoteAddress }

This will give you output like

HostName           RecordType Type       Timestamp            TimeToLive      RecordData
--------           ---------- ----       ---------            ----------      ----------
Webapp01           A          1          4/13/2023 2:00:00 AM 00:20:00        10.108.68.59
Webapp02           A          1          4/13/2023 2:00:00 AM 00:20:00        10.108.68.58
Webapp03           A          1          4/13/2023 2:00:00 AM 00:20:00        10.108.68.60

and

ComputerName    RemoteAddress
------------    -------------
WEBAPP01        10.108.68.59
WEBAPP02        10.108.68.58
WEBAPP03        10.108.68.60

The above is somewhat quick'n'dirty, normally you want to assign all your query results to vars, then filter those for your output at the end. Especially when you're learning those particular objects and what properties you want displayed.

Orangutech
  • 769
  • 1
  • 10
  • 17