djl236 icon

IPScanner.ps1

djl236 | PRO | 01/12/25 10:10:46 PM UTC | 0 ⭐ | 7672 👁️ | Never ⏰ | [powershell, IP Scanner]
PowerShell |

12.17 KB

|

Source Code

|

0 👍

/

0 👎

<#
****************************************************************************************
*              Powershell Script GUI Network Scanner                                   *
*              Scans user input subnet and returns all active devices' IP Address      *
*              hostname, MAC Address, and OS version if applicable.                    *
*              User can select field and right mouse click to copy data.               *
*               Version 2: WPF GUI                                                     *
*                        Coded by: djl236                                              *
*                        2025 January 11                                               *
*                        Version 2.0                                                   *
****************************************************************************************
#>
 
#Load WPF Assembly
Add-Type -AssemblyName PresentationFramework
 
#Define the WPF XAML Layout
$Xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Title="Network Scanner Tool" 
        Height="520" Width="750" WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>   <!-- Header -->
            <RowDefinition Height="Auto"/>   <!-- Subnet Input -->
            <RowDefinition Height="*"/>     <!-- Results -->
            <RowDefinition Height="Auto"/>   <!-- Status -->
            <RowDefinition Height="Auto"/>   <!-- Footer -->
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/> <!-- Label -->
            <ColumnDefinition Width="Auto"/> <!-- Input -->
            <ColumnDefinition Width="Auto"/> <!-- Scan -->
            <ColumnDefinition Width="Auto"/> <!-- Clear -->
            <ColumnDefinition Width="Auto"/> <!-- Close -->
            <ColumnDefinition Width="*"/>   <!-- Remaining space -->
        </Grid.ColumnDefinitions>
 
        <!-- Header -->
        <Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="6" HorizontalAlignment="Center" 
               VerticalAlignment="Center" FontSize="14" FontWeight="Bold">
            <TextBlock TextAlignment="Center">
                Network Scanner Tool
                <LineBreak/>
                Right mouse click selected data to copy.
            </TextBlock>
        </Label>
 
        <!-- Subnet Input -->
        <Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Margin="0,5,5,5">Subnet:</Label>
        <TextBox x:Name="SubnetTextBox" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center"
                 Margin="0,5,5,5" Text="Enter Subnet (192.168.1)" Width="200"/>
        <Button x:Name="ScanButton" Grid.Row="1" Grid.Column="2" Margin="5" Width="75">Scan</Button>
        <Button x:Name="ClearButton" Grid.Row="1" Grid.Column="3" Margin="5" Width="75">Clear</Button>
        <Button x:Name="CloseButton" Grid.Row="1" Grid.Column="4" Margin="2,5,5,5" Width="75">Close</Button>
 
        <!-- Results ListView -->
        <ListView x:Name="ResultsListView" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="6" 
                  Margin="5" BorderThickness="1" SelectionMode="Single">
            <ListView.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Copy IP Address" />
                    <MenuItem Header="Copy Host Name" />
                    <MenuItem Header="Copy MAC Address" />
                    <MenuItem Header="Copy OS Version" />
                    <MenuItem Header="Copy Entire Row" />
                </ContextMenu>
            </ListView.ContextMenu>
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="IP Address" Width="120" DisplayMemberBinding="{Binding IPAddress}"/>
                    <GridViewColumn Header="Host Name" Width="200" DisplayMemberBinding="{Binding HostName}"/>
                    <GridViewColumn Header="MAC Address" Width="150" DisplayMemberBinding="{Binding MACAddress}"/>
                    <GridViewColumn Header="OS Version" Width="200" DisplayMemberBinding="{Binding OSVersion}"/>
                </GridView>
            </ListView.View>
        </ListView>
 
        <!-- Status Label -->
        <Label x:Name="StatusTextLabel" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="6" Margin="5">
            Status: Ready
        </Label>
 
        <!-- Footer -->
        <Label Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="6" HorizontalAlignment="Center" 
               VerticalAlignment="Center" FontSize="12" FontWeight="Bold">
            Developer POC - djl236
        </Label>
    </Grid>
</Window>
"@
 
#Load the XAML
[xml]$XamlObject = $Xaml
$Reader = (New-Object System.Xml.XmlNodeReader $XamlObject)
$Window = [Windows.Markup.XamlReader]::Load($Reader)
 
#Get UI Elements
$SubnetTextBox = $Window.FindName("SubnetTextBox")
$ScanButton = $Window.FindName("ScanButton")
$ClearButton = $Window.FindName("ClearButton")
$CloseButton = $Window.FindName("CloseButton")
$ResultsListView = $Window.FindName("ResultsListView")
$StatusTextLabel = $Window.FindName("StatusTextLabel")
 
#Functions
Function Copy-SelectedField
    {
        Param ([string]$Field)
        If ($ResultsListView.SelectedItem)
            {
                $SelectedItem = $ResultsListView.SelectedItem
                Switch ($Field)
                    {
                        "IP" { [System.Windows.Clipboard]::SetText($SelectedItem.IPAddress); Write-Host "IP Address copied." }
                        "HostName" { [System.Windows.Clipboard]::SetText($SelectedItem.HostName); Write-Host "Host Name copied." }
                        "MAC" { [System.Windows.Clipboard]::SetText($SelectedItem.MACAddress); Write-Host "MAC Address copied." }
                        "OS" { [System.Windows.Clipboard]::SetText($SelectedItem.OSVersion); Write-Host "OS Version copied." }
                        "Row" {
                            $RowData = "$($SelectedItem.IPAddress), $($SelectedItem.HostName), $($SelectedItem.MACAddress), $($SelectedItem.OSVersion)"
                            [System.Windows.Clipboard]::SetText($RowData)
                            Write-Host "Entire row copied."
                        }
                    }
            }
        Else
            {
                Write-Host "No item selected to copy." -ForegroundColor Yellow
            }
    }
 
#Attach Context Menu Events
$ResultsListView.ContextMenu.Items[0].Add_Click({ Copy-SelectedField -Field "IP" })
$ResultsListView.ContextMenu.Items[1].Add_Click({ Copy-SelectedField -Field "HostName" })
$ResultsListView.ContextMenu.Items[2].Add_Click({ Copy-SelectedField -Field "MAC" })
$ResultsListView.ContextMenu.Items[3].Add_Click({ Copy-SelectedField -Field "OS" })
$ResultsListView.ContextMenu.Items[4].Add_Click({ Copy-SelectedField -Field "Row" })
 
Function Get-MACAddress
    {
        Param ([string]$IPAddress)
        Try
            {
                $LocalIP = (Get-NetIPAddress | Where-Object { $_.IPAddress -eq $IPAddress }).IPAddress
                If ($LocalIP)
                    {
                        $Adapter = Get-NetIPAddress -IPAddress $IPAddress | Get-NetAdapter
                        If ($Adapter)
                            {
                                Return $Adapter.MacAddress
                            }
                        Else
                            {
                                Return "MAC Not Found (Local)"
                            }
                    }
 
                $ARPTable = arp -a
                $Regex = [regex]"(?<IP>\d+\.\d+\.\d+\.\d+)\s+(?<MAC>([0-9a-f]{2}-?){6})"
                $Match = $Regex.Matches($ARPTable) | Where-Object { $_.Groups["IP"].Value -eq $IPAddress }
                If ($Match)
                    {
                        Return $Match.Groups["MAC"].Value
                    }
                Else
                    {
                        Return "Not Found"
                    }
            }
        Catch
            {
                Return "Error"
            }
    }
 
Function Get-OSVersion
    {
        Param ([string]$IPAddress)
        Try
            {
                $OS = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $IPAddress -ErrorAction Stop
                Return $OS.Caption
            }
        Catch
            {
                Return "Unknown or Not a Windows OS"
            }
    }
 
Function Update-Status
    {
        #Forces the WPF GUI to refresh immediately
        $Frame = New-Object -TypeName System.Windows.Threading.DispatcherFrame
        [System.Windows.Threading.Dispatcher]::CurrentDispatcher.Invoke(
            [System.Action]{ $Frame.Continue = $false },
            [System.Windows.Threading.DispatcherPriority]::Background
        )
        [System.Windows.Threading.Dispatcher]::PushFrame($Frame)
    }
 
    Function Search-Network
    {
        Param ([string]$Subnet)
 
        If (-not $Subnet)
            {
                $StatusTextLabel.Content = "Error: Please enter a subnet."
                Return
            }
 
        $StatusTextLabel.Content = "Scanning..."
        
        #Force GUI refresh
        Update-Status
 
        $ResultsListView.Items.Clear()
 
        Try
            {
                $IPRange = 1..254 | ForEach-Object { "$Subnet.$_" }
                $Addresses = $IPRange -join "' or Address='"
                $Filter = "(Address='$Addresses') AND StatusCode=0"
                $Results = Get-WmiObject -Class Win32_PingStatus -Filter $Filter
 
                #Manual IP Sorting
                $SortedResults = $Results | Sort-Object {
                    $Octets = $_.Address -split '\.' | ForEach-Object { [int]$_ }
                    ($Octets[0] * 256 * 256 * 256) + ($Octets[1] * 256 * 256) + ($Octets[2] * 256) + $Octets[3]
                }
 
                #Add Sorted Results to the ListView
                ForEach ($Result in $SortedResults)
                    {
                        $IPAddress = $Result.Address
                        $HostName = Try { ([System.Net.Dns]::GetHostEntry($IPAddress)).HostName } Catch { "Unable to Resolve" }
                        $MACAddress = Get-MACAddress -IPAddress $IPAddress
                        $OSVersion = Get-OSVersion -IPAddress $IPAddress
 
                        If (-not $MACAddress) { $MACAddress = "Unable to Resolve" }
 
                        $Item = [PSCustomObject]@{
                            IPAddress  = $IPAddress
                            HostName   = $HostName
                            MACAddress = $MACAddress
                            OSVersion  = $OSVersion
                        }
                        $ResultsListView.Items.Add($Item)
                    }
 
                $StatusTextLabel.Content = "Scan Complete."
            }
        Catch
            {
                $StatusTextLabel.Content = "Error occurred: $_"
                Write-Host "Error occurred: $_" -ForegroundColor Red
            }
    }
 
 
Function Clear-Results
    {
        $ResultsListView.Items.Clear()
        $StatusTextLabel.Content = "Status: Ready"
        Write-Host "Results cleared."
    }
 
#Event Handlers
$ScanButton.Add_Click({ 
    #Validate Subnet Format
    $Subnet = $SubnetTextBox.Text
    $SubnetRegex = '^\d{1,3}\.\d{1,3}\.\d{1,3}$'
 
    If (-not [string]::IsNullOrWhiteSpace($Subnet))
        {
            If ($Subnet -match $SubnetRegex)
                {
                    Search-Network -Subnet $Subnet
                }
            Else
                {
                    $StatusTextLabel.Content = "Error: Invalid Subnet Format (e.g. 192.168.1)"
                    Write-Host "Error: Invalid Subnet Format (e.g. 192.168.1)"
                }
        }
    Else
        {
            $StatusTextLabel.Content = "Error: Please enter a subnet."
            Write-Host "Error: Please enter a subnet."
        }
})
$ClearButton.Add_Click({ Clear-Results })
$CloseButton.Add_Click({ $Window.Close() })
 
#Show the Window
$Window.ShowDialog()
 

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎