aboutsummaryrefslogtreecommitdiff
path: root/Extras/Invoke-NBNSC2.ps1
blob: 41d2e6419beb41247ff60a6aa3f7b411952159b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
function Invoke-NBNSC2
{
<#
.SYNOPSIS
Invoke-NBNSC2 will listen for NBNS requests and execute set commands if requests for specific hostnames are
received. The function must be supplied with an even number of Hostnames and Commands. NBNS requests can be
sent from a NBNS enabled system on the same subnet using ping, etc.

.PARAMETER Hostnames
A comma separated list of Hostnames that will trigger a corresponding command. The first hostname trigger a command
from the Commands array with a matching index (e.g. Hostnames[0] executes Commands[0]).

.PARAMETER Commands
An array of commands stored in scriptblock format. All commands must be enclosed in {} brackets.

.PARAMETER ExitHostname
Specify a hostname that will cause the function to exit. This hostname must not match a hostname used in Hostnames.

.PARAMETER RunTime
(Integer) Set the run time duration.

.PARAMETER RunTimeUnit
Default = Minutes: Set the time unit for RunTime to either Minutes, Hours, or Days.

.EXAMPLE
Send-NBNSC2 -Hostnames test1,test2 -Command {calc},{notepad} -RunTime 1 -RunTimeUnit Days

.LINK
https://github.com/Kevin-Robertson/Inveigh
#>

[CmdletBinding()]
param
(
[parameter(Mandatory=$true)][Array]$Hostnames = "",
[parameter(Mandatory=$true)][Array]$Commands = "",
[parameter(Mandatory=$true)][String]$ExitHostname = "",
[parameter(Mandatory=$false)][Int]$RunTime="",
[parameter(Mandatory=$false)][ValidateSet("Minutes","Hours","Days")][String]$RunTimeUnit="Minutes",
[parameter(ValueFromRemainingArguments=$true)]$invalid_parameter
)

if ($invalid_parameter)
{
    throw "$($invalid_parameter) is not a valid parameter."
}

if($Hostnames.Count -ne $Commands.Count)
{
    throw "Must use an equal number of Hostnames and Commands."
}
elseif($Hostnames -contains $ExitHostname)
{
    throw "ExitHostname cannot be used as in Hostnames."
}

if($RunTime)
{   
    if($RunTimeUnit -like 'Minutes')
    {
        $runtime_timeout = new-timespan -Minutes $RunTime
    }
    elseif($RunTimeUnit -like 'Hours')
    {
        $runtime_timeout = new-timespan -Hours $RunTime
    }
    elseif($RunTimeUnit -like 'Days')
    {
        $runtime_timeout = new-timespan -Days $RunTime
    }

    $runtime_stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
}

$Hostnames = $Hostnames | % {$_.ToUpper()}
$running = $true
$NBNS_listener_endpoint = New-Object System.Net.IPEndPoint ([IPAddress]::Broadcast,137)
$NBNS_UDP_client = New-Object System.Net.Sockets.UdpClient 137
$NBNS_UDP_client.Client.ReceiveTimeout = 10000
$control_timeout = new-timespan -Seconds 1
$control_stopwatch = [System.Diagnostics.Stopwatch]::StartNew()

while($running)
{
    try
    {
        $NBNS_request_data = $NBNS_UDP_client.Receive([Ref]$NBNS_listener_endpoint)
    }
    catch
    {
        $NBNS_request_data = $null
    }

    if($NBNS_request_data)
    {
        $NBNS_query = [System.BitConverter]::ToString($NBNS_request_data[13..($NBNS_request_data.Length - 4)])
        $NBNS_query = $NBNS_query -replace "-00",""
        $NBNS_query = $NBNS_query.Split("-") | ForEach-Object{[Char][System.Convert]::ToInt16($_,16)}
        $NBNS_query_string_encoded = New-Object System.String ($NBNS_query,0,$NBNS_query.Length)
        $NBNS_query_string_encoded = $NBNS_query_string_encoded.Substring(0,$NBNS_query_string_encoded.IndexOf("CA"))
        $NBNS_query_string_subtracted = ""
        $NBNS_query_string = ""
        $n = 0
                            
        if($NBNS_query_string_encoded.Length -gt 1)
        {
            do
            {
                $NBNS_query_string_sub = (([Byte][Char]($NBNS_query_string_encoded.Substring($n,1))) - 65)
                $NBNS_query_string_subtracted += ([System.Convert]::ToString($NBNS_query_string_sub,16))
                $n += 1
            }
            until($n -gt ($NBNS_query_string_encoded.Length - 1))
                   
            $n = 0
                    
            do
            {
                $NBNS_query_string += ([Char]([System.Convert]::ToInt16($NBNS_query_string_subtracted.Substring($n,2),16)))
                $n += 2
            }
            until($n -gt ($NBNS_query_string_subtracted.Length - 1) -or $NBNS_query_string.Length -eq 15)
        }

        if([Array]::IndexOf($Hostnames,$NBNS_query_string) -ge 0 -and $control_stopwatch.Elapsed -ge $control_timeout)
        {
            $NBNS_UDP_client.Close()
            $command_index = [Array]::IndexOf($Hostnames,$NBNS_query_string)
            $NBNS_query_string = ''
            & $Commands[$command_index]
            $control_timeout = new-timespan -Seconds 5
            $control_stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
            $NBNS_UDP_client = New-Object System.Net.Sockets.UdpClient 137
            $NBNS_UDP_client.Client.ReceiveTimeout = 10000
        }
        elseif($ExitHostname -like $NBNS_query_string)
        {
            $running = $false
        }
    }

    if($RunTime -and $runtime_stopwatch.Elapsed -ge $runtime_timeout)
    {
        $running = $false
    }

}

$NBNS_UDP_client.Close()

}