wake up on lan script gives error ObjectOpen(MSwinsock, winsock)

Started by jwt, November 27, 2024, 09:38:24 AM

Previous topic - Next topic

jwt

I'am trying to get the wake up on lan script from the Tech. Forum running on my Windows-11 dekstop PC, but the line objSocket = ObjectOpen("MSWinsock.Winsock") gives the following error 1727 COM Invalid Class string.
Which class string do I have to use or is there another way to send/broadcast the byte message on my LAN network?

thanks for any helpful answer.
Regards jan Willem Teunisse

td

I don't believe MSFT supports the MSWINSCK.OCX COM component anymore although you might be able to find it via a careful Web search.

You do have multiple options, however. I have not tried it but you might consider the OstroSoft's Winsock Component. It supports COM Automation and should, therefore, be compatible with WinBatch COM Automation. The WIL WinSock Extender supports window sockets and is available on the WinBatch download webpage. The simplest solution may be to use the WIL Terminal Services Extender's wtsSendMessage to broadcast a message on a LAN.  The Terminal Extender is also available on the WinBatch download webpage.

I am sure I am missing a few other possibilities but the above provides a starting point.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

jwt

Thanks for your answer, TD. I thought about the WIL Winsock extender, but from the help CHM file I did not see a broadcast function. I will try the WIL Terminal Services extender this afternoon.

td

Using the WIL Winsock extender would require sending a data packet to the local subnet's broadcast address. I can understand the hesitancy to use it because it does require some knowledge of TCP/IP networks.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Possibly this PS function, nicely commented, could be adapted to WB's CLR, most is just .NET except creating the ByteArray
#Define MAC target address,
# can contain the separators ":" or "-" or the hexadecimal string alone
$MAC = "1A:2B:3C:4D:5E:6F"
#convert MAC to byte array
$ByteArray = $MAC -replace "[:\-]" -split "(..)" -ne '' | ForEach-Object { [Byte] "0x$_"}
#Build Magic Packet according to WOL specs
[Byte[]] $MagicPacket = (,0xFF * 6) + ($ByteArray * 16)
#Use .NET method to build UdpClient object
$Client = New-Object System.Net.Sockets.UdpClient
#Set Magic Packet destination to broadcast address of our network on port 7
$Client.Connect(([System.Net.IPAddress]::Broadcast),7)
#Send Magic Packet
$Client.Send($MagicPacket,$MagicPacket.Length)
#Close UdpClient
$Client.Close()
Stan - formerly stanl [ex-Pundit]

td

My apologies to the OP. While OstroSoft's Winsock Component will likely work, the two extender solutions will not.

Here is an untested solution based on Stan's .Net suggestion:

;; Using Stan's .Net suggestion
ObjectClrOption('useany','System')
objClient = ObjectClrNew('System.Net.Sockets.UdpClient')

; Create a byte array from the MAC address of the target.
; There are serveral ways to fetch the Mac address of a
; computer on the LAN.
lMac = '74:86:31:7D:19' ; Example MAC address.
hMac = BinaryAlloc(1)
for i = 1 to 6
  BinaryPokeHex(hMac, 0,ItemExtract(i, lMac,':'))
  aBytes[i-1] = BinaryPeek(hMac,0) 
next
BinaryFree(hMac)
aBytes = ObjectType('array|i1', aBytes)

; Send the "magic packet".
objClient.Connect('255.255.255.255', 7) ; Broadcast address for most LANs.
objClient.Send(aBytes, 6)
objClient.Close()
exit

If it doesn't work, post back and I will see what can be done.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Don't know if this helps, but the PS code creates a MagicPacket as the 6 byte ...255... + 16 copies of the MAC byte array. This leads to a variable length for the second parameter of the broadcast. Easy to test in PS [I use the ISE]
$MAC = "1A:2B:3C:4D:5E:6F"
#Tony's test MAC
#$MAC = "74:86:31:7D:19"
$ByteArray = $MAC -replace "[:\-]" -split "(..)" -ne '' | ForEach-Object { [Byte] "0x$_"}
[Byte[]] $MagicPacket = (,0xFF * 6) + ($ByteArray * 16)
$len = "Length: $MagicPacket.Length"
$len

so using the test MAC in my post you get length of 102
ength: 255 255 255 255 255 255 26 43 60 77 94 111 26 43 60 77 94 111 26 43 60 77 94 111 26 43 60 77 94 111 26 43 60 77 94 111 26 43 60 77 94 111 26 43 60 77 94 111 26 43 60 77 94 111
26 43 60 77 94 111 26 43 60 77 94 111 26 43 60 77 94 111 26 43 60 77 94 111 26 43 60 77 94 111 26 43 60 77 94 111 26 43 60 77 94 111 26 43 60 77 94 111.Length

and with Tony's length is 86
Length: 255 255 255 255 255 255 116 134 49 125 25 116 134 49 125 25 116 134 49 125 25 116 134 49 125 25 116 134 49 125 25 116 134 49 125 25 116 134 49 125 25 116 134 49 125 25 116 134
49 125 25 116 134 49 125 25 116 134 49 125 25 116 134 49 125 25 116 134 49 125 25 116 134 49 125 25 116 134 49 125 25 116 134 49 125 25.Length

So, I would think the WB code would use the length as the second parameter in the Send() function.

NOTE: the PS code can be tested [just remove all comment lines] with the StdOut script I posted in WB


Stan - formerly stanl [ex-Pundit]

td

According to the following Wikipedia article:

https://en.wikipedia.org/wiki/Wake-on-LAN#Magic_packet

When using the UPD protocol, the magic packet should be 102 bytes. Interestingly, It can also be sent using the TCP protocol. That means that the WinSock extender can be used to send a Wake-on-LAN message.

Here is a correction to my lazily constructed previous script.
ObjectClrOption('useany','System')
objClient = ObjectClrNew('System.Net.Sockets.UdpClient')

; Create a byte array from the target's MAC address.
; There are several ways to fetch the Mac address of a
; computer on the LAN.
lMac = '74:86:E2:31:7D:19' ; Example MAC address.
lMagPack = 'FF:FF:FF:FF:FF:FF'
for i = 1 to 16
   lMagPack := ':':lMac
next
nCnt = ItemCount(lMagPack, ':')
hMac = BinaryAlloc(1)
for i = 1 to nCnt
  BinaryPokeHex(hMac, 0,ItemExtract(i, lMagPack,':'))
  aBytes[i-1] = BinaryPeek(hMac,0) 
next

BinaryFree(hMac)
aBytes = ObjectType('array|i1', aBytes)

; Send the "magic packet".
objClient.Connect('255.255.255.255', 7) ; Broadcast address for most LANs.
objClient.Send(aBytes, nCnt)
objClient.Close()
exit

I still haven't tested this by waking up a machine. For security reasons, I don't have any machines with WOL enabled. However, the contents of the Magic Packet sent are easily verifiable using WinBatch Studio in debug mode.

Out of an abundance of curiosity, I will try to configure a NIC to listen for WOL packets to see if it works.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Stan - formerly stanl [ex-Pundit]

td

Here is a simple example of fetching the broadcast address dynamically based on the target IP address.

; Get the broadcast address dynamically. Assumes System is already loaded...
lIp = '192.168.0.123'   ; IP address of target
aIp = Arrayize(lIp, '.')
aIp = ObjectType('array|ui1', aIp)
objAddr = ObjectClrNew('System.Net.IPAddress', aIp)
Baddr = objAddr.Broadcast

;str = Baddr.ToString() ; Gets broadcast address as string.

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Just one nitpick. I saw from the wikipedia you posted that packet length should be 102. I tested for the nCnt for both the original MAC I posted 1A:2B:3C:4D:5E:6F and your example 74:86:31:7D:19 and with your byte parsing both come out 102 as length, but the PS code still shows 102 and 86. Possibly a bug in PS byte handling...

[EDIT] I tried multiple mac addresses and all came out either 102 or 86 with PS [and 102-86 = 16]... probably a bug
Stan - formerly stanl [ex-Pundit]

td

74:86:31:7D:19 was a cut & paste error. I dropped the last hex number from my network MAC address reporting tool. If you look at the updated script I posted, you will see that the MAC address has 6 hex bytes instead of 5. As I previously mentioned the second script is a correction to my lazily (and carelessly) constructed previous script.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Yup. I was reminded of that when I brought it up on a PS forum.
Stan - formerly stanl [ex-Pundit]

td

It took me a while to notice the bunder, myself. Sorry about that.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Quote from: td on December 04, 2024, 02:35:36 PMIt took me a while to notice the bunder, myself. Sorry about that.

Outside the fact the OP probably has a great WB WOL script utilizing the CLR, equally great comparison between PS and WB for creating a byte array.

[EDIT]:
Now just wondering could WB CLR use System.Text.Encoding with GetBytes() to create the initial array.
Stan - formerly stanl [ex-Pundit]

td

Here is a slightly easier-to-read version of the script:
gosub procs

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Script to perform Wake-On-LAN.
TargetIP = '192.168.0.123'
TargetMac = '00:E0:4C:08:03:E2'

; Get the broadcast address for the LAN.
objBcAddr = GetBroadcastFromIP(TargetIP)

; Create a magic macket for the targeted
; device.
MagicPack = CreateMagicPacket(TargetMac)

objClient = ObjectClrNew('System.Net.Sockets.UdpClient')

; Send the "magic packet".
objClient.Connect(objBcAddr, 7)
nSent = objClient.Send(MagicPack, ArrInfo(MagicPack, 1))
objClient.Close()

; Confirm transmition.
Terminate(nSent!=102,'WOL Error','Wrong number of magic packet bytes sent')
exit

;;;;;;
;; Define UDPs and load needed assembly.
:procs

;; Main line script and GetBroadcastFromIP UDF
;; need this.
ObjectClrOption('useany','System')

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Returns the broadcast address
;; of the network based on the caller
;;  supplied IP address.
#DefineFunction GetBroadcastFromIP(_ip)
   aIp = Arrayize(_ip, '.')
   aIp = ObjectType('array|ui1', aIp)
   objAddr = ObjectClrNew('System.Net.IPAddress', aIp)
   
   return objAddr.Broadcast   
#EndFunction

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Returns a Magic Packet byte array
;; based on the MAC address of the
;; target device.
#DefineFunction CreateMagicPacket(_macaddress)
    lMagPack = 'FF:FF:FF:FF:FF:FF'
    for i = 1 to 16
       lMagPack := ':':_macaddress
    next
    nCnt = ItemCount(lMagPack, ':')
    hMac = BinaryAlloc(1)
    for i = 1 to nCnt
      BinaryPokeHex(hMac, 0,ItemExtract(i, lMagPack,':'))
      aBytes[i-1] = BinaryPeek(hMac,0) 
    next
    BinaryFree(hMac)
   
   return ObjectType('array|ui1', aBytes)
#EndFunction

return ; end gosub
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade