WiFiProfileManagement.psm1

$script:localizedData = Import-LocalizedData -BaseDirectory "$PSScriptRoot\en-US" -FileName WiFiProfileManagement.strings.psd1

<#
    .SYNOPSIS
        Retrieves the list of available networks on a wireless LAN interface.
    .PARAMETER WiFiAdapterName
        Specifies the name of the wireless network adapter on the machine. This is used to obtain the Guid of the interface.
        The default value is 'Wi-Fi'
    .EXAMPLE
        PS C:\>Get-WiFiAvailableNetwork

        SSID SignalStength SecurityEnabled dot11DefaultAuthAlgorithm dot11DefaultCipherAlgorithm
        ---- ------------- --------------- ------------------------- ---------------------------
                                63 True DOT11_AUTH_ALGO_RSNA_PSK DOT11_CIPHER_ALGO_CCMP
        gogoinflight 63 False DOT11_AUTH_ALGO_80211_OPEN DOT11_CIPHER_ALGO_NONE
#>

function Get-WiFiAvailableNetwork
{
    [CmdletBinding()]
    [OutputType([WiFi.ProfileManagement+WLAN_AVAILABLE_NETWORK])]
    param
    (
        [Parameter()]
        [System.String]
        $WiFiAdapterName = 'Wi-Fi'
    )    

    begin
    {
        $interfaceGUID = Get-WiFiInterfaceGuid -WiFiAdapterName $WiFiAdapterName
        $clientHandle = New-WiFiHandle
        $networkPointer = 0
    }
    process
    {
        [void][WiFi.ProfileManagement]::WlanGetAvailableNetworkList($clientHandle,$interfaceGUID,0,[IntPtr]::zero,[ref]$networkPointer)
        $availableNetworks = [WiFi.ProfileManagement+WLAN_AVAILABLE_NETWORK_LIST]::new($networkPointer)
        
        foreach ($network in $availableNetworks.wlanAvailableNetwork)
        {
            [WiFi.ProfileManagement+WLAN_AVAILABLE_NETWORK]$network
        }
    }
    end
    {
        [WiFi.ProfileManagement]::WlanFreeMemory($networkPointer) 
        Remove-WiFiHandle -ClientHandle $clientHandle
    }
}

<#
    .SYNOPSIS
        Lists the wireless profiles and their configuration settings.
    .PARAMETER ProfileName
        The name of the WiFi profile.
    .PARAMETER WiFiAdapterName
        Specifies the name of the wireless network adapter on the machine. This is used to obtain the Guid of the interface.
        The default value is 'Wi-Fi'
    .PARAMETER ClearKey
        Specifies if the password of the profile is to be returned.
    .EXAMPLE
        PS C:\>Get-WiFiProfile -ProfileName TestWiFi

        SSIDName : TestWiFi
        ConnectionMode : auto
        Authentication : WPA2PSK
        Encryption : AES
        Password :

        Get the WiFi profile information on wireless profile TestWiFi

    .EXAMPLE
        PS C:\>Get-WiFiProfile -ProfileName TestWiFi -CLearKey

        SSIDName : TestWiFi
        ConnectionMode : auto
        Authentication : WPA2PSK
        Encryption : AES
        Password : password1

        This examples shows the use of the ClearKey switch to return the WiFi profile password.

    .EXAMPLE
        PS C:\>Get-WiFiProfile | where {$_.ConnectionMode -eq 'auto' -and $_.Authentication -eq 'open'}

        This example shows how to find WiFi profiles with insecure connection settings.
#>

function Get-WiFiProfile
{
    [CmdletBinding()]
    [OutputType([System.Management.Automation.PSCustomObject])]
    param
    (
        [Parameter(Position=0)]
        [System.String[]]
        $ProfileName,

        [Parameter()]
        [System.String]
        $WiFiAdapterName = 'Wi-Fi',

        [Parameter()]
        [Switch]
        $ClearKey
    )

    begin
    {
        [String]$pstrProfileXml = $null
        $wlanAccess = 0
        $ProfileListPointer = 0
        $interfaceGuid = Get-WiFiInterfaceGuid -WiFiAdapterName $WiFiAdapterName

        $clientHandle = New-WiFiHandle

        if ($ClearKey)
        {
          $wlanProfileFlags = 13
        }
        else
        {
           $wlanProfileFlags = 0
        }
    }
    process
    {
        if (!$ProfileName)
        {
            [void][WiFi.ProfileManagement]::WlanGetProfileList($clientHandle,$interfaceGUID,[IntPtr]::zero,[ref]$ProfileListPointer)
            $WiFiProfileList = [WiFi.ProfileManagement+WLAN_PROFILE_INFO_LIST]::new($ProfileListPointer)
            $ProfileName = ($WiFiProfileList.ProfileInfo).strProfileName
        }

        foreach ($WiFiProfile in $ProfileName)
        {
            Get-WiFiProfileInfo -ProfileName $WiFiProfile -InterfaceGuid $interfaceGUID -ClientHandle $clientHandle -WlanProfileFlags $wlanProfileFlags
        }
    }
    end
    {
        Remove-WiFiHandle -ClientHandle $clientHandle
    }
}

<#
    .SYNOPSIS
        Creates the content of a specified wireless profile.
    .DESCRIPTION
        Creates the content of a wireless profile by calling the WlanSetProfile native function but with the overide parameter set to false.
    .PARAMETER ProfileName
        The name of the wireless profile to be updated. Profile names are case sensitive.
    .PARAMETER ConnectionMode
        Indicates whether connection to the wireless LAN should be automatic ("auto") or initiated ("manual") by user.
    .PARAMETER Authentication
        Specifies the authentication method to be used to connect to the wireless LAN.
    .PARAMETER Encryption
        Sets the data encryption to use to connect to the wireless LAN.
    .PARAMETER Password
        The network key or passpharse of the wireless profile in the form of a secure string.
    .PARAMETER XmlProfile
        The XML representation of the profile.
    .EXAMPLE
        PS C:\>$password = Read-Host -AsSecureString
        **********

        PS C:\>New-WiFiProfile -ProfileName MyNetwork -ConnectionMode auto -Authentication WPA2PSK -Encryption AES -Password $password

        This examples shows how to create a wireless profile by using the individual parameters.
    .EXAMPLE
        PS C:\>$templateProfileXML = @"
        <?xml version="1.0"?>
        <WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
            <name>MyNetwork</name>
            <SSIDConfig>
                <SSID>
                    <name>MyNetwork</name>
                </SSID>
            </SSIDConfig>
            <connectionType>ESS</connectionType>
            <connectionMode>manual</connectionMode>
            <MSM>
                <security>
                    <authEncryption>
                        <authentication>WPA2PSK</authentication>
                        <encryption>AES</encryption>
                        <useOneX>false</useOneX>
                    </authEncryption>
                    <sharedKey>
                        <keyType>passPhrase</keyType>
                        <protected>false</protected>
                        <keyMaterial>password1</keyMaterial>
                    </sharedKey>
                </security>
            </MSM>
        </WLANProfile>
        "@

        PS C:\>New-WiFiProfile -XmlProfile $templateProfileXML

        This example demonstrates how to update a wireless profile with the XmlProfile parameter.
    .NOTES
        https://msdn.microsoft.com/en-us/library/windows/desktop/ms706795(v=vs.85).aspx
        https://msdn.microsoft.com/en-us/library/windows/desktop/ms707381(v=vs.85).aspx
#>

function New-WiFiProfile
{
    [CmdletBinding()]
    param 
    (
        [Parameter(Mandatory=$true,Position=0,ParameterSetName='UsingArguments')]
        [System.String]
        $ProfileName,

        [Parameter(ParameterSetName='UsingArguments')]
        [ValidateSet('manual','auto')]
        [System.String]
        $ConnectionMode = 'auto',

        [Parameter(ParameterSetName='UsingArguments')]
        [System.String]
        $Authentication = 'WPA2PSK',

        [Parameter(ParameterSetName='UsingArguments')]
        [System.String]
        $Encryption = 'AES',

        [Parameter(Mandatory=$true,ParameterSetName='UsingArguments')]
        [System.Security.SecureString]
        $Password,

        [Parameter()]
        [System.String]
        $WiFiAdapterName = 'Wi-Fi',

        [Parameter(Mandatory=$true,ParameterSetName='UsingXml')]
        [System.String]
        $XmlProfile
    )

    begin
    {
        if ($Password)
        {
            $secureStringToBstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
            $plainPassword      = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($secureStringToBstr) 
        }

        $clientHandle = New-WiFiHandle
        $interfaceGuid = Get-WiFiInterfaceGuid -WiFiAdapterName $WiFiAdapterName
        $flags = 0
        $allUserProfileSecurity = [System.IntPtr]::zero
        $overwrite = $false
        $reasonCode = [IntPtr]::Zero                  

        if ($XmlProfile)
        {
            $profileXML = $XmlProfile
        }
        else
        {
            $newProfileParameters = @{
                ProfileName    = $ProfileName
                ConnectionMode = $ConnectionMode
                Authentication = $Authentication
                Password       = $plainPassword
            }

            $profileXML = New-WiFiProfileXml @newProfileParameters
        }
    }
    process
    {
        $profilePointer = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni($profileXML)

        [WiFi.ProfileManagement]::WlanSetProfile(
                                        $clientHandle,
                                        [ref]$interfaceGuid,
                                        $flags,
                                        $profilePointer,
                                        [IntPtr]::Zero,
                                        $overwrite,
                                        [IntPtr]::Zero,
                                        [ref]$reasonCode
                                        )

        Format-WiFiReasonCode -ReasonCode $reasonCode
    }
    end
    {
        Remove-WiFiHandle -ClientHandle $clientHandle
    }
}

<#
    .SYNOPSIS
        Deletes a WiFi profile.
    .PARAMETER ProfileName
        The name of the profile to be deleted. Profile names are case-sensitive.
    .PARAMETER WiFiAdapterName
        Specifies the name of the wireless network adapter on the machine. This is used to obtain the Guid of the interface.
        The default value is 'Wi-Fi'
    .EXAMPLE
    C:\>Remove-WiFiProfile -ProfileName FreeWiFi

    This examples deletes the FreeWiFi profile.
#>

function Remove-WiFiProfile
{
    [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='High')]
    Param 
    (
        [Parameter(Position = 0,Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
        [System.String[]]
        $ProfileName,

        [Parameter(Position = 1)]
        [System.String]
        $WiFiAdapterName = 'Wi-Fi'
    )

    begin
    {
        $interfaceGUID = Get-WiFiInterfaceGuid
        $clientHandle = New-WiFiHandle
    }
    process
    {
        foreach ($wiFiProfile in $ProfileName)
        {
            if ($PSCmdlet.ShouldProcess("$($script:localizedData.ShouldProcessDelete -f $WiFiProfile)"))
            {
                $deleteProfileResult = [WiFi.ProfileManagement]::WlanDeleteProfile($clientHandle,$interfaceGUID,$wiFiProfile,[IntPtr]::zero)            

                if ($deleteProfileResult -ne 0)
                {
                    throw $($script:localizedData.ErrorDeletingProfile -f $deleteProfileResult)
                }
            }
        }
    }
    end
    {
        Remove-WiFiHandle -ClientHandle $clientHandle
    }
}

<#
    .SYNOPSIS
        Sets the content of a specified wireless profile.
    .DESCRIPTION
        Calls the WlanSetProfile native function with overide parameter set to true.
    .PARAMETER ProfileName
        The name of the wireless profile to be updated. Profile names are case sensitive.
    .PARAMETER ConnectionMode
        Indicates whether connection to the wireless LAN should be automatic ("auto") or initiated ("manual") by user.
    .PARAMETER Authentication
        Specifies the authentication method to be used to connect to the wireless LAN.
    .PARAMETER Encryption
        Sets the data encryption to use to connect to the wireless LAN.
    .PARAMETER Password
        The network key or passpharse of the wireless profile in the form of a secure string.
    .PARAMETER XmlProfile
        The XML representation of the profile.
    .EXAMPLE
        PS C:\>$password = Read-Host -AsSecureString
        **********

        PS C:\>Set-WiFiProfile -ProfileName MyNetwork -ConnectionMode auto -Authentication WPA2PSK -Encryption AES -Password $password

        This examples shows how to update or create a wireless profile by using the individual parameters.
    .EXAMPLE
        PS C:\>$templateProfileXML = @"
        <?xml version="1.0"?>
        <WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
            <name>MyNetwork</name>
            <SSIDConfig>
                <SSID>
                    <name>MyNetwork</name>
                </SSID>
            </SSIDConfig>
            <connectionType>ESS</connectionType>
            <connectionMode>manual</connectionMode>
            <MSM>
                <security>
                    <authEncryption>
                        <authentication>WPA2PSK</authentication>
                        <encryption>AES</encryption>
                        <useOneX>false</useOneX>
                    </authEncryption>
                    <sharedKey>
                        <keyType>passPhrase</keyType>
                        <protected>false</protected>
                        <keyMaterial>password1</keyMaterial>
                    </sharedKey>
                </security>
            </MSM>
        </WLANProfile>
        "@

        PS C:\>Set-WiFiProfile -XmlProfile $templateProfileXML

        This example demonstrates how to update a wireless profile with the XmlProfile parameter.
    .NOTES
        https://msdn.microsoft.com/en-us/library/windows/desktop/ms706795(v=vs.85).aspx
        https://msdn.microsoft.com/en-us/library/windows/desktop/ms707381(v=vs.85).aspx
#>

function Set-WiFiProfile
{
    [CmdletBinding()]
    param 
    (
        [Parameter(Mandatory=$true,Position=0,ParameterSetName='UsingArguments')]
        [System.String]
        $ProfileName,
        
        [Parameter(ParameterSetName='UsingArguments')]
        [ValidateSet('manual','auto')]
        [System.String]
        $ConnectionMode = 'auto',
        
        [Parameter(Mandatory=$true,ParameterSetName='UsingArguments')]
        [System.String]
        $Authentication = 'WPA2PSK',
        
        [parameter(ParameterSetName='UsingArguments')]
        [System.String]
        $Encryption = 'AES',

        [Parameter(Mandatory=$true,ParameterSetName='UsingArguments')]
        [System.Security.SecureString]
        $Password,
        
        [Parameter()]
        [System.String]
        $WiFiAdapterName = 'Wi-Fi',

        [Parameter(Mandatory=$true,ParameterSetName='UsingXml')]
        [System.String]
        $XmlProfile
    )

    begin
    {
        if ($Password)
        {
            $secureStringToBstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
            $plainPassword      = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($secureStringToBstr) 
        }
        
        $clientHandle = New-WiFiHandle
        $interfaceGuid = Get-WiFiInterfaceGuid -WiFiAdapterName $WiFiAdapterName
        $flags = 0
        $allUserProfileSecurity = [IntPtr]::zero
        $overwrite = $true
        $reasonCode = [IntPtr]::Zero

        if ($XmlProfile)
        {
            $profileXML = $XmlProfile
        }
        else
        {
            $newProfileParameters = @{
                ProfileName    = $ProfileName
                ConnectionMode = $ConnectionMode
                Authentication = $Authentication
                Password       = $plainPassword
            }

            $profileXML = New-WiFiProfileXml @newProfileParameters
        }
    }
    process
    {
        $profilePointer = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni($profileXML)

        $setProfileResults = [WiFi.ProfileManagement]::WlanSetProfile(
                                        $clientHandle,
                                        [ref]$interfaceGuid,
                                        $flags,
                                        $profilePointer,
                                        [IntPtr]::Zero,
                                        $overwrite,
                                        [IntPtr]::Zero,
                                        [ref]$reasonCode
                                        )

        Format-WiFiReasonCode -ReasonCode $reasonCode
    }
    end
    {
        Remove-WiFiHandle -ClientHandle $clientHandle
    }
}

<#
    .SYNOPSIS
        An internal function to format the reason code returned by WlanSetProfile
    .PARAMETER ReasonCode
        A vlaue that indicates why the profile failed.
#>

function Format-WiFiReasonCode
{
    [OutputType([System.String])]
    [Cmdletbinding()]
    param
    (
        [Parameter()]
        [System.IntPtr]
        $ReasonCode
    )

    $stringBuilder = New-Object -TypeName Text.StringBuilder
    $stringBuilder.Capacity = 1024
    [WiFi.ProfileManagement]::WlanReasonCodeToString($ReasonCode.ToInt32(),$stringBuilder.Capacity,$stringBuilder,[IntPtr]::zero) | Out-Null

    return $stringBuilder.ToString()
}

<#
    .SYNOPSIS
        Retrieves the guid of the network interface.
    .PARAMETER WiFiAdapterName
        The name of the wireless network adapter.
#>

function Get-WiFiInterfaceGuid
{
    [CmdletBinding()]
    [OutputType([System.Guid])]
    param 
    (
        [Parameter()]
        [System.String]
        $WiFiAdapterName = 'Wi-Fi'
    )
    
    $osVersion = [Environment]::OSVersion.Version

    if ($osVersion -ge ([Version] 6.2))
    {
        [Guid]$interfaceGuid = (Get-NetAdapter -Name $WiFiAdapterName).interfaceguid
    }
    else
    {
        $wifiAdapterInfo = Get-WmiObject -Query "select Name, NetConnectionID from Win32_NetworkAdapter where NetConnectionID = '$WiFiAdapterName'"
        [Guid]$interfaceGuid = (Get-WmiObject -Query "select SettingID from Win32_NetworkAdapterConfiguration where Description = '$($wifiAdapterInfo.Name)'").SettingID
    }

    return $interfaceGuid
}

<#
    .SYNOPSIS
        Retrieves the information of a WiFi profile.
    .PARAMETER ProfileName
        The name of the WiFi profile.
    .PARAMETER InterfaceGuid
        Specifies the Guid of the wireless network card. This is required by the native WiFi functions.
    .PARAMETER ClientHandle
        Specifies the handle used by the natvie WiFi functions.
    .PARAMETER WlanProfileFlags
        A pointer to the address location used to provide additional information about the request.

#>

function Get-WiFiProfileInfo
{
    [OutputType([System.Management.Automation.PSCustomObject])]
    [CmdletBinding()]    
    param
    (
        [Parameter()]
        [System.String]
        $ProfileName,

        [Parameter()]
        [System.Guid]
        $InterfaceGuid,

        [Parameter()]
        [System.IntPtr]
        $ClientHandle,

        [System.Int16]
        $WlanProfileFlags
    )
    
    begin
    {
        [String]$pstrProfileXml = $null    
        $wlanAccess = 0
        $WlanProfileFlagsInput = $WlanProfileFlags
    }
    process
    {
        $profileInfoResult = [WiFi.ProfileManagement]::WlanGetProfile($ClientHandle,$InterfaceGuid,$ProfileName,[IntPtr]::Zero,[ref]$pstrProfileXml,[ref]$WlanProfileFlags,[ref]$wlanAccess)

        if ($profileInfoResult -ne 0)
        {
            throw $($script:localizedData.ErrorGettingProfile -f $profileInfoResult)
        }
        elseIf ($profileInfoResult -eq 1168)
        {
            throw $($script:localizedData.ProfileNotFound -f $ProfileName)
        }

        $wlanProfile = [xml]$pstrProfileXml

        if ($WlanProfileFlagsInput -eq 13)
        {
            $password = $wlanProfile.WLANProfile.MSM.security.sharedKey.keyMaterial
        }
        else
        {
            $password = $null
        }

        [WiFi.ProfileManagement+ProfileInfo]@{
            ProfileName    = $wlanProfile.WLANProfile.SSIDConfig.SSID.name
            ConnectionMode = $wlanProfile.WLANProfile.connectionMode
            Authentication = $wlanProfile.WLANProfile.MSM.security.authEncryption.authentication
            Encryption     = $wlanProfile.WLANProfile.MSM.security.authEncryption.encryption
            Password       = $password
            Xml            = $pstrProfileXml            
        }
    }
    end 
    {
        $xmlPtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalAuto($pstrProfileXml)
        [WiFi.ProfileManagement]::WlanFreeMemory($xmlPtr) 
    }
}

<#
    .SYNOPSIS
        Opens a WiFi handle
#>

function New-WiFiHandle
{    
    [CmdletBinding()]
    [OutputType([System.IntPtr])]
    param()

    $maxClient = 2
    [Ref]$negotiatedVersion = 0
    $clientHandle = [IntPtr]::zero

    $handle = [WiFi.ProfileManagement]::WlanOpenHandle($maxClient,[IntPtr]::Zero,$negotiatedVersion,[ref]$clientHandle)
    
    if ($handle -eq 0)
    {
        return $clientHandle
    }
    else
    {
        throw $($Script:localizedData.ErrorOpeningHandle)
    }
}

<#
    .SYNOPSIS
        Create a string of XML that represents the wireless profile.
    .PARAMETER ProfileName
        The name of the wireless profile to be updated. Profile names are case sensitive.
    .PARAMETER ConnectionMode
        Indicates whether connection to the wireless LAN should be automatic ("auto") or initiated ("manual") by user.
    .PARAMETER Authentication
        Specifies the authentication method to be used to connect to the wireless LAN.
    .PARAMETER Encryption
        Sets the data encryption to use to connect to the wireless LAN.
#>

function New-WiFiProfileXml
{
    [OutputType([System.String])]
    [CmdletBinding()]
    param 
    (
        [Parameter(Mandatory=$true,Position=0)]
        [System.String]
        $ProfileName,
        
        [Parameter()]
        [ValidateSet('manual','auto')]
        [System.String]
        $ConnectionMode = 'auto',
        
        [Parameter()]
        [System.String]
        $Authentication = 'WPA2PSK',
        
        [Parameter()]
        [System.String]
        $Encryption = 'AES',
        
        [Parameter(Mandatory=$true)]
        [System.String]
        $Password   
    )
    
    process
    {
        $stringWriter = [System.IO.StringWriter]::new()
        $xmlWriter    = [System.Xml.XmlTextWriter]::new($stringWriter)

        $xmlWriter.WriteStartDocument()
        $xmlWriter.WriteStartElement("WLANProfile","http://www.microsoft.com/networking/WLAN/profile/v1");
        $xmlWriter.WriteElementString("name", "$profileName");
        $xmlWriter.WriteStartElement("SSIDConfig");
        $xmlWriter.WriteStartElement("SSID");
        $xmlWriter.WriteElementString("name", "$profileName");
        $xmlWriter.WriteEndElement();
        $xmlWriter.WriteEndElement();
        $xmlWriter.WriteElementString("connectionType", "ESS");
        $xmlWriter.WriteElementString("connectionMode", $ConnectionMode);
        $xmlWriter.WriteStartElement("MSM");
        $xmlWriter.WriteStartElement("security");
        $xmlWriter.WriteStartElement("authEncryption");
        $xmlWriter.WriteElementString("authentication", $Authentication);
        $xmlWriter.WriteElementString("encryption", "$Encryption");
        $xmlWriter.WriteEndElement();
        $xmlWriter.WriteStartElement("sharedKey");
        $xmlWriter.WriteElementString("keyType", "passPhrase");
        $xmlWriter.WriteElementString("protected", "false");
        $xmlWriter.WriteElementString("keyMaterial", $plainPassword);
        $xmlWriter.WriteEndElement();
        $xmlWriter.WriteEndElement();
        $xmlWriter.WriteEndElement();
        $xmlWriter.WriteEndElement();
        $xmlWriter.WriteEndDocument();

        $xmlWriter.Close()
        $stringWriter.ToString()
    }
}

<#
    .SYNOPSIS
        Closes an open WiFi handle
    .Parameter ClientHandle
        Specifies the object that represents the open WiFi handle.
#>

function Remove-WiFiHandle
{
    [CmdletBinding()]
    param
    (
        [Parameter()]
        [IntPtr]$ClientHandle
    )

    $closeHandle = [WiFi.ProfileManagement]::WlanCloseHandle($ClientHandle,[IntPtr]::zero)

    if ($closeHandle -eq 0)
    {
        Write-Verbose -Message $script:localizedData.HandleClosed
    }
    else
    {
        throw $($script:localizedData.ErrorClosingHandle)
    }
}


$WlanGetProfileListSig = @'
 
    [DllImport("wlanapi.dll")]
    public static extern uint WlanOpenHandle(
        [In] UInt32 clientVersion,
        [In, Out] IntPtr pReserved,
        [Out] out UInt32 negotiatedVersion,
        [Out] out IntPtr clientHandle
    );
 
    [DllImport("Wlanapi.dll")]
    public static extern uint WlanCloseHandle(
        [In] IntPtr ClientHandle,
        IntPtr pReserved
    );
 
    [DllImport("wlanapi.dll", SetLastError = true, CallingConvention=CallingConvention.Winapi)]
    public static extern uint WlanGetProfileList(
        [In] IntPtr clientHandle,
        [In, MarshalAs(UnmanagedType.LPStruct)] Guid interfaceGuid,
        [In] IntPtr pReserved,
        [Out] out IntPtr profileList
    );
 
    [DllImport("wlanapi.dll")]
    public static extern uint WlanGetProfile(
        [In]IntPtr clientHandle,
        [In, MarshalAs(UnmanagedType.LPStruct)] Guid interfaceGuid,
        [In, MarshalAs(UnmanagedType.LPWStr)] string profileName,
        [In, Out] IntPtr pReserved,
        [Out, MarshalAs(UnmanagedType.LPWStr)] out string pstrProfileXml,
        [In, Out, Optional] ref uint flags,
        [Out, Optional] out uint grantedAccess
    );
     
    [DllImport("wlanapi.dll")]
    public static extern uint WlanDeleteProfile(
        [In]IntPtr clientHanle,
        [In, MarshalAs(UnmanagedType.LPStruct)] Guid interfaceGuid,
        [In, MarshalAs(UnmanagedType.LPWStr)] string profileName,
        [In, Out] IntPtr pReserved
    );
 
    [DllImport("wlanapi.dll", EntryPoint = "WlanFreeMemory")]
    public static extern void WlanFreeMemory(
        [In] IntPtr pMemory
    );
 
    [DllImport("Wlanapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern uint WlanSetProfile(
        [In] IntPtr clientHanle,
        [In] ref Guid interfaceGuid,
        [In] uint flags,
        [In] IntPtr ProfileXml,
        [In, Optional] IntPtr AllUserProfileSecurity,
        [In] bool Overwrite,
        [In, Out] IntPtr pReserved,
        [In, Out]ref IntPtr pdwReasonCode
    );
 
    [DllImport("wlanapi.dll",SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern uint WlanReasonCodeToString(
        [In] uint reasonCode,
        [In] uint bufferSize,
        [In, Out] StringBuilder builder,
        [In, Out] IntPtr Reserved
    );
 
    [DllImport("Wlanapi.dll", SetLastError = true)]
    public static extern uint WlanGetAvailableNetworkList(
        [In] IntPtr hClientHandle,
        [In, MarshalAs(UnmanagedType.LPStruct)] Guid interfaceGuid,
        [In] uint dwFlags,
        [In] IntPtr pReserved,
        [Out] out IntPtr ppAvailableNetworkList
    );
 
    [DllImport("Wlanapi.dll", SetLastError = true)]
    public static extern uint WlanConnect(
        [In] IntPtr hClientHandle,
        [In] ref Guid interfaceGuid,
        [In] ref WLAN_CONNECTION_PARAMETERS pConnectionParameters,
        [In, Out] IntPtr pReserved
    );
 
    [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]
    public struct WLAN_CONNECTION_PARAMETERS
    {
        public WLAN_CONNECTION_MODE wlanConnectionMode;
        public string strProfile;
        public DOT11_SSID[] pDot11Ssid;  
        public DOT11_BSSID_LIST[] pDesiredBssidList;   
        public DOT11_BSS_TYPE dot11BssType;  
        public uint dwFlags; 
    }
 
    public struct DOT11_BSSID_LIST
    {
        public NDIS_OBJECT_HEADER Header;
        public ulong uNumOfEntries;
        public ulong uTotalNumOfEntries;
        public IntPtr BSSIDs;
    }
 
    public struct NDIS_OBJECT_HEADER
    {
        public byte Type;
        public byte Revision;
        public ushort Size;
    }
 
    public struct WLAN_PROFILE_INFO_LIST
    {
        public uint dwNumberOfItems;
        public uint dwIndex;
        public WLAN_PROFILE_INFO[] ProfileInfo;
 
        public WLAN_PROFILE_INFO_LIST(IntPtr ppProfileList)
        {
            dwNumberOfItems = (uint)Marshal.ReadInt32(ppProfileList);
            dwIndex = (uint)Marshal.ReadInt32(ppProfileList, 4);
            ProfileInfo = new WLAN_PROFILE_INFO[dwNumberOfItems];
            IntPtr ppProfileListTemp = new IntPtr(ppProfileList.ToInt64() + 8);
 
            for (int i = 0; i < dwNumberOfItems; i++)
            {
                ppProfileList = new IntPtr(ppProfileListTemp.ToInt64() + i * Marshal.SizeOf(typeof(WLAN_PROFILE_INFO)));
                ProfileInfo[i] = (WLAN_PROFILE_INFO)Marshal.PtrToStructure(ppProfileList, typeof(WLAN_PROFILE_INFO));
            }
        }
    }
 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct WLAN_PROFILE_INFO
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public string strProfileName;
        public WlanProfileFlags ProfileFLags;
    }
 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct WLAN_AVAILABLE_NETWORK_LIST
    {
        public uint dwNumberOfItems;
        public uint dwIndex;
        public WLAN_AVAILABLE_NETWORK[] wlanAvailableNetwork;
        public WLAN_AVAILABLE_NETWORK_LIST(IntPtr ppAvailableNetworkList)
        {
            dwNumberOfItems = (uint)Marshal.ReadInt64 (ppAvailableNetworkList);
            dwIndex = (uint)Marshal.ReadInt64 (ppAvailableNetworkList, 4);
            wlanAvailableNetwork = new WLAN_AVAILABLE_NETWORK[dwNumberOfItems];
            for (int i = 0; i < dwNumberOfItems; i++)
            {
                IntPtr pWlanAvailableNetwork = new IntPtr (ppAvailableNetworkList.ToInt64() + i * Marshal.SizeOf (typeof(WLAN_AVAILABLE_NETWORK)) + 8);
                wlanAvailableNetwork[i] = (WLAN_AVAILABLE_NETWORK)Marshal.PtrToStructure (pWlanAvailableNetwork, typeof(WLAN_AVAILABLE_NETWORK));
            }
        }
    }
 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]     
    public struct WLAN_AVAILABLE_NETWORK
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public string ProfileName;
        public DOT11_SSID Dot11Ssid;
        public DOT11_BSS_TYPE dot11BssType;
        public uint uNumberOfBssids;
        public bool bNetworkConnectable;
        public uint wlanNotConnectableReason;
        public uint uNumberOfPhyTypes;
 
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public DOT11_PHY_TYPE[] dot11PhyTypes;
        public bool bMorePhyTypes;
        public uint SignalQuality;
        public bool SecurityEnabled;
        public DOT11_AUTH_ALGORITHM dot11DefaultAuthAlgorithm;
        public DOT11_CIPHER_ALGORITHM dot11DefaultCipherAlgorithm;
        public uint dwFlags;
        public uint dwReserved;
    }
 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct DOT11_SSID
    {
        public uint uSSIDLength;
        
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string ucSSID;
    }
 
    public enum DOT11_BSS_TYPE
    {
        dot11_BSS_type_infrastructure = 1,
        dot11_BSS_type_independent = 2,
        dot11_BSS_type_any = 3,
    }
 
    public enum DOT11_PHY_TYPE
    {
        dot11_phy_type_unknown = 0,
        dot11_phy_type_any = 0,
        dot11_phy_type_fhss = 1,
        dot11_phy_type_dsss = 2,
        dot11_phy_type_irbaseband = 3,
        dot11_phy_type_ofdm = 4,
        dot11_phy_type_hrdsss = 5,
        dot11_phy_type_erp = 6,
        dot11_phy_type_ht = 7,
        dot11_phy_type_vht = 8,
        dot11_phy_type_IHV_start = -2147483648,
        dot11_phy_type_IHV_end = -1,
    }
 
    public enum DOT11_AUTH_ALGORITHM
    {
        DOT11_AUTH_ALGO_80211_OPEN = 1,
        DOT11_AUTH_ALGO_80211_SHARED_KEY = 2,
        DOT11_AUTH_ALGO_WPA = 3,
        DOT11_AUTH_ALGO_WPA_PSK = 4,
        DOT11_AUTH_ALGO_WPA_NONE = 5,
        DOT11_AUTH_ALGO_RSNA = 6,
        DOT11_AUTH_ALGO_RSNA_PSK = 7,
        DOT11_AUTH_ALGO_IHV_START = -2147483648,
        DOT11_AUTH_ALGO_IHV_END = -1,
    }
 
    public enum DOT11_CIPHER_ALGORITHM
    {
        /// DOT11_CIPHER_ALGO_NONE -> 0x00
        DOT11_CIPHER_ALGO_NONE = 0,
 
        /// DOT11_CIPHER_ALGO_WEP40 -> 0x01
        DOT11_CIPHER_ALGO_WEP40 = 1,
 
        /// DOT11_CIPHER_ALGO_TKIP -> 0x02
        DOT11_CIPHER_ALGO_TKIP = 2,
 
        /// DOT11_CIPHER_ALGO_CCMP -> 0x04
        DOT11_CIPHER_ALGO_CCMP = 4,
 
        /// DOT11_CIPHER_ALGO_WEP104 -> 0x05
        DOT11_CIPHER_ALGO_WEP104 = 5,
 
        /// DOT11_CIPHER_ALGO_WPA_USE_GROUP -> 0x100
        DOT11_CIPHER_ALGO_WPA_USE_GROUP = 256,
 
        /// DOT11_CIPHER_ALGO_RSN_USE_GROUP -> 0x100
        DOT11_CIPHER_ALGO_RSN_USE_GROUP = 256,
 
        /// DOT11_CIPHER_ALGO_WEP -> 0x101
        DOT11_CIPHER_ALGO_WEP = 257,
 
        /// DOT11_CIPHER_ALGO_IHV_START -> 0x80000000
        DOT11_CIPHER_ALGO_IHV_START = -2147483648,
 
        /// DOT11_CIPHER_ALGO_IHV_END -> 0xffffffff
        DOT11_CIPHER_ALGO_IHV_END = -1,
    }
 
    public enum WLAN_CONNECTION_MODE
    {
        wlan_connection_mode_profile,
        wlan_connection_mode_temporary_profile,
        wlan_connection_mode_discovery_secure,
        wlan_connection_mode_discovery_unsecure,
        wlan_connection_mode_auto,
        wlan_connection_mode_invalid,
    };
 
    [Flags]
    public enum WlanProfileFlags
    {
        AllUser = 0,
        GroupPolicy = 1,
        User = 2
    }
 
    public class ProfileInfo
    {
        public string ProfileName;
        public string ConnectionMode;
        public string Authentication;
        public string Encryption;
        public string Password;
        public string Xml;
    }
'@


Add-Type -MemberDefinition $WlanGetProfileListSig -Name ProfileManagement -Namespace WiFi -Using System.Text -PassThru