Skip to content

Instantly share code, notes, and snippets.

@keithga
Created November 4, 2025 03:16
Show Gist options
  • Select an option

  • Save keithga/e2ef180a837c214e5c00bb1dd9acc650 to your computer and use it in GitHub Desktop.

Select an option

Save keithga/e2ef180a837c214e5c00bb1dd9acc650 to your computer and use it in GitHub Desktop.
PowerShell module for Belkin WeMo switches
<#
.Synopsis
Belkin WeMo Library
.DESCRIPTION
Powershell library for WeMo Switches (Model F7C063)
.NOTES
Now that We-Mo switches are NO LONGER being supported by belkin (boo),
I will need a way to Reset, Join, and control my We-Mo switches Model F7C063.
.EXAMPLE
RESET is easy - Just Hold down the Power Switch while plugging into a power socket.
.EXAMPLE
To Configure a WeMo switch, you will need a PC with a Wi-Fi card.
Simply run the cmdlet with the SSID and Password:
Find-WeMoSwitches -Password "MySecret123" -SSID "MyHomeNetwork"
This script will automatically connect to the first 'WeMo.Mini.XXX' SSID.
It will connect with the device, ensure that the SSID is avaiable.
It will then bind the device using the SSID and Password.
This fuction REQUIRES openssl.exe from the git desktop program.
.EXAMPLE
get-wemoBasicEvent -ipaddress '192.168.1.111'
will get the current state of the wemo switch at this IP address.
1 = On, 0 = Off
.EXAMPLE
Set-WeMoBasicEvent -ipaddress '192.168.1.111' -data 0
Will Set the current state of the wemo switch at this IP address.
Where Data 1 = On, 0 = Off
.EXAMPLE
switch-WeMoBasicEvent -ipaddress '192.168.1.111'
Will toggle the switch, turn off if on, turn on if off.
.NOTES
https://github.com/pywemo/pywemo
https://github.com/vadimkantorov/wemosetup/blob/master/wemosetup.py
More operations at: http://$($IPAddress):$($Port)/setup.xml
Future: Add a command to find all WeMo switches on the local network.
#>
function Invoke-WeMoSoapCommand {
[cmdletbinding()]
param(
[Parameter(Mandatory=$true)]
[String] $Uri,
[Parameter(Mandatory=$true)]
[String] $SoapAction,
[String] $SoapBody,
[String] $Method = 'POST'
)
$Soapactions = $SoapAction.trim("""") -split "#"
$WebArgs = @{
Uri = $Uri
Headers = @{ SOAPACTION = """$SoapAction"""; 'Content-Type' = 'text/xml' }
Method = $Method
Body = @"
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:$($SoapActions[1]) xmlns:u="$($SoapActions[0])">
$($SoapBody)
</u:$($SoapActions[1])>
</s:Body>
</s:Envelope>
"@
}
$webArgs | convertto-json -Depth 2 | write-verbose
$result = Invoke-WebRequest @WebArgs
if ($Result.StatusCode -ne 200) {
$result | out-string | Write-Warning
}
(($result | % content ) -as [xml] | % envelope | % body).innerxml | Write-verbose
(($result | % content ) -as [xml] | % envelope | % body) | % childnodes | % Childnodes | % '#text' | Write-Output
}
function Get-WeMoBasicEvent {
param(
[Parameter(Mandatory=$true)]
[string] $IPaddress,
$Port
)
if ( $port -eq $null ) {
$port = Find-WeMoPort $IPaddress
}
$WeMoCommand = @{
Uri = "http://$($ipAddress):$($Port)/upnp/control/basicevent1"
SoapAction = 'urn:Belkin:service:basicevent:1#GetBinaryState'
}
Invoke-WeMoSoapCommand @WeMoCommand | write-output
}
function Find-WeMoPort {
param(
[Parameter(Mandatory=$true)]
[string] $IPaddress
)
while ( -not ( Test-NetConnection -ComputerName $IPaddress -InformationLevel Quiet ) ) {
write-verbose "Trying to connect..."
}
$foundPort = -1
foreach ( $port in (49153, 49152, 49154, 49151, 49155, 49156, 49157, 49158, 49159) ) {
if ( Test-NetConnection -ComputerName $IPaddress -port $port -InformationLevel Quiet ) {
write-verbose "Found: $Port"
return $port
}
}
throw "Unable to find responding port on device $IPAddress"
}
function Get-WeMoStatus {
param(
[Parameter(Mandatory=$true)]
[string] $IPaddress,
$Port
)
if ( $port -eq $null ) {
$port = Find-WeMoPort $IPaddress
}
(iwr "http://$($IPaddress):$($Port)/setup.xml" | % Content ) -as [XML] | % root | % device | write-output
}
function Set-WeMoBasicEvent {
param(
[Parameter(Mandatory=$true)]
[string] $IPaddress,
[Parameter(Mandatory=$true)]
[int] $data,
$Port
)
if ( $port -eq $null ) {
$port = Find-WeMoPort $IPaddress
}
$WeMoCommand = @{
Uri = "http://$($ipAddress):$($Port)/upnp/control/basicevent1"
SoapAction = 'urn:Belkin:service:basicevent:1#SetBinaryState'
SoapBody = "<BinaryState>{0}</BinaryState>" -f $data
}
Invoke-WeMoSoapCommand @WeMoCommand | select-object -first 1 | write-output
}
function switch-WeMoBasicEvent {
param(
[Parameter(Mandatory=$true)]
[string] $IPaddress,
$Port
)
$Data = Get-WeMoBasicEvent @PSBoundParameters
write-verbose "Data is: $Data"
Set-WeMoBasicEvent @PSBoundParameters -data ( !($data -as [int]) -as [int] )
}
Function Find-WeMoSwitches {
[cmdletbinding()]
param(
[Parameter(Mandatory=$true)]
[string] $Password,
[string] $SSID
)
$IPAddress = "10.22.22.1"
#region Find WeMo Device and Connect
$found = (netsh wlan show networks) |
Where-Object { $_ -like "*SSID*" } |
ForEach-Object { $_.Split(':')[1].Trim() } |
Where-Object { $_ -like "Wemo.Mini.*" }
if ( $Found -eq $null ) {
throw "No WeMo devices found on Wi-Fi"
}
if ( $Found.count -gt 1 ) {
$found = $found | Out-GridView -Title "Select the WeMo Switch to prepare" -OutputMode Single
}
@"
<?xml version="1.0"?>
<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
<name>$Found</name>
<SSIDConfig>
<SSID>
<name>$Found</name>
</SSID>
</SSIDConfig>
<connectionType>ESS</connectionType>
<connectionMode>manual</connectionMode>
<MSM>
<security>
<authEncryption>
<authentication>open</authentication>
<encryption>none</encryption>
<useOneX>false</useOneX>
</authEncryption>
</security>
</MSM>
<MacRandomization xmlns="http://www.microsoft.com/networking/WLAN/profile/v3">
<enableRandomization>true</enableRandomization>
<randomizationSeed>1347463800</randomizationSeed>
</MacRandomization>
</WLANProfile>
"@ | out-file "$env:temp\SSID$($Found).xml" -Encoding utf8
if ( -not ( netsh wlan show networks | where-object { $_ -like "*$($Found)*" } ) ) {
netsh wlan add profile "FileName=$env:temp\SSID$($Found).xml"
netsh wlan connect Name=$found
}
#endregion
#region Test Device:
$Port = Find-WeMoPort $IPAddress
write-host "Found Device $IPAddress port: $Port"
#endregion
#region Get the AP List
$WeMoCommand = @{
Uri = "http://$($ipAddress):$($Port)/upnp/control/WiFiSetup1"
SoapAction = 'urn:Belkin:service:WiFiSetup:1#GetApList'
}
$APList = Invoke-WeMoSoapCommand @WeMoCommand
$AP = $null
if ( $SSID ) {
$AP = $aplist -split "`n" | Where-Object { $_.startswith($SSID) } | select-object -first 1
}
if ( $AP -eq $null ) {
$AP = $aplist -split "`n" | Out-GridView -OutputMode Single -Title "Select your Wi-Fi Access Point"
}
if ( $AP -eq $null ) {
throw "Need an Access Point selected"
}
$AP | write-verbose
`
#endregion
#region Get MetaInfo
$WeMoCommand = @{
Uri = "http://$($ipAddress):$($Port)/upnp/control/metainfo1"
SoapAction = 'urn:Belkin:service:metainfo:1#GetMetaInfo'
}
$MetaArray = Invoke-WeMoSoapCommand @WeMoCommand
#endregion
#region Get Encrypted String
# Written under protest.
$keydata = $metaarray.Substring(0,6) + $MetaArray.SubString(13,14) + $MetaArray.SubString(6,6)
$keydata | write-verbose
$salt = ([BitConverter]::ToString([Text.Encoding]::UTF8.GetBytes($keydata.Substring(0,8)))).Replace("-","").ToLower()
$iv = ([BitConverter]::ToString([Text.Encoding]::UTF8.GetBytes($keydata.Substring(0,16)))).Replace("-","").ToLower()
$password | out-file -Encoding ascii -NoNewline $env:TEMP\pw.txt
echo "'C:\Program Files\git\usr\bin\openssl.exe' enc -aes-128-cbc -md md5 -S $salt -iv $iv -pass 'pass:$keydata' -v -a -in $env:TEMP\pw.txt"
$encryptedPassword = & 'C:\Program Files\git\usr\bin\openssl.exe' enc -aes-128-cbc -md md5 -S $salt -iv $iv -pass "pass:$keydata" -v -a -in "$env:TEMP\pw.txt"
del $env:temp\pw.txt
$encryptedPassword += "{0:x2}" -f $encryptedPassword.Length
$encryptedPassword += "{0:x2}" -f $password.Length
write-verbose "encpw: $encryptedPassword $($encryptedPassword.length)"
#endregion
#region Set SSID and Password
$APData = $ap.trim("""").split("|")
$WeMoCommand = @{
Uri = "http://$($ipAddress):$($Port)/upnp/control/WiFiSetup1"
SoapAction = 'urn:Belkin:service:WiFiSetup:1#ConnectHomeNetwork'
SoapBody = @"
<ssid>{0}</ssid>
<channel>{1}</channel>
<auth>{2}</auth>
<encrypt>{3}</encrypt>
<password>{4}</password>
"@ -f $APData[0],$APData[1],$APData[3].Split("/")[0],$APData[3].Split("/")[1].trim(','),$encryptedPassword
}
$WeMoCommand | convertto-json -depth 5 | write-verbose
$Status = Invoke-WeMoSoapCommand @WeMoCommand
#endregion
Write-Verbose "We may loose Wi-Fi connectivity with the device after this point."
write-verbose "This is a good thing, look for the device on the regular network."
sleep 10
#region Get Network stauts
$WeMoCommand = @{
Uri = "http://$($ipAddress):$($Port)/upnp/control/WiFiSetup1"
SoapAction = 'urn:Belkin:service:WiFiSetup:1#GetNetworkStatus'
}
$Status = Invoke-WeMoSoapCommand @WeMoCommand
if ( $status -notin (1,3) ) {
write-warning "Status $Status did not return 1,3 after setting Wi-Fi"
}
#endregion
#region Done
$WeMoCommand = @{
Uri = "http://$($ipAddress):$($Port)/upnp/control/WiFiSetup1"
SoapAction = 'urn:Belkin:service:WiFiSetup:1#CloseSetup'
}
$Status = Invoke-WeMoSoapCommand @WeMoCommand
if ( $Status -ne "success" ) {
throw "CloseSetup() did not return Success"
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment