Skip to content

Alternate Client

lancehilliard edited this page Apr 14, 2022 · 6 revisions

Perhaps you have a Windows machine where you cannot run BusyLight, but you nevertheless want that machine's activity to inform illumination. In that case, and if you are able to run a PowerShell script, the following can help.

This PowerShell script runs (in the background) on the machine where you cannot run BusyLight and sends activity updates to the BusyLight instance you presumably are running (on the machine attached to your BlinkStick).

Like BusyLight, this PowerShell script requires May 2019's Windows 10 1903 or greater.

Notice the configuration required at the top of the script. See Messaging and Configuration for information that will help you set these values.

# begin config
$logPath = "$HOME\logs\busylight";
$apiUsername = 'dluqnjic'
$apiPassword = '5r5DKUk2_UYPDSDBgUi5ZeAHRopcllPe'
$apiVhost = 'dluqnjic'
$apiExchange = 'amq.default'
$apiUrl = 'https://albatross.rmq.cloudamqp.com/api/exchanges/dluqnjic/amq.default/publish';
# end config

# Append date-time to beginning of specified value, and return the result
function Stamp([object]$value) {
    $when = Get-Date -Format "MM/dd/yyyy HH:mm:ss"
    return "["+$when+"] "+$value
}

# Stamp the specified value, and then print it
function Print([object]$value) {
    Stamp $value
}

# Log the given value with the given category, and truncating the log to 5000 lines
function Log([string]$category, [object]$value) {
    $message = Stamp "[$($category)] $($value)"
    "$($message)`n" + (Get-Content $logFilename -Raw 2> $null) | Set-Content $logFilename
    (gc -First 5000 $logFilename) | ? {$_.trim() -ne "" } | set-content $logFilename
}

# Log the given value with the INFO category
function LogInfo([object]$value) {
    Log "INFO" $value
}

# Log the given value with the ERROR category
function LogError([object]$value) {
    Log "ERROR" $value
}

# Scan for microphone activity and publish detected activity to the API
function Scan-And-Send {
    try {
        LogInfo "Scanning..."
        $hklmKeys = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone -Recurse
        $hkcuKeys = Get-ChildItem -Path HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\microphone -Recurse
        $keys = $hklmKeys + $hkcuKeys
        foreach ($key in $keys){
            $name = $key | Select-Object Name
            if (!$name.Name.EndsWith('NonPackaged')) {
                $path = "Registry::$($name.Name)"
                $lastUsedTimeStop = (Get-ItemProperty -Path $path -Name LastUsedTimeStop).LastUsedTimeStop
                if ($lastUsedTimeStop -eq "0") {
                    LogInfo "Sending..."
                    $postParams = '{"vhost": "${$apiVhost}","name": "${$apiExchange}","properties": {"delivery_mode": 2,"type": "microphone","headers": {}},"routing_key": "BusyLight","delivery_mode": "2","payload": "","payload_encoding": "string"}'
                    $response = Invoke-WebRequest -Headers @{"Authorization" = "Basic "+[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($apiUsername+":"+$apiPassword ))} -Uri $apiUrl -Method POST -Body $postParams
                    LogInfo "Sent."
                    break
                }
            }
        }
    }
    catch {
        LogError $_
    }
}

# Source: https://www.systanddeploy.com/2018/12/create-your-own-powershell.html
function Hide-Window {
    $windowcode = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'
    $asyncwindow = Add-Type -MemberDefinition $windowcode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru
    $null = $asyncwindow::ShowWindowAsync((Get-Process -PID $pid).MainWindowHandle, 0)
}

function Kill-Other-Instances {
    $scriptFileName = [System.IO.Path]::GetFileName($MyInvocation.ScriptName)
    $otherInstances = Get-WmiObject Win32_Process -Filter "Name='powershell.exe' AND CommandLine LIKE '%$scriptFileName%' AND NOT ProcessId=$PID"
    foreach ($otherInstance in $otherInstances) {
        " - Stopping other instance: "+$otherInstance.ProcessId
        Stop-Process -Id $otherInstance.ProcessId
    }
}

"Starting BusyLight..."
Kill-Other-Instances
New-Item -type Directory -Path $logPath -Force | Out-Null
$logFilename = Join-Path -Path $logPath "busylight.log"
Start-Sleep -s 1
"Hiding window..."
Start-Sleep -s 1

Hide-Window # use Task Manager if/when you want to kill the process
while($true) {
    Scan-And-Send
    Start-Sleep -s 4
}