NetworkProfile.psm1

#Region '.\Private\Convert-NetworkProfileTimestamp.ps1' -1

Function Convert-NetworkProfileTimestamp {
    <#
    .SYNOPSIS
    Convert binary time data from Network Profile registry keys to datetime object
    .DESCRIPTION
    Network Profiles are stored in the registry and two timestamp values stored in binary. This function will convert those timestamps to a datetime object.
    .PARAMETER RegTimeStamp
    The binary array representing a timestamp
    .EXAMPLE
    Convert-NetworkProfileTimestamp -RegTimeStamp $Profile.GetValue("DateCreated")
    #>

    Param (
        [Byte[]]$RegTimeStamp
    )

    $First = 1
    $Second = 0
    $Values = while ($First -lt 15) {
        if ($First -eq 5) {
            #the bytes in the 4th and 5th are the day of the week which we don't need
        } else {
            [uint32]$('0x{0:x}{1:x}' -f $RegTimeStamp[$First], $RegTimeStamp[$Second])
        }
        $First+=2
        $Second+=2
    }
    New-Object Datetime ($Values)
}
#EndRegion '.\Private\Convert-NetworkProfileTimestamp.ps1' 29
#Region '.\Public\Get-NetworkProfile.ps1' -1

Function Get-NetworkProfile {
    <#
    .SYNOPSIS
    Function to return network profiles from registry as Powershell objects
    .DESCRIPTION
    Query the Local Machine registry hive for current network profiles and return them as Powershell objects. Requires administrative privilege to read the hive.
    .PARAMETER ProfileName
    Return a specific network profile by name. Uses regex for matching.
    .PARAMETER GUID
    Return a specific network profile by GUID. If you run Get-NetworkProfile with no arguments, the returned objects have a property called 'GUID' that's not shown in the table format view.
    Either pipe the output to `select *` or `format-list` to view the GUIDs. Can also be seen if capturing the output in a variable and then calling the property.
    .EXAMPLE
    PS> Get-NetworkProfile
 
    ProfileName Description Managed Category DateCreated NameType DateLastConnected
    ----------- ----------- ------- -------- ----------- -------- -----------------
    PSHSummit PSHSummit No Public 4/8/2024 8:58:09 AM Wireless Network 4/10/2024 12:58:16 PM
    Gizmo Network No Public 7/16/2024 3:23:27 PM Wireless Network 7/16/2024 4:09:02 PM
    contoso contoso.lcl Yes Domain 1/31/2024 5:28:46 PM Wired Network 7/16/2024 3:25:07 PM
 
    # with no arguments it returns all network profiles found in the registry
    .EXAMPLE
    PS> $Profile = Get-NetworkProfile -ProfileName PSHSummit
    PS> $Profile | Format-List
     
    ProfileName : PSHSummit
    Description : PSHSummit
    Managed : No
    Category : Public
    DateCreated : 4/8/2024 8:58:09 AM
    NameType : Wireless Network
    DateLastConnected : 4/10/2024 12:58:16 PM
    GUID : 4b2c4e83-90ca-4aa4-a321-2a7b08d3d669
     
    # now with the GUID property we can use it to retrieve that specific profile.
    PS> Get-NetworkProfile -GUID 4b2c4e83-90ca-4aa4-a321-2a7b08d3d669
 
    ProfileName Description Managed Category DateCreated NameType DateLastConnected
    ----------- ----------- ------- -------- ----------- -------- -----------------
    PSHSummit PSHSummit No Public 4/8/2024 8:58:09 AM Wireless Network 4/10/2024 12:58:16 PM
    #>

    #Requires -RunAsAdministrator
    [CmdletBinding(DefaultParameterSetName="none")]
    Param (
        [Parameter(Mandatory=$false,Position=0,ParameterSetName="ProfileName")]
        [Alias("Name")]
        [Regex]$ProfileName,
        [Parameter(Mandatory=$false,Position=1,ParameterSetName="GUID")]
        [Guid]$GUID
    )

    $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles"

    $RegProfiles = switch ($PSCmdlet.ParameterSetName) {
        "ProfileName" {
            try {
                Get-ChildItem $RegPath -ErrorAction Stop | Where-Object {
                    $_.GetValue("ProfileName") -match $ProfileName.ToString()
                }
            } catch {
                throw $Error[0]
            }
        }
        "GUID" {
            try {
                $ProfilePath = Join-Path -Path $RegPath -ChildPath "{$($GUID.ToString())}"
                if (Test-Path $ProfilePath) {
                   Get-Item -Path $ProfilePath 
                } else {
                    Write-Warning "No network profile found matching GUID: {$($GUID.ToString())}"
                }
            } catch {
                throw $Error[0]
            }
        }
        "none" {
            try {
                Get-ChildItem $RegPath -ErrorAction Stop
            } catch {
                throw $Error[0]
            }
        }
    }

    Foreach ($Profile in $RegProfiles) {
        $Managed = Get-ItemPropertyValue -Path $(Join-Path -Path $RegPath -ChildPath $Profile.PSChildName) -Name "Managed" | Foreach-Object {
            if ($_ -eq 1) {
                "Yes"
            } else {
                "No"
            }
        }
        $Category = Get-ItemPropertyValue -Path $(Join-Path -Path $RegPath -ChildPath $Profile.PSChildName) -Name "Category" | Foreach-Object {
            switch ($_) {
                0 {"Public"}
                1 {"Private"}
                2 {"Domain"}
            }
        }
        $DateCreated = Convert-NetworkProfileTimestamp -RegTimeStamp $Profile.GetValue("DateCreated")
        $NameTypeValue = Get-ItemPropertyValue -Path $(Join-Path -Path $RegPath -ChildPath $Profile.PSChildName) -Name "NameType" | Foreach-Object {
            switch ($_) {
                6  {"Wired Network"}
                23  {"VPN"}
                53 {"VPN"}
                71  {"Wireless Network"}
                243  {"Mobile Broadband"}
            }
        }
        $DateLastConnected = Convert-NetworkProfileTimestamp -RegTimeStamp $Profile.GetValue("DateLastConnected")
        [PSCustomObject]@{
            PSTypeName          = "NetworkProfile"
            ProfileName         = $Profile.GetValue("ProfileName")
            Description         = $Profile.GetValue("Description")
            Managed             = $Managed
            Category            = $Category
            DateCreated         = $DateCreated
            NameType            = $NameTypeValue
            DateLastConnected   = $DateLastConnected
            GUID                = [GUID]$Profile.PSChildName
        }
    }
}
#EndRegion '.\Public\Get-NetworkProfile.ps1' 124
#Region '.\Public\Remove-NetworkProfile.ps1' -1

Function Remove-NetworkProfile {
    <#
    .SYNOPSIS
    Function to change the name, description or category of existing network profiles in registry
    .DESCRIPTION
    Function takes the unique ProfileName, GUID, or pipeline input of an existing network profile from registry and allows for updating the description, name and/or category of that profile.
    .PARAMETER ProfileName
    ProfileName to target for updating. Accepts pipeline input.
    .PARAMETER GUID
    Specify the GUID without braces for the network profile. Accepts pipeline input from Get-NetworkProfile
    .EXAMPLE
    PS> Get-networkprofile -ProfileName PSHSummit | Remove-NetworkProfile
 
    Confirm
    Are you sure you want to perform this action?
    Performing the operation "Remove-Item" on target "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles\{4b2c4e83-90ca-4aa4-a321-2a7b08d3d669}".
    [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): y
    #>

    #Requires -RunAsAdministrator
    [CmdletBinding(DefaultParameterSetName="ProfileName",SupportsShouldProcess,ConfirmImpact="High")]
    Param (
        [Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ProfileName")]
        [Alias("Name")]
        [Regex]$ProfileName,
        [Parameter(Mandatory=$false,Position=1,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="GUID")]
        [guid]$GUID
    )

    begin {
        $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles"
    }

    process {
        switch ($PSBoundParameters.Keys) {
            "GUID" {
                $ProfilePath = Join-Path -Path $RegPath -ChildPath "{$($GUID.ToString())}"
                if (Test-Path $ProfilePath) {
                    $NetworkProfile = Get-NetworkProfile -GUID $GUID
                } else {
                    Write-Warning "No network profile with GUID $GUID found"
                }
            }
            "ProfileName" {
                $NetworkProfile = Get-NetworkProfile -ProfileName $ProfileName
                $ProfilePath = Join-Path -Path $RegPath -ChildPath "{$($NetworkProfile.GUID)}"
                if ($NetworkProfile.count -gt 1) {
                    Write-Warning "Multiple network profiles match the name $ProfileName . Please use the -GUID parameter to specify a single network profile or find a more specific name."
                    $NetworkProfile = $null
                } elseif ($null -eq $NetworkProfile) {
                    Write-Warning "No network profile with name $ProfileName found"
                }                
            }
        }  
        
        if ($NetworkProfile) {
            Write-Verbose "Removing network profile: $($NetworkProfile.ProfileName) / $($NetworkProfile.GUID.ToString())"
            if ($PSCmdlet.ShouldProcess($ProfilePath,'Remove-Item')) {
                try {
                    Remove-Item -Path $ProfilePath
                } catch {
                    $Error[0]
                }
            }
        }
    }

    end {}
}
#EndRegion '.\Public\Remove-NetworkProfile.ps1' 69
#Region '.\Public\Set-NetworkProfile.ps1' -1

Function Set-NetworkProfile {
    <#
    .SYNOPSIS
    Function to change the name, description or category of existing network profiles in registry
    .DESCRIPTION
    Function takes the unique ProfileName, GUID, or pipeline input of an existing network profile from registry and allows for updating the description, name and/or category of that profile.
    .PARAMETER ProfileName
    ProfileName to target for updating. Accepts pipeline input.
    .PARAMETER GUID
    Specify the GUID without braces for the network profile. Accepts pipeline input from Get-NetworkProfile
    .PARAMETER NewProfileName
    Specify the new profile name to change the network profile to
    .PARAMETER Description
    Change the description text for the network profile
    .PARAMETER Category
    Change the category for the network profile. Options are Private, Public or Domain
    .EXAMPLE
    PS$> Get-NetworkProfile -ProfileName PSHSummit
 
    ProfileName Description Managed Category DateCreated NameType DateLastConnected
    ----------- ----------- ------- -------- ----------- -------- -----------------
    PSHSummit PSHSummit No Public 4/8/2024 8:58:09 AM Wireless Network 4/10/2024 12:58:16 PM
     
    PS$> Get-NetworkProfile -ProfileName PSHSummit | Set-NetworkProfile -Description "Powershell Rocks" -Category "Private"
    PS$> Get-NetworkProfile -ProfileName PSHSummit
 
    ProfileName Description Managed Category DateCreated NameType DateLastConnected
    ----------- ----------- ------- -------- ----------- -------- -----------------
    PSHSummit Powershell Rocks No Private 4/8/2024 8:58:09 AM Wireless Network 4/10/2024 12:58:16 PM
    #>

    #Requires -RunAsAdministrator
    [CmdletBinding(DefaultParameterSetName="ProfileName")]
    Param (
        [Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="ProfileName")]
        [Alias("Name")]
        [Regex]$ProfileName,
        [Parameter(Mandatory=$false,Position=1,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,ParameterSetName="GUID")]
        [guid]$GUID,
        [Parameter(ParameterSetName="ProfileName")]
        [Parameter(ParameterSetName="GUID")]
        [String]$NewProfileName,
        [Parameter(ParameterSetName="ProfileName")]
        [Parameter(ParameterSetName="GUID")]
        [String]$Description,
        [Parameter(ParameterSetName="ProfileName")]
        [Parameter(ParameterSetName="GUID")]
        [ValidateSet("Private","Public","Domain")]
        [String]$Category
    )

    begin {
        $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles"
    }

    process {
        switch ($PSBoundParameters.Keys) {
            "GUID" {
                $ProfilePath = Join-Path -Path $RegPath -ChildPath "{$($GUID.ToString())}"
                if (Test-Path $ProfilePath) {
                    $NetworkProfile = Get-NetworkProfile -GUID $GUID
                } else {
                    Write-Warning "No network profile with GUID $GUID found"
                }
            }
            "ProfileName" {
                $NetworkProfile = Get-NetworkProfile -ProfileName $ProfileName
                $ProfilePath = Join-Path -Path $RegPath -ChildPath "{$($NetworkProfile.GUID)}"
                if ($NetworkProfile.count -gt 1) {
                    Write-Warning "Multiple network profiles match the name $ProfileName . Please use the -GUID parameter to specify a single network profile or find a more specific name."
                    $NetworkProfile = $null
                } elseif ($null -eq $NetworkProfile) {
                    Write-Warning "No network profile with name $ProfileName found"
                }                
            }
        }  
        
        if ($NetworkProfile) {
            Write-Verbose "Updating properties on ProfileName: $($NetworkProfile.ProfileName)"
            $ValuesToSet = switch ($PSBoundParameters.Keys) {
                "NewProfileName" {
                    [PSCustomObject]@{
                        Name = "ProfileName"
                        Value = $NewProfileName
                    }
                }
                "Description" {
                    [PSCustomObject]@{
                        Name = "Description"
                        Value = $Description
                    }
                }
                "Category" {
                    [PSCustomObject]@{
                        Name = "Category"
                        Value = switch ($Category) {
                            "Public" {0}
                            "Private" {1}
                            "Domain" {2}
                        }
                    }
                }
            }

            try {
                $ValuesToSet | Set-ItemProperty -Path $ProfilePath -Name {$_.Name} -ErrorAction Stop
            } catch {
                throw $Error[0]
            }
        }
    }

    end {}
}
#EndRegion '.\Public\Set-NetworkProfile.ps1' 114