Public/Wifi/Connect-WifiNetworkWps.ps1

<#$global:CurrentWpsTask = $null
$Global:ConnectTask = $null
Function AdapterConnectAsync {
    [OutputType([Windows.Foundation.IAsyncInfo]
    )]
    param(
        $Adapter, $AvailableNetwork, $ReconnectionKind,
        [Windows.Security.Credentials.PasswordCredential]$PasswordCredential,
        $ssid, $ConnectionMethod
    )
    Process {
        return $Adapter.ConnectAsync($AvailableNetwork, $ReconnectionKind, $PasswordCredential, $ssid, $ConnectionMethod)
    }
}#>


Function Connect-WifiNetworkWps {
    <#
.SYNOPSIS
    This function connects a Windows device to a Wi-Fi network using Wi-Fi Protected Setup (WPS).
    It supports two WPS connection methods: PushButton and PIN.
 
.DESCRIPTION
    The Connect-WifiNetworkWps function is a PowerShell script designed to simplify the process
    of connecting a Windows device to a Wi-Fi network via WPS. The function checks if the
    network supports WPS, and depending on the input, it uses either the PushButton method
    or the WPS PIN method for connection.
 
    - WPS Capabilities Check: Verifies if the target Wi-Fi network supports WPS.
    - WPS PIN and PushButton Support: The function can use either the WPS PIN method or
      PushButton method for connection.
      - If a WPS PIN is provided, the function ensures the PIN is numeric and checks if
        the network supports the PIN method.
      - If no PIN is provided, the PushButton method is used by default.
    - Adapter Handling: Retrieves available Wi-Fi adapters and attempts to connect using
      the first available adapter (currently, adapter 0 may be the only one supported).
    - Connection Attempt: Attempts to connect to the network, managing retries, timeouts,
      and errors.
    - Progress and Feedback: Uses Write-Progress to provide feedback on connection status.
 
.PARAMETER AvailableNetwork
    The Wi-Fi network object to which the function will attempt to connect (mandatory input).
 
.PARAMETER WpsPin
    The optional WPS PIN to use for connection. If not provided, the PushButton method
    is used.
 
.EXAMPLE
    Connect-WifiNetworkWps -AvailableNetwork $network -WpsPin '12345678'
    Connects to the specified Wi-Fi network using the provided WPS PIN.
 
.EXAMPLE
    Connect-WifiNetworkWps -AvailableNetwork $network
    Connects to the specified Wi-Fi network using the PushButton method (default).
 
.WARNING
    Currently, this script might only work with the first Wi-Fi adapter (adapter 0).
    There are still some bugs to iron out, and future versions will improve adapter handling.
 
.NOTES
    This script is intended to simplify Wi-Fi connections to networks that support WPS,
    and it is especially useful for automation in environments where manual connection
    via passwords is not desired or feasible.
 
#>

    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [Windows.Devices.WiFi.WiFiAvailableNetwork]$AvailableNetwork,

        [Parameter(Mandatory = $false)]
        [string]$WpsPin  # WPS Pin, required if using Pin method
    )
    
    Process {
        Write-Progress -Activity "WPS Connection"

        # Check if the network supports WPS at all
        $wpsCapabilities = Get-WifiNetworkWpsCapability -wifiNetwork $AvailableNetwork
        if ($null -eq $wpsCapabilities.WpsKinds ) {
            Write-Warning ("{0} does not support WPS" -f $AvailableNetwork.Ssid)
            return $null
        }

        # Get the Wi-Fi adapter
        $Adapter = Get-WiFiAvailableAdapter
        $ReconnectionKind = [Windows.Devices.WiFi.WiFiReconnectionKind]::Automatic
        $PasswordCredential = [Windows.Security.Credentials.PasswordCredential]::new()  # Create it once
        $ssid = $AvailableNetwork.Ssid

        # Automatically set the connection method based on the presence of a PIN
        if ($WpsPin) {
            # Validate that the WPS PIN is numeric and has the correct format (only digits)
            if ($WpsPin -match '^\d+$') {
                # If a WPS PIN is provided, check for Pin support
                if (-not ($wpsCapabilities.WpsKinds -contains 'Pin')) {
                    Write-Warning ("{0} does not support Pin WPS" -f $AvailableNetwork.Ssid)
                    return $null
                }
                $PasswordCredential.Password = $WpsPin
                $ConnectionMethodEnum = [Windows.Devices.WiFi.WiFiConnectionMethod]::WpsPin
            } else {
                Write-Warning ("Invalid WPS Pin. The PIN must only contain numeric digits.")
                return $null
            }
        } else {
            # If no PIN is provided, use PushButton (default)
            if (-not ($wpsCapabilities.WpsKinds -contains 'PushButton')) {
                Write-Warning ("{0} does not support PushButton WPS" -f $AvailableNetwork.Ssid)
                return $null
            }
            $ConnectionMethodEnum = [Windows.Devices.WiFi.WiFiConnectionMethod]::WpsPushButton
        }

        # Connection attempt with the chosen method
        Write-Host "Connecting to $ssid using $ConnectionMethodEnum method"

        # Start the connection task
        $ConnectTask = $Adapter[0].ConnectAsync($AvailableNetwork, $ReconnectionKind, $PasswordCredential, $ssid, $ConnectionMethodEnum)

        # Handle connection task with timeout
        $ResultType = ([Windows.Devices.WiFi.WiFiConnectionResult])
        Await -WinRtTask $ConnectTask -ResultType $ResultType -TimeoutMS 30000 -Activity "WPS Connection"

        Write-Progress -Activity "WPS Connection" -Completed
    }
}
<#Function Connect-WifiNetworkByPushButton {
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [Windows.Devices.Wifi.WifiAvailableNetwork]$AvailableNetwork
    )
    Process {
        Write-Progress -Activity "WPSConnection"
        #Just a Quick Check to see if the network you want to connect to has WpsPushToConnect
 
        if ( -not (Get-WifiNetworkWpsCapability -wifiNetwork $AvailableNetwork).WpsKinds -contains 'PushButton') {
            Write-Warning ("{0} Does not support PushButton" -f $AvailableNetwork.Ssid)
            Return $null
        }
         
        $Adapter = Get-WiFiAvailableAdapter
        $ReconnectionKind = [Windows.Devices.WiFi.WiFiReconnectionKind]::Automatic
        $PasswordCredential = [Windows.Security.Credentials.PasswordCredential]::new()
        $ssid = "" #$AvailableNetwork.Ssid
        $ConnectionMethod = [Windows.Devices.Wifi.WiFiConnectionMethod]::WpsPushButton
        Write-Host $AvailableNetwork.Ssid
        #[Windows.Foundation.IAsyncOperation`1[Windows.Devices.WiFi.WiFiConnectionMethod]]
        $ConnectTask = $Adapter[0].ConnectAsync($AvailableNetwork, $ReconnectionKind, $PasswordCredential, $ssid, $ConnectionMethod)
        #$ConnectTask = AdapterConnectAsync -Adapter $Adapter -AvailableNetwork $AvailableNetwork -ReconnectionKind $ReconnectionKind -PasswordCredential $PasswordCredential -Ssid $ssid -ConnectionMethod $ConnectionMethod
        $ResultType = ([Windows.Devices.Wifi.WiFiConnectionResult])
        Await -WinRtTask $ConnectTask -ResultType $ResultType -TimeoutMS 30000 -ProgressBarName "WPSConnection"
        Write-Progress -Activity "WPSConnection" -Completed
    }
}#>