SCONFIG.ps1

# Script Name: SCONFIG.ps1
# Current Version: 1.8
# Written By: Peter Remstad
# Date Created: 2018-03-28
# Date Revised: 2020-01-02
#
# Notes: v1.0 - Feature complete when comparing to old sconfig.vbs that ships with Windows
# Server.
# v1.1 - Improvement: Updated input text for options 1-7 to be more consistent
# v1.2 - Set ideal buffer size for script. Prevents awkward text wrapping.
# v1.3 - Re-ordered main menu options to a more logical order. Add in two options
# which will be developed soon.
# v1.4 - Firewall toggling added.
# v1.5 - Windows Defender toggling added.
# v1.6 - NIC Teaming configurations added, updated network config to handle teaming.
# v1.7 - Bug fixes
# v1.8 - Added requirement for Computer renaming, name may not consist of only
# digits. Update sc_Set-Domain function to be consistent with new Computer
# naming error and change where an error returns the prompt.
#
############################################################################################

<#PSScriptInfo
 
.VERSION 1.8
 
.GUID 465df723-0dac-4bed-95f6-8a403596fe74
 
.AUTHOR Peter Remstad
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS SCONFIG Configuration Server
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
#>


<#
 
.DESCRIPTION
 Provides SCONFIG functionality through Powershell, cleans up user interface, adds additional functionality from built-in Microsoft SCONFIG.vbs. Script operates correctly on Windows Server 2016 and newer server operating systems.
 
#>
 
Param()

###################################################### EXECUTE SYSTEM INFO QUERY #######################################################
function sc_Create-MainMenu (

)
{
    # RESETS ALL VARIABLES FOR FUNCTION
    $ErrorActionPreference = "SilentlyContinue"
    $Domain = $null
    $CompSys = $null
    $Remote = $null
    $AU = $null
    $Update = $null
    $TSConnect = $null
    $UserAuth = $null
    $RDP = $null
    $TelReg = $null
    $Telem = $null
    $TimeZone = $null
    $ConProf = $null
    $FWStatus = $null
    $Firewall = $null

    Write-Host -ForegroundColor Cyan "Gathing information..."

    # GATHERS ALL DATA
    $CompSys = Get-WmiObject -Class Win32_ComputerSystem
    $Remote = Configure-SMRemoting.exe -Get
    $AU = Get-ItemProperty -Path "HKLM:\\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU"
    $NoAU = $AU.NoAutoUpdate
    $AU = $AU.AUOptions
    $TSConnect = (Get-ItemProperty -Path "HKLM:\\SYSTEM\CurrentControlSet\Control\Terminal Server").fDenyTSConnections
    $UserAuth = (Get-ItemProperty -Path "HKLM:\\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-TCP").UserAuthentication
    $TelReg = (Get-ItemProperty -Path "HKLM:\\SOFTWARE\Policies\Microsoft\Windows\DataCollection").AllowTelemetry
    $TimeZone = Get-TimeZone | Select -Property DisplayName

    # GETS LOCAL TELEMETRY SETTING IF GROUP POLICY SETTING DOESN'T EXIST/APPLY
    If ($TelReg -eq $null) {
        $TelReg = (Get-ItemProperty -Path "HKLM:\\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection").AllowTelemetry
    }

    # MANIPULATES DATA FOR DOMAIN
    If (($CompSys.DomainRole -eq 0) -or ($CompSys.DomainRole -eq 2)) {
        $Domain = "Workgroup: $($CompSys.Domain)"
    } ElseIf (($CompSys.DomainRole -eq 1) -or ($CompSys.DomainRole -eq 3) -or ($CompSys.DomainRole -eq 4) -or ($CompSys.DomainRole -eq 5)) {
        $Domain = "Domain: $($CompSys.Domain)"
    }

    # PROVIDES OUTPUT IF QUERY FAILED FOR REMOTE MANAGEMENT SETTINGS
    If ($Remote -eq $null) {
        $Remote = "Failed query"
    } ElseIf ($Remote -match "disabled") {
        $Remote = "Disabled"
    } ElseIf ($Remote -match "enabled") {
        $Remote = "Enabled"
    }

    # TRANSLATES REGISTRY FOR WINDOWS UPDATE TO USER FRIENDLY OUTPUT
    Switch ($AU) {
        $null {If ($NoAU -eq 1) {$Update = "Manual"} ElseIf ($NoAU -eq $null) {$Update = "Failed Query"} ; break}
        1 {$Update = "Never check for updates" ; break}
        2 {$Update = "Notify before download" ; break}
        3 {$Update = "DownloadOnly" ; break}
        4 {$Update = "Automatic" ; break}
    }

    # TRANSLATES REGISTRY FOR RDP CONFIG TO USER FRIENDLY OUTPUT
    Switch ($TSConnect) {
        $null {$RDP = "Failed Query" ; break}
        0 {If ($UserAuth -eq 0) {$RDP = "Enabled (all clients)"} ElseIf ($UserAuth -eq 1) {$RDP = "Enabled (more secure clients only)"} Else {$RDP = "Failed Query"} ; break}
        1 {$RDP = "Disabled" ; break}
    }

    # TRANSLATES TELEMETRY SETTINGS TO USER FRIENDLY OUTPUT
    Switch ($TelReg) {
        $null {$Telem = "Failed Query" ; break}
        0 {$Telem = "Security" ; break}
        1 {$Telem = "Basic" ; break}
        2 {$Telem = "Enhanced" ; break}
        3 {$Telem = "Full" ; break}
    }

    # GATHERS CONNECTED NETWORK PROFILES
    $ConProf = Get-NetConnectionProfile
    $ConProf = $ConProf.NetworkCategory | Select -Unique

    # GATHERS THE FIREWALL STATUS OF ALL CONNECTED FIREWALL PROFILES
    If ($ConProf.count -eq 1) {

        # MODIFIES CONNECTED PROFILE TO USABLE VALUE
        If ($ConProf -eq "DomainAuthenticated") {
            $ConProf = "Domain"
        }

        # GATHERS ASSOCIATED FIREWALL PROFILE
        $FWStatus = (Get-NetFirewallProfile -Name $ConProf).Enabled

        # TRANSLATES STATUS
        Switch ($FWStatus) {
            $true {$FWStatus = "Enabled" ; break}
            $false {$FWStatus = "Disabled" ; break}
        }

        # GENERATES STRING
        $Firewall = "$ConProf`: $FWStatus"
    } Else {
        Foreach ($Prof in $ConProf) {

            # MODIFIES CONNECTED PROFILE TO USABLE VALUE
            If ($Prof -eq "DomainAuthenticated") {
                $Prof = "Domain"
            }

            # GATHERS ASSOCIATED FIREWALL PROFILE
            $FWStatus = (Get-NetFirewallProfile -Name $ConProf).Enabled
            Switch ($FWStatus) {
                $true {$FWStatus = "Enabled" ; break}
                $false {$FWStatus = "Disabled" ; break}
            }

            # GENERATES STRING
            $Firewall += "$Prof`: $FWStatus "
        }
    }

    $TextArray = @()

    $TextArray += New-Object -TypeName psobject -Property @{Item = "1) Domain/Workgroup:"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "$Domain"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "2) Computer Name:"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "$($CompSys.PSComputerName)"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "3) Add Local Administrator"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "4) Date and Time:"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "$($TimeZone.DisplayName)"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "5) Network Settings"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "6) NIC Teaming"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "7) Firewall Settings:"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "$Firewall"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "8) Telemetry Settings:"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "$Telem"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "9) Windows Activation"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "10) Windows Defender"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "11) Configure Remote Management:"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "$Remote"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "12) Remote Desktop:"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "$RDP"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "13) Windows Update Settings:"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "$Update"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "14) Download and Install Updates"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "15) Log Off User"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "16) Restart Server"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "17) Shut Down Server"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}
    $TextArray += New-Object -TypeName psobject -Property @{Item = "18) Exit to Command Line"}
    $TextArray += New-Object -TypeName psobject -Property @{Item = ""}

    # GENERATES OUTPUT TEXT
    $OutputText = "
 
====================================================================================
                                Server Configuration
===================================================================================="


    # RETURNS TEXT DATA
    Write-Output $OutputText
    $TextArray | Format-Wide -Property Item -Column 2

    # DEFINES VALID OPTIONS
    $ValidInput = @(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18)

    # GATHERS SELECTED OPTION
    [int]$Choice = Read-Host "Enter number to select an option"

    # VALIDATES SELECTED OPTION ; RETURNS TO MAIN MENU ON BAD INPUT
    If ($ValidInput -notcontains $Choice) {
        Write-Host -ForegroundColor Yellow "Invalid input, returning to main menu..."

        Start-Sleep -Seconds 1

        sc_Create-MainMenu
    }

    # EXECUTES SELECTED OPTION
    Switch ($Choice) {

        1 {sc_Set-Domain ; break}
        2 {sc_Set-ComputerName ; break}
        3 {sc_Add-LocalAdmin ; break}
        4 {sc_Set-DateTime ; break}
        5 {sc_Set-Network ; break}
        6 {sc_Config-NICTeaming ; break}
        7 {sc_Set-Firewall ; break}
        8 {sc_Set-Telemetry ; break}
        9 {sc_Set-WinAct ; break}
        10 {sc_Set-WinDefend ; break}
        11 {sc_Set-RemoteMgmt ; break}
        12 {sc_Set-RDP ; break}
        13 {sc_Set-WindowsUpdate ; break}
        14 {sc_Execute-WindowsUpdate ; break}
        15 {sc_Logoff ; break}
        16 {sc_Restart ; break}
        17 {sc_Shutdown ; break}
        18 {sc_Exit ; break}
    }
}

######################################################## CHANGE DOMAIN/WORKGROUP #######################################################
function sc_Set-Domain (

)
{
    # RESETS VARIABLES FOR FUNCTION
    $DomOrWork = $null
    $DWname = $null
    $NewName = $null
    $ValidDW = $null
    $OutputText = $null

    # EXECUTES DOMAIN JOIN
    function sc_Join-Domain (
        [parameter(Mandatory=$true)]$DName
    )
    {
        # RESETS VARIABLES FOR FUNCTION
        $DCred = $null

        # DEFINES VALID COMPUTER CHARCATERS
        $Characters = "[][\\/;:*?`"`'<>|,~!@#$%^&.(){}_``=+ ]"

        # GETS CREDENTIALS AND NEW NAME
        $DCred = Get-Credential -Message "Specify an authorized domain\user"

        # GATHERS INPUT
        $NewName = $null
        $NewName = Read-Host "Enter new name for this computer (Blank = keep current name)"

        # THROWS ERROR MESSAGE AND RETURNS TO SET DOMAIN MENU
        If ($NewName -match $Characters) {
            Write-Host -ForegroundColor Red "Invalid characters used. The following characters are illegal:"
            Write-Host -ForegroundColor Yellow "$Characters"
            Write-Host -ForegroundColor Yellow "Returning to Set Domain menu..."

            Start-Sleep -Seconds 2

            sc_Set-Domain
        }

        # THROWS ERROR MESSAGE AND RETURNS TO SET DOMAIN MENU
        If ($NewName.Length -ge 16) {
            Write-Host -ForegroundColor Red "Name is too long. A valid name must be 15 characters or shorter."
            Write-Host -ForegroundColor Yellow "Returning to Set Domain menu..."

            Start-Sleep 2

            sc_Set-Domain
        }

        # THROWS ERROR MESSAGE AND RETURNS TO SET DOMAIN MENU
        If ($NewName -match "^\d+$") {
            Write-Host -ForegroundColor Red "Name may not contain only digits"
            Write-Host -ForegroundColor Yellow "Returning to Set Domain menu..."

            Start-Sleep -Seconds 2

            sc_Set-Domain
        }

        # EXECUTES DOMAIN JOIN
        If ($NewName -eq "") {
            Add-Computer -DomainName $DName -Credential $DCred
            sc_Create-MainMenu
        } Else {
            Add-Computer -DomainName $DName -NewName $NewName -Credential $DCred
            sc_Create-MainMenu
        }
    }

    # EXECUTES WORKGROUP JOIN
    function sc_Join-Workgroup (
        [parameter(Mandatory=$true)]$WName
    )
    {
        # RESETS VARIABLES FOR FUNCTION
        $DCred = $null
        $DCheck = $null
        $NewName = $null

        # CHECKS IF CURRENTLY IN A DOMAIN AND GETS NEW NAME
        $DCheck = Get-WmiObject -Class Win32_ComputerSystem

        # DEFINES VALID COMPUTER CHARCATERS
        $Characters = "[][\\/;:*?`"`'<>|,~!@#$%^&.(){}_``=+ ]"

        # GATHERS INPUT
        $NewName = $null
        $NewName = Read-Host "Enter new name for this computer (Blank = keep current name)"

        # THROWS ERROR MESSAGE AND RETURNS TO SET DOMAIN MENU
        If ($NewName -match $Characters) {
            Write-Host -ForegroundColor Red "Invalid characters used. The following characters are illegal:"
            Write-Host -ForegroundColor Yellow "$Characters"
            Write-Host -ForegroundColor Yellow "Returning to Set Domain menu..."

            Start-Sleep -Seconds 2

            sc_Set-Domain
        }

        # THROWS ERROR MESSAGE AND RETURNS TO SET DOMAIN MENU
        If ($NewName.Length -ge 16) {
            Write-Host -ForegroundColor Red "Name is too long. A valid name must be 15 characters or shorter."
            Write-Host -ForegroundColor Yellow "Returning to Set Domain menu..."

            Start-Sleep 2

            sc_Set-Domain
        }

        # THROWS ERROR MESSAGE AND RETURNS TO SET DOMAIN MENU
        If ($NewName -match "^\d+$") {
            Write-Host -ForegroundColor Red "Name may not contain only digits"
            Write-Host -ForegroundColor Yellow "Returning to Set Domain menu..."

            Start-Sleep -Seconds 2

            sc_Set-Domain
        }

        # IF IN A DOMAIN, GATHERS CREDS ; EXECUTES WORKGROUP JOIN
        If (($DCheck.DomainRole -ne 0) -and ($DCheck.DomainRole -ne 2)) {
            $DCred = Get-Credential -Message "Specify credentials to unjoin domain"
            If ($NewName -eq "") {
                Add-Computer -DomainName $WName -Credential $DCred
                sc_Create-MainMenu
            } Else {
                Add-Computer -DomainName $WName -NewName $NewName -Credential $DCred
                sc_Create-MainMenu
            }
        } Else {
            If ($NewName -eq "") {
                Add-Computer -DomainName $WName
                sc_Create-MainMenu
            } Else {
                Add-Computer -DomainName $WName -NewName $NewName
                sc_Create-MainMenu
            }
        }
    }

    $ValidDW = @(1,2,3)

    # GENERATES OUTPUT TEXT
    $OutputText = "
 
------ JOIN DOMAIN/WORKGROUP ------
 
1) Join Domain
2) Join Workgroup
 
3) Return to main menu
 
    "


    # RETURNS TEXT DATA
    Write-Output $OutputText

    # GATHERS OPTION UNTIL VALID CHOICE IS MADE
    Do {
        $DomOrWork = $null
        $DomOrWork = Read-Host "Enter selection"
    } While ($ValidDW -notcontains $DomOrWork)

    # EXECUTES SELECTED OPTION
    Switch ($DomOrWork) {
        1 {$DWname = Read-Host "Name of domain to join" ; sc_Join-Domain -DName $DWname ; break}
        2 {$DWname = Read-Host "Name of workgroup to join" ; sc_Join-Workgroup -WName $DWname ; break}
        3 {sc_Create-MainMenu ; break}
    }
}

########################################################## CHANGE COMPUTER NAME ########################################################
function sc_Set-ComputerName (

)
{
    # RESETS VARIABLES FOR FUNCTION
    $NewName = $null
    $DCheck = $null
    $Characters = $null

    # CHECKS IF CURRENTLY IN A DOMAIN AND GETS NEW NAME
    $DCheck = Get-WmiObject -Class Win32_ComputerSystem

    # DEFINES VALID COMPUTER CHARCATERS
    $Characters = "[][\\/;:*?`"`'<>|,~!@#$%^&.(){}_``=+ ]"

    # GATHERS INPUT
    $NewName = $null
    $NewName = Read-Host "Enter new computer name (Blank=Cancel)"

    # IF BLANK RETURNS TO MAIN MENU
    If ($NewName -eq "") {
        sc_Create-MainMenu
    }

    # THROWS ERROR MESSAGE AND RETURNS TO MAIN MENU
    If ($NewName -match $Characters) {
        Write-Host -ForegroundColor Red "Invalid characters used. The following characters are illegal:"
        Write-Host -ForegroundColor Red "$($Characters.Substring(1,32))"
        Write-Host -ForegroundColor Yellow "Returning to main menu..."

        Start-Sleep -Seconds 2

        sc_Create-MainMenu
    }

    # THROWS ERROR MESSAGE AND RETURNS TO MAIN MENU
    If ($NewName.Length -ge 16) {
        Write-Host -ForegroundColor Red "Name is too long. A valid name must be 15 characters or shorter."
        Write-Host -ForegroundColor Yellow "Returning to main menu..."

        Start-Sleep -Seconds 2

        sc_Create-MainMenu
    }

    # THROWS ERROR MESSAGE AND RETURNS TO MAIN MENU
    If ($NewName -match "^\d+$") {
        Write-Host -ForegroundColor Red "Name may not contain only digits"
        Write-Host -ForegroundColor Yellow "Returning to main menu..."

        Start-Sleep -Seconds 2

        sc_Create-MainMenu
    }

    # IF IN A DOMAIN, GATHERS CREDS ; CHANGES SYSTEM NAME
    If (($DCheck.DomainRole -ne 0) -and ($DCheck.DomainRole -ne 2)) {
        $DCred = Get-Credential -Message "Specify credentials to update computer object"
        Rename-Computer -NewName $NewName -DomainCredential $DCred
        sc_Create-MainMenu
    } Else {
        Rename-Computer -NewName $NewName
        sc_Create-MainMenu
    }
}

######################################################## ADD LOCAL ADMINISTRATOR #######################################################
function sc_Add-LocalAdmin (

)
{
    # RESETS VARIABLES FOR FUNCTION
    $CompSys = $null
    $LocAdmin = $null
    $LocUser = $null
    $Pass = $null
    $OutputText = $null
    $Characters = $null

    # GATHERS DATA
    $CompSys = Get-WmiObject -Class Win32_ComputerSystem

    # DEFINES VALID COMPUTER CHARCATERS
    $Characters = "[][\\/:*?`"<>|,;@]"

    # GENERATES OUTPUT TEXT
    $OutputText = "
 
In a domain environment, specify domain\username.
In a workgroup environment, specify username.
 
    "


    # RETURNS TEXT DATA
    Write-Output $OutputText

    # GATHERS ADMIN ACCOUNT NAME
    $LocAdmin = Read-Host "Enter account to join local Administrators group (Blank=Cancel)"

    # ADDS ACCOUNT TO LOCAL ADMIN GROUP ; WILL CREATE USER IF IN A WORKGROUP AND USER DOESN'T EXIST
    If ($LocAdmin -ne "") {
        # WORKGROUP/NON-DOMAIN PROCESS
        If (($CompSys.DomainRole -eq 0) -or ($CompSys.DomainRole -eq 2)) {

            # ERRORS IF INVALID CHARACTERS ARE USED
            If ($LocAdmin -match $Characters) {
                Write-Host -ForegroundColor Yellow "Invalid characters used. The following characters are illegal:"
                Write-Host -ForegroundColor Yellow "$($Characters.Substring(1,14))"
                Write-Host -ForegroundColor Yellow "Returning to main menu..."

                Start-Sleep -Seconds 2

                sc_Create-MainMenu
            }

            If ($LocAdmin.Length -ge 16) {
                Write-Host -ForegroundColor Yellow "Name is too long. A valid name must be 15 characters or shorter."
                Write-Host -ForegroundColor Yellow "Returning to main menu..."

                Start-Sleep -Seconds 2

                sc_Create-MainMenu
            }

            # CHECKS FOR USER ACCOUNT, CREATES IF MISSING, OTHERWISE ADDS TO ADMINISTRATORS
            $LocUser = Get-LocalUser -Name $LocAdmin -ErrorAction SilentlyContinue
            If ($LocUser -eq $null) {
                $Pass = Read-Host -AsSecureString "Enter password for user account"
                New-LocalUser -Name $LocAdmin -Password $Pass | Add-LocalGroupMember -Group Administrators

                sc_Create-MainMenu
            } Else {
                Add-LocalGroupMember -Group Administrators -Member $LocAdmin

                sc_Create-MainMenu
            }
        # DOMAIN PROCESS
        } Else {
            # VALIDATES A DOMAIN WAS PROVIDED
            If ($LocAdmin.Split('\\')[1] -eq $null) {
                Write-Host -ForegroundColor Yellow "Domain systems may only add domain accounts."
                Write-Host -ForegroundColor Yellow "No domain provide in input. Returning to main menu..."

                Start-Sleep -Seconds 1

                sc_Create-MainMenu
            }

            Add-LocalGroupMember -Group Administrators -Member $LocAdmin -Verbose

            sc_Create-MainMenu
        }
    } Else {
        sc_Create-MainMenu
    }
}

###################################################### CONFIGURE DATE AND TIME ######################################################
function sc_Set-DateTime (

)
{
    # EXECUTES TIME/DATE CPL
    timedate.cpl
    sc_Create-MainMenu
}

###################################################### CONFIGURE NETWORK SETTINGS ######################################################
function sc_Set-Network (

)
{
    # RESETS ALL VARIABLES FOR FUNCTION
    $AdapterArray = @()
    $NetAdapters = @()
    $NetChoice = $null
    $NetInput = $null
    $IP = $null

    # CONVERTS SUBNETS INTO PREFIXES AND PREFIXES INTO SUBNETS
    function sc_Convert-SubnetInfo (
        [parameter(Mandatory=$false)]$Sub,
        [parameter(Mandatory=$false)]$Pre
    )
    {
        # GENERATES OUTPUT TEXT
        [int]$cnt = 0
        [string]$OutArr = ""
        [string]$BinaryOctet = $null
        [string]$BinaryAddress = $null
        [string]$Subnet = $null
        [string]$Prefix = $null

        # EXECUTES IF SUB WAS INPUTTED
        If ($Sub -ne $null) {

            # PROCESSES EACH OCTET SEPARATELY
            $Sub.Split('.') | Foreach {
                $BinaryOctet = [convert]::ToString($_,2)

                # IF OCTET IS 0, CREATES 8-BITS OF 0
                If ($BinaryOctet -eq 0) {
                    $BinaryOctet = "00000000"
                }

                # MERGES WITH EXISTING DATA
                $BinaryAddress = "$BinaryAddress" + "$BinaryOctet"
            }

            # COUNTS 1 BITS IN ADDRESS AND THEN OUTPUTS PREFIX
            $Prefix = ($BinaryAddress.ToCharArray() | Where {$_ -eq '1'}).count
            Return $Prefix
        }

        # EXECUTES IF PRE WAS INPUTTED
        If ($Pre -ne $null) {
            
            # ADDS A 1 AT THE BACK OF THE STRING UNTIL THE PREFIX NUMBER THEN ADDS A 0 UNTIL ALL 32 BITS ARE ACCOUNNTED FOR
            While ($cnt -lt 32) {
                If ($cnt -lt $Pre) {
                    $OutArr = "$OutArr" + "1"
                } Else {
                    $OutArr = "$OutArr" + "0"
                }

                $cnt++
            }

            # ADDS '.' INTO THE BITS TO MAKE A BINARY ADDRESS
            $BinaryAddress = "$($OutArr.Substring(0,8)).$($OutArr.Substring(8,8)).$($OutArr.Substring(16,8)).$($OutArr.Substring(24,8))"
            $cnt = 0

            # CONVERTS EACH BINARY OCTET TO DECIMAL
            $BinaryAddress.Split('.') | Foreach {
                $Octet = [convert]::ToInt32($_,2)
                If ($cnt -eq 0) {
                    $Subnet = "$Octet"
                } Else {
                    $Subnet = "$Subnet" + "." + "$Octet"
                }
                $cnt++
            }

            # OUTPUTS SUBNET MASK
            Return $Subnet
        }
    }

    # PROVIDES THE INTERFACE AFTER ADAPTER IS SELECTED
    function sc_Modify-NetInterface (
        [parameter(Mandatory=$true)][psobject]$Adapter
    )
    {
        # RESETS ALL VARIABLES FOR FUNCTION
        $OutputText = $null
        $ValidNetConf = @()
        $NetConfChoice = $null
        $IPData = $null
        $cnt = 1
        $ValidNetConf = @(1,2,3,4)

        # GATHERS INTERFACE IP DATA
        $IPData = sc_Get-NetInfo -Name $Adapter.Name

        # GENERATES OUTPUT TEXT
        $OutputText = "
--------------------------------
      $($Adapter.Name) Settings
--------------------------------
 
        $($IPData | Out-String)
1) Modify IPv4 Address Settings
2) Modify DNS Server Settings
3) Enable/Disable IPv6
 
4) Return to main menu
 
        "


        # RETURNS TEXT DATA
        Write-Output $OutputText

        # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
        Do {
            $NetConfChoice = $null
            [int]$NetConfChoice = Read-Host "Enter selection"

        } While ($ValidNetConf -notcontains $NetConfChoice)

        # EXECUTES FUNCTIONS FOR PROCESSING CHANGES
        Switch ($NetConfChoice) {
            1 {sc_Set-IPv4 -Data $IPData ; sc_Modify-NetInterface -Adapter $Adapter ; break}
            2 {sc_Modify-DNSSettings -Data $IPData ; sc_Modify-NetInterface -Adapter $Adapter ; break}
            3 {sc_Toggle-IPv6 -Adapter $IPData ; break}
            4 {sc_Create-MainMenu ; break}
        }
    }

    # EXECUTES CHANGES TO IPV4 ADDRESSES
    function sc_Set-IPv4 (
        [parameter(Mandatory=$true)]$Data
    )
    {
        # RESETS ALL VARIABLES FOR FUNCTION
        $Prefix = $null
        $Octs = $null
        $IP = $null
        $Subnet = $null
        $Gateway = $null
        $ValidOcts = 0..255
        $OutputText = $null
        $ValidDHCP = @(1,2,3)

        # GENERATES OUTPUT TEXT
        $OutputText = "
------ DHCP or STATIC IP ------
 
1) Use DHCP
2) Use and set a static IP
 
3) Return to NIC Settings
 
        "


        # RETURNS TEXT DATA
        Write-Output $OutputText

        # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
        Do {
            $DHCPChoice = $null
            $DHCPChoice = Read-Host "Enter selection"

        } While ($ValidDHCP -notcontains $DHCPChoice)

        # EXECUTES SELECTED OPTION
        If ($DHCPChoice -eq 1) {
            Set-NetIPInterface -InterfaceAlias $Data.Name -Dhcp Enabled
            Start-Sleep -Seconds 2
            sc_Modify-NetInterface -Adapter $Data
        } ElseIf ($DHCPChoice -eq 2) {
            Set-NetIPInterface -InterfaceAlias $Data.Name -Dhcp Disabled
            $IP = Read-Host "Enter static IP address"
            $Octs = $IP.Split('.')

            # VALIDATES IP HAS 4 OCTETS
            If ($Octs.count -ne 4) {
                Write-Host -ForegroundColor Red "Invalid IP. Input must have 4 octects."
                sc_Modify-NetInterface -Adapter $Data
            }

            # VALIDATES IP VALUES FOR EACH OCTET
            Foreach ($Oct in $Octs) {
                If ($ValidOcts -notcontains $Oct) {
                    Write-Host -ForegroundColor Red "Invalid IP. All octets must be between 0 and 255."
                    sc_Modify-NetInterface -Adapter $Data
                }
            }

            $Subnet = Read-Host "Enter subnet mask (Blank = Default 255.0.0.0)"
            $Octs = $Subnet.Split('.')

            # VALIDATES IP HAS 4 OCTETS
            If ($Octs.count -ne 4) {
                Write-Host -ForegroundColor Red "Invalid IP. Input must have 4 octects."
                sc_Modify-NetInterface -Adapter $Data
            }

            # VALIDATES IP VALUES FOR EACH OCTET
            Foreach ($Oct in $Octs) {
                If ($ValidOcts -notcontains $Oct) {
                    Write-Host -ForegroundColor Red "Invalid IP. All octets must be between 0 and 255."
                    sc_Modify-NetInterface -Adapter $Data
                }
            }

            $Gateway = Read-Host "Enter default gateway"
            $Octs = $Gateway.Split('.')

            # VALIDATES IP HAS 4 OCTETS
            If (($Octs.count -ne 4) -and ($Octs -ne "")) {
                Write-Host -ForegroundColor Red "Invalid IP. Input must have 4 octects."
                sc_Modify-NetInterface -Adapter $Data
            } ElseIf ($Octs.count -eq 4) {
                # VALIDATES IP VALUES FOR EACH OCTET
                Foreach ($Oct in $Octs) {
                    If ($ValidOcts -notcontains $Oct) {
                        Write-Host -ForegroundColor Red "Invalid IP. All octets must be between 0 and 255."
                        sc_Modify-NetInterface -Adapter $Data
                    }
                }
            }

            # DELETES OLD IP DATA
            Remove-NetIPAddress -InterfaceAlias $Data.Name -Confirm:$false
            Remove-NetRoute -InterfaceAlias $Data.Name -AddressFamily IPv4 -NextHop $Data.DefaultGateway -Confirm:$false -ErrorAction SilentlyContinue| Out-Null

            # SETS NEW IP DATA
            New-NetIPAddress -InterfaceAlias $Data.Name -AddressFamily IPv4 -IPAddress $IP -PrefixLength (sc_Convert-SubnetInfo -Sub $Subnet) | Out-Null
            New-NetRoute -InterfaceAlias $Data.Name -AddressFamily IPv4 -NextHop $Gateway -DestinationPrefix "0.0.0.0/0" -Confirm:$false -ErrorAction SilentlyContinue| Out-Null

            sc_Modify-NetInterface -Adapter $Data
        } ElseIf ($DHCPChoice -eq 3) {
            sc_Modify-NetInterface -Adapter $Data
        }
    }

    # GATHERS IP INFO FOR AN INTERFACE
    function sc_Get-NetInfo (
        [parameter(Mandatory=$true)]$Name
    )
    {
        # RESETS ALL VARIABLES FOR FUNCTION
        $TempIPInfo = $null
        $IPv4 = $null
        $SM = $null
        $GW = $null
        $DNS1 = $null
        $DNS2 = $null
        $MAC = $null
        $DHCPStatus = $null
        $IPv6Status = $null
        $IPObject = $null

        # GATHERS ALL RELEVANT IP INFORMATION FROM EACH ADAPTER
        $TempIPInfo = Get-NetIPConfiguration -InterfaceAlias $Name
        $IPv4 = $TempIPInfo.IPv4Address.IPAddress
        $SM = sc_Convert-SubnetInfo -Pre $TempIPInfo.IPv4Address.PrefixLength
        $GW = $TempIPInfo.IPv4DefaultGateway.NextHop
        $DNS1 = (Get-DnsClientServerAddress -InterfaceAlias $Name -AddressFamily IPv4).ServerAddresses[0]
        $DNS2 = (Get-DnsClientServerAddress -InterfaceAlias $Name -AddressFamily IPv4).ServerAddresses[1]
        $MAC = (Get-NetAdapter -Name $Name).MacAddress
        $IPv6Status = (Get-NetAdapterBinding -Name $Name | Where {$_.ComponentID -eq "ms_tcpip6"}).Enabled

        # TRANSLATES PREFIX ORIGIN
        Switch ($TempIPInfo.IPv4Address.PrefixOrigin) {
            "Manual" {$DHCPStatus = "STATIC" ; break}
            "Dhcp" {$DHCPStatus = "DHCP" ; break}
            "WellKnown" {$DHCPStatus = "APIPA" ; break}
        }

        # GENERATES CUSTOM IP OBJECT
        $IPObject += New-Object -TypeName psobject -Property @{
            Name = $Name
            Description = $TempIPInfo.InterfaceDescription
            IPv4 = $IPv4
            SubnetMask = $SM
            DefaultGateway = $GW
            DNSServer1 = $DNS1
            DNSServer2 = $DNS2
            MAC = $MAC
            AddressAssignment = $DHCPStatus
            IPv6Enabled = $IPv6Status
        }

        # RETURNS IP DATA
        Return $IPObject | Select -Property Name,Description,AddressAssignment,MAC,IPv4,SubnetMask,DefaultGateway,DNSServer1,DNSServer2,IPv6Enabled
    }

    # MODIFIES DNS SETTINGS
    function sc_Modify-DNSSettings (
        [parameter(Mandatory=$true)]$Data
    )
    {
    # RESETS ALL VARIABLES FOR FUNCTION
        $DChoice = $null
        $PrefDNS = $null
        $AltDNS = $null
        $Octs = $null
        $OutputText = $null
        $ValidOcts = 0..255
        $ValidD = @(1,2,3)

        # GENERATES OUTPUT TEXT
        $OutputText = "
------ DNS Settings ------
 
1) Clear DNS Servers
2) Set DNS Servers
 
3) Back to NIC Settings
 
        "


        # RETURNS TEXT DATA
        Write-Output $OutputText

        # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
        Do {
            $DChoice = $null
            $DChoice = Read-Host "Enter selection"

        } While ($ValidD -notcontains $DChoice)
        
        # EXECUTES SELECTED OPTION
        If ($DChoice -eq 1) {
            Set-DnsClientServerAddress -InterfaceAlias $Data.Name -ResetServerAddresses
            sc_Modify-NetInterface -Adapter $Data
        } ElseIf ($DChoice -eq 2) {
            # GATHERS DNS DATA
            $PrefDNS = Read-Host "Enter preferred DNS server"
            $Octs = $PrefDNS.Split('.')

            # VALIDATES IP HAS 4 OCTETS
            If ($Octs.count -ne 4) {
                Write-Host -ForegroundColor Red "Invalid IP. Input must have 4 octects."
                sc_Modify-NetInterface -Adapter $Data
            }

            # VALIDATES IP VALUES FOR EACH OCTET
            Foreach ($Oct in $Octs) {
                If ($ValidOcts -notcontains $Oct) {
                    Write-Host -ForegroundColor Red "Invalid IP. All octets must be between 0 and 255."
                    sc_Modify-NetInterface -Adapter $Data
                }
            }

            $AltDNS = Read-Host "Enter alternate DNS server (Blank for no entry)"
            $Octs = $PrefDNS.Split('.')

            # VALIDATES IP HAS 4 OCTETS
            If (($Octs.count -ne 4) -and ($AltDNS -ne "")) {
                Write-Host -ForegroundColor Red "Invalid IP. Input must have 4 octects."
                sc_Modify-NetInterface -Adapter $Data

            } ElseIf ($Octs.count -eq 4) {
                # VALIDATES IP VALUES FOR EACH OCTET
                Foreach ($Oct in $Octs) {
                    If ($ValidOcts -notcontains $Oct) {
                        Write-Host -ForegroundColor Red "Invalid IP. All octets must be between 0 and 255."
                        sc_Modify-NetInterface -Adapter $Data
                    }
                }
            }

            # EXECUTES DNS CHANGE
            Set-DnsClientServerAddress -InterfaceAlias $Data.Name -ServerAddresses ($PrefDNS,$AltDNS)
            sc_Modify-NetInterface -Adapter $Data
        } ElseIf ($DChoice -eq 3) {
            sc_Modify-NetInterface -Adapter $Adapter
        }
    }

    # ENABLES\DISABLES IPv6 ON AN INTERFACE
    function sc_Toggle-IPv6 (
        [parameter(Mandatory=$true)]$Adapter
    )
    {
        # RESETS ALL VARIABLES FOR FUNCTION
        $IPv6Choice = $null
        $OutputText = $null
        $ValidIPv6 = @(1,2,3)

        # GENERATES OUTPUT TEXT
        $OutputText = "
------ ENABLE/DISABLE IPv6 ------
 
1) Disable IPv6 on this adapter
2) Enable IPv6 on this adapter
 
3) Back to NIC Settings
 
        "


        # RETURNS TEXT DATA
        Write-Output $OutputText

        # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
        Do {
            $IPv6Choice = $null
            $IPv6Choice = Read-Host "Enter selection"

        } While ($ValidIPv6 -notcontains $IPv6Choice)

        # EXECUTES IPv6 SETTING
        Switch ($IPv6Choice) {
            1 {Disable-NetAdapterBinding -Name $Adapter.Name -ComponentID ms_tcpip6 ; sc_Modify-NetInterface -Adapter $Adapter ; break}
            2 {Enable-NetAdapterBinding -Name $Adapter.Name -ComponentID ms_tcpip6 ; sc_Modify-NetInterface -Adapter $Adapter ; break}
            3 {sc_Modify-NetInterface -Adapter $Adapter ; break}
        }
    }

    # RESETS CNT VARIABLE
    $cnt = 1

    # GATHERS ALL NETWORK ADAPTERS ON SERVER
    $Teams = Get-NetLbfoTeam
    $NetAdapters += Get-NetAdapter | Sort -Property Name | Foreach {
        If ($Teams.Members -notcontains $_.Name) {
            $IP = Get-NetIPConfiguration -InterfaceAlias $_.Name
            New-Object -TypeName psobject -Property @{
                Name = $_.Name
                IPv4 = $IP.IPv4Address
                Description = $_.InterfaceDescription
                "#" = $cnt
            }
        } Else {
            New-Object -TypeName psobject -Property @{
                Name = $_.Name
                IPv4 = "N/A"
                Description = "NIC Team Member"
                "#" = $cnt
            }
        }

        $cnt++
    }

    $NetAdapters += New-Object -TypeName psobject -Property @{
        Name = "Return to Main menu"
        IPv4 = ""
        Description = ""
        "#" = $cnt
    }

    # GENERATES OUTPUT TEXT
    $OutputText = "
 
----Network Adapter Settings----
 
Available Network Adapters
    "


    # RETURNS TEXT DATA AND BRIEF OF ADAPTER DATA AS STRING
    Write-Output $OutputText
    $NetAdapters | Select -Property "#",Name,IPv4,Description | Sort -Property "#" | Out-String

    # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
    Do {
        $NetChoice = $null
        $NetChoice = Read-Host "Enter selection"

        # Ignores team members selections
        If ($Teams -ne $null) {
            If (($NetAdapters | Where {$_.Description -eq "NIC Team Member"})."#" -contains $NetChoice) {
                Write-Host -ForegroundColor Yellow "Due to NIC Teaming this interface is not allowed to be modified."
                Write-Host -ForegroundColor Yellow "Please select another."
                $NetChoice = $null
            }
        }

        If ($NetChoice -eq $NetAdapters.count) {
            sc_Create-MainMenu
        }

    } While ($NetAdapters."#" -notcontains $NetChoice)

    # GATHERS ONLY ADAPTER TO BE WORKED
    $NetInput = $NetAdapters | Where {$_."#" -like "$NetChoice"}

    # EXECUTES ADAPTER SPECIFIC INTERFACE
    sc_Modify-NetInterface -Adapter $NetInput
}

###################################################### CONFIGURES NIC TEAMING ######################################################
function sc_Config-NICTeaming (

)
{
    # RESETS ALL VARIABLES FOR FUNCTION
    $NICTeams = $null
    $ValidNT = @()
    $NTChoice = $null
    $OutputText = $null
    $NICOutput = $null

    function sc_Create-NICTeam (
        [Parameter(Mandatory=$true)]$Teams
    )
    {
        # RESETS ALL VARIABLES FOR FUNCTION
        $AvailNics = $null
        $TeamName = $null
        $NICChoice = $null
        $Model = $null
        $OutputText = $null
        $NicInput = $null
        $ValidTM = $null
        $OutputText2 = $null
        $TMChoice = $null
        $ValidLBA = $null
        $OutputText3 = $null
        $LBAChoice = $null
        $cnt = 1

        # GATHERS ONLY VALID ADAPTERS
        If ($Teams -eq "NO TEAMS") {
            $AvailNics = Get-NetAdapter | Sort -Property Name
        } Else {
            $AvailNics = Get-NetAdapter | Sort -Property Name | Where {($Teams.Members -notcontains $_.Name) -and ($_.InterfaceDescription -notmatch `
                "Microsoft Network Adapter Multiplexor Driver")}
        }

        If ($AvailNics.count -eq 0) {
            Write-Host -ForegroundColor Yellow "No NICs are available for teaming."
            
            Start-Sleep -Seconds 1

            sc_Config-NICTeaming

        } Else {

            Foreach ($AvailNic in $AvailNics) {
                $AvailNic | Add-Member -MemberType NoteProperty -Name "#" -Value $cnt
                $cnt++
            }
        }
        
        # GATHERS TEAM NAME
        ""
        $TeamName = Read-Host "Input NIC Team Name"

        # GENERATES OUTPUT TEXT
        $OutputText = "
 
----Select First Team Member----
    "


        # RETURNS TEXT DATA AND BRIEF OF ADAPTER DATA AS STRING
        Write-Output $OutputText
        $AvailNics | Select -Property "#",Name | Sort -Property "#" | Out-String

        # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
        Do {
            $NICChoice = $null
            $NICChoice = Read-Host "Enter selection"

        } While ($AvailNics."#" -notcontains $NICChoice)

        # GATHERS ONLY ADAPTER TO BE WORKED
        $NicInput = $AvailNics | Where {$_."#" -like "$NICChoice"}

        # GATHERS COMPUTER MODEL
        $Model = Get-WmiObject -Class Win32_ComputerSystem | Select -Property Model
        
        # IF VIRTUAL MACHINE SETS ONLY POSSIBLE TEAM MODE OTHERWISE GATHERS INPUT
        If (($Model.Model -match "Virtual Machine") -or ($Model.Model -match "VMware")) {
            $TeamMode = "SwitchIndependent"
        } Else {

            # DEFINE VALID INPUT
            $ValidTM = @(1,2,3)

            # GENERATES OUTPUT TEXT
            $OutputText2 = "
 
-------Select Teaming Mode------
 
1) Switch Independent (default in GUI)
2) LACP
3) Static
 
    "


            # RETURNS TEXT
            Write-Output $OutputText2

            # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
            Do {
                $TMChoice = $null
                $TMChoice = Read-Host "Enter selection"

            } While ($ValidTM -notcontains $TMChoice)

            # CONVERTS TMCHOICE TO VALID COMMAND STRING
            Switch ($TMChoice) {
                1 {$TeamMode = "SwitchIndependent" ; break}
                2 {$TeamMode = "Lacp" ; break}
                3 {$TeamMode = "Static" ; break}
            }
        }

        # DEFINE VALID INPUT
        $ValidLBA = @(1,2,3,4,5)

        # GENERATES OUTPUT TEXT
        $OutputText3 = "
 
--Select Load Balancing Algorithm--
 
1) Transport Ports (default in GUI)
2) Dynamic
3) Hyper-V Port
4) IP Addresses
5) MAC Addresses
 
    "


        # RETURNS TEXT
        Write-Output $OutputText3

        # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
        Do {
            $LBAChoice = $null
            $LBAChoice = Read-Host "Enter selection"

        } While ($ValidLBA -notcontains $LBAChoice)

        # CONVERTS LBACHOICE TO VALID COMMAND STRING
        Switch ($LBAChoice) {
            1 {$LBA = "TransportPorts" ; break}
            2 {$LBA = "Dynamic" ; break}
            3 {$LBA = "HyperVPort" ; break}
            4 {$LBA = "IPAddresses" ; break}
            5 {$LBA = "MacAddresses" ; break}
        }

        # EXECUTES NIC TEAM CREATION AND THEN RETURNS TO PREVIOUS MENU
        New-NetLbfoTeam -Name $TeamName -TeamMembers $NicInput.Name -TeamingMode $TeamMode -LoadBalancingAlgorithm $LBA -Confirm:$false
        sc_Config-NICTeaming

    }

    function sc_Add-NICTeamMember (
        [Parameter(Mandatory=$true)]$Teams
    )
    {
        # RESETS ALL VARIABLES FOR FUNCTION
        $AvailNics = $null
        $NTChoice = $null
        $TeamInput = $null
        $NICChoice = $null
        $OutputText = $null
        $NicInput = $null
        $OutputText2 = $null
        $ValidNM = @()
        $NMChoice = $null
        $OutputText3 = $null
        $ModeInput = $null
        $cnt = 1

        # VALIDATES THAT THERE ARE AVAILABLE TEAMS
        If ($Teams -eq "NO TEAMS") {
            Write-Host -ForegroundColor Yellow "No NIC Teams are currently created."
            Start-Sleep -Seconds 1

            sc_Config-NICTeaming

        } Else {
            $Teams = $Teams | Sort -Property Name

            Foreach ($Team in $Teams) {
                $Team | Add-Member -MemberType NoteProperty -Name "#" -Value $cnt -Force
                $cnt++
            }
        }

        # GATHERS ONLY VALID ADAPTERS
        $cnt = 1
        $AvailNics = Get-NetAdapter | Where {($Teams.Members -notcontains $_.Name) -and ($_.InterfaceDescription -notmatch `
            "Microsoft Network Adapter Multiplexor Driver")}

        # VALIDATES THAT THERE ARE AVAILABLE NICS, AND GENERATES OUTPUT
        If ($AvailNics.count -eq 0) {
            Write-Host -ForegroundColor Yellow "No NICs are available for teaming."
            Start-Sleep -Seconds 1

            sc_Config-NICTeaming

        } Else {
            $AvailNics = $AvailNics | Sort -Property Name

            Foreach ($AvailNic in $AvailNics) {
                $AvailNic | Add-Member -MemberType NoteProperty -Name "#" -Value $cnt

                $cnt++
            }
        }

        # GENERATES OUTPUT TEXT
        $OutputText = "
 
---Select NIC Team to Modify----
    "

        
        # RETURNS TEAM DATA AS STRING
        Write-Output $OutputText
        $Teams | Select -Property "#",Name,Members | Out-String

        # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
        Do {
            $NTChoice = $null
            $NTChoice = Read-Host "Enter selection"

        } While ($Teams."#" -notcontains $NTChoice)

        # GATHERS ONLY ADAPTER TO BE WORKED
        $TeamInput = $Teams | Where {$_."#" -like "$NTChoice"}

        # GENERATES OUTPUT TEXT
        $OutputText2 = "
 
-----Select NIC to Join Team----
    "


        # RETURNS TEXT DATA AND BRIEF OF ADAPTER DATA AS STRING
        Write-Output $OutputText2
        $AvailNics | Select -Property "#",Name | Sort -Property "#" | Out-String

        # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
        Do {
            $NICChoice = $null
            $NICChoice = Read-Host "Enter selection"

        } While ($AvailNics."#" -notcontains $NICChoice)

        # GATHERS ONLY ADAPTER TO BE WORKED
        $NicInput = $AvailNics | Where {$_."#" -like "$NICChoice"}

        # DEFINES VALID INPUT
        $ValidNM = @(1,2)

        # GENERATES OUTPUT TEXT
        $OutputText3 = "
 
----Select Mode for Adapter-----
 
1) Active
2) Standby
 
    "


        # RETURNS TEXT DATA AND BRIEF OF ADAPTER DATA AS STRING
        Write-Output $OutputText3

        # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
        Do {
            $NMChoice = $null
            $NMChoice = Read-Host "Enter selection"

        } While ($ValidNM -notcontains $NMChoice)

        # CONVERTS NMCHOICE TO VALID COMMAND STRING
        Switch ($NMChoice) {
            1 {$ModeInput = "Active" ; break}
            2 {$ModeInput = "Standby" ; break}
        }

        # EXECUTES NIC TEAM MEMBER ADD AND THEN RETURNS TO PREVIOUS MENU
        Add-NetLbfoTeamMember -Name $NicInput.Name -Team $TeamInput.Name -AdministrativeMode $ModeInput -Confirm:$false | Out-Null
        sc_Config-NICTeaming
    }

    function sc_Remove-NICTeamMember (
        [Parameter(Mandatory=$true)]$Teams
    )
    {
        # RESETS ALL VARIABLES FOR FUNCTION
        $NTChoice = $null
        $TeamInput = $null
        $SelectedTeam = $null
        $TeamMembers = @()
        $NICChoice = $null
        $OutputText = $null
        $NicInput = $null
        $OutputText2 = $null
        $cnt = 1

        # VALIDATES THAT THERE ARE AVAILABLE TEAMS
        If ($Teams -eq "NO TEAMS") {
            Write-Host -ForegroundColor Yellow "No NIC Teams are currently created."

            Start-Sleep -Seconds 1

            sc_Config-NICTeaming

        } Else {
            $Teams = $Teams | Sort -Property Name

            Foreach ($Team in $Teams) {
                $Team | Add-Member -MemberType NoteProperty -Name "#" -Value $cnt -Force

                $cnt++
            }
        }

        # GENERATES OUTPUT TEXT
        $OutputText = "
 
---Select NIC Team to Modify----
    "

        
        # RETURNS TEAM DATA AS STRING
        Write-Output $OutputText
        $Teams | Select -Property "#",Name,Members | Out-String

        # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
        Do {
            $NTChoice = $null
            $NTChoice = Read-Host "Enter selection"

        } While ($Teams."#" -notcontains $NTChoice)

        # GATHERS ONLY ADAPTER TO BE WORKED
        $TeamInput = $Teams | Where {$_."#" -like "$NTChoice"}

        # GATHERS NIC TEAM MEMBERS
        $cnt = 1
        $SelectedTeam = ($Teams | Where {$_.Name -match $TeamInput.Name}).Members | Sort

        # VALIDATES THAT THERE ARE MULTIPLE NICS IN TEAM
        If ($SelectedTeam.count -eq 1) {
            Write-Host -ForegroundColor Yellow "Only 1 member in team. Use `'Delete NIC Team`' option."

            Start-Sleep -Seconds 1

            sc_Config-NICTeaming

        } Else {
            Foreach ($Member in $SelectedTeam) {
                $TeamMembers += New-Object -TypeName psobject -Property @{
                    "#" = $cnt
                    Name = $Member
                }

                $cnt++
            }
        }

        # GENERATES OUTPUT TEXT
        $OutputText2 = "
 
---Select NIC to Remove from Team--
    "


        # RETURNS TEXT DATA AND BRIEF OF ADAPTER DATA AS STRING
        Write-Output $OutputText2
        $TeamMembers | Select -Property "#",Name | Sort -Property "#" | Out-String

        # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
        Do {
            $NICChoice = $null
            $NICChoice = Read-Host "Enter selection"

        } While ($TeamMembers."#" -notcontains $NICChoice)

        # GATHERS ONLY ADAPTER TO BE WORKED
        $NicInput = $TeamMembers | Where {$_."#" -like "$NICChoice"}

        # EXECUTES NIC TEAM MEMBER REMOVAL AND THEN RETURNS TO PREVIOUS MENU
        Remove-NetLbfoTeamMember -Name $NicInput.Name -Team $TeamInput.Name -Confirm:$false | Out-Null
        sc_Config-NICTeaming
    }

    function sc_Remove-NICTeam (
        [Parameter(Mandatory=$true)]$Teams
    )
    {
        # RESETS ALL VARIABLES FOR FUNCTION
        $NTChoice = $null
        $TeamInput = $null
        $OutputText = $null
        $cnt = 1

        # VALIDATES THAT THERE ARE AVAILABLE TEAMS
        If ($Teams -eq "NO TEAMS") {
            Write-Host -ForegroundColor Yellow "No NIC Teams are currently created."

            Start-Sleep -Seconds 1

            sc_Config-NICTeaming

        } Else {
            $Teams = $Teams | Sort -Property Name

            Foreach ($Team in $Teams) {
                $Team | Add-Member -MemberType NoteProperty -Name "#" -Value $cnt -Force

                $cnt++
            }
        }

        # GENERATES OUTPUT TEXT
        $OutputText = "
 
---Select NIC Team to Delete----
    "

        
        # RETURNS TEAM DATA AS STRING
        Write-Output $OutputText
        $Teams | Select -Property "#",Name,Members | Out-String

        # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
        Do {
            $NTChoice = $null
            $NTChoice = Read-Host "Enter selection"

        } While ($Teams."#" -notcontains $NTChoice)

        # GATHERS ONLY ADAPTER TO BE WORKED
        $TeamInput = $Teams | Where {$_."#" -like "$NTChoice"}

        # EXECUTES NIC TEAM DELETION AND THEN RETURNS TO PREVIOUS MENU
        Remove-NetLbfoTeam -Name $TeamInput.Name -Confirm:$false
        sc_Config-NICTeaming
    }

    # GATHERS ALL NIC TEAMS
    $NICTeams = Get-NetLbfoTeam

    # GATHERS NIC TEAM INFO
    If ($NICTeams -eq $null) {
        $NICOutput = "**No NIC Teams are configured**"
        $NICTeams = "NO TEAMS"
    } Else {
        $NICOutput = $NICTeams | Select -Property Name,Members,Status | Out-String
    }

    # DEFINES VALID INPUTS
    $ValidNT = @(1,2,3,4,5)

    # GENERATES OUTPUT TEXT
    $OutputText = "
--------------------------------
         CURRENT TEAMS
--------------------------------
 
$NICOutput
 
-----Configuration Options------
 
1) Create NIC Team
2) Add Member to NIC Team
3) Remove Member of NIC Team
4) Delete NIC Team
 
5) Return to main menu
 
    "


    # RETURNS TEXT DATA
    Write-Output $OutputText

    # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
    Do {
        $NTChoice = $null
        $NTChoice = Read-Host "Enter selection"

    } While ($ValidNT -notcontains $NTChoice)

    # EXECUTES CHOSEN SUB-FUNCTION
    Switch ($NTChoice) {
        1 {sc_Create-NICTeam -Teams $NICTeams ; break}
        2 {sc_Add-NICTeamMember -Teams $NICTeams ; break}
        3 {sc_Remove-NICTeamMember -team $NICTeams ; break}
        4 {sc_Remove-NICTeam -Teams $NICTeams ; break}
        5 {sc_Create-MainMenu ; break}
    }
}

##################################################### CONFIGURE FIREWALL PROFILES ######################################################
function sc_Set-Firewall (

)
{
    # RESETS ALL VARIABLES FOR FUNCTION
    $DomFW = $null
    $PriFW = $null
    $PubFW = $null
    $OutputText = $null
    $ValidFW = @()
    $FWChoice = $null

    # FUNCTION TO TOGGLE A FIREWALL PROFILE
    function sc_Toggle-Firewall (
        [parameter(Mandatory=$true)]$Profile,
        [parameter(Mandatory=$true)]$Status
    )
    {
        If ($Status -eq "Enabled") {
            Set-NetFirewallProfile -Name $Profile -Enabled False | Out-Null
            sc_Set-Firewall
        } Else {
            Set-NetFirewallProfile -Name $Profile -Enabled True | Out-Null
            sc_Set-Firewall
        }
    }

    # DEFINES VALID INPUTS
    $ValidFW = @(1,2,3,4)

    # GATHERS STATUS OF EACH PROFILE
    If ((Get-NetFirewallProfile -Name Domain).Enabled) {$DomFW = "Enabled"} Else {$DomFW = "Disabled"}
    If ((Get-NetFirewallProfile -Name Private).Enabled) {$PriFW = "Enabled"} Else {$PriFW = "Disabled"}
    If ((Get-NetFirewallProfile -Name Public).Enabled) {$PubFW = "Enabled"} Else {$PubFW = "Disabled"}

    # GENERATES OUTPUT TEXT
    $OutputText = "
--- TOGGLE FIREWALL ---
 
1) Domain: $DomFW
2) Private: $PriFW
3) Public: $PubFW
 
4) Return to main menu
 
    "


    # RETURNS TEXT DATA
    Write-Output $OutputText

    # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
    Do {
        $FWChoice = $null
        $FWChoice = Read-Host "Enter selection"

    } While ($ValidFW -notcontains $FWChoice)

    Switch ($FWChoice) {
        1 {sc_Toggle-Firewall -Profile "Domain" -Status $DomFW ; break}
        2 {sc_Toggle-Firewall -Profile "Private" -Status $PriFW ; break}
        3 {sc_Toggle-Firewall -Profile "Public" -Status $PubFW ; break}
        4 {sc_Create-MainMenu ; break}
    }
}

######################################################### CONFIGURE TELEMETRY ##########################################################
function sc_Set-Telemetry (

)
{
    # GENERATES OUTPUT TEXT
    $ValidTel = $null
    $TelReg = $null
    $OutputText = $null
    $TelChoice = $null

    # DEFINES VALID OPTIONS
    $ValidTel = @(1,2,3,4,5)

    # GATHERS SETTING IF SET BY GROUP POLICY
    $TelReg = (Get-ItemProperty -Path "HKLM:\\SOFTWARE\Policies\Microsoft\Windows\DataCollection").AllowTelemetry

    # EXITS FUNCTION IF CONTROLLED BY GROUP POLICY
    If ($TelReg -ne $null) {
        Write-Host "Telemetry settings are controlled by Group Policy. Returning to main menu..."
        Start-Sleep -Seconds 3
        sc_Create-MainMenu
    }

    # GENERATES OUTPUT TEXT
    $OutputText = "
 
Available telemetry settings:
 
1) Security
2) Basic
3) Enhanced
4) Full
 
5) Return to main menu
 
    "


    # RETURNS TEXT DATA
    Write-Output $OutputText

    # GATHERS OPTION UNTIL VALID CHOICE IS MADE
    Do {
        $TelChoice = $null
        $TelChoice = Read-Host "Enter selection"

    } While ($ValidTel -notcontains $TelChoice)

    # EXECUTES TELEMETRY ADJUSTMENT
    Switch ($TelChoice) {
        1 {Set-ItemProperty -Path "HKLM:\\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection" -Name AllowTelemetry -Value 0 ; sc_Create-MainMenu ; break}
        2 {Set-ItemProperty -Path "HKLM:\\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection" -Name AllowTelemetry -Value 1 ; sc_Create-MainMenu ; break}
        3 {Set-ItemProperty -Path "HKLM:\\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection" -Name AllowTelemetry -Value 2 ; sc_Create-MainMenu ; break}
        4 {Set-ItemProperty -Path "HKLM:\\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection" -Name AllowTelemetry -Value 3 ; sc_Create-MainMenu ; break}
        5 {sc_Create-MainMenu ; break}
    }
}

###################################################### EXECUTE WINDOWS ACTIVATION ######################################################
function sc_Set-WinAct (

)
{
    # RESETS VARIABLES FOR FUNCTION
    $OutputText = $null
    $ValidWA = $null
    $WAChoice = $null
    $Key = $null

    # SETS VALID OPTIONS
    $ValidWA = @(1,2,3,4)

    # GENERATES OUTPUT TEXT
    $OutputText = "
 
 -- Windows Activation --
 
1) Display License Info
2) Activate Windows
3) Install Product Key
 
4) Return to main menu
 
    "


    # RETURNS TEXT DATA
    Write-Output $OutputText

    # GATHERS OPTION UNTIL VALID CHOICE IS SELECTED
    Do {
        $WAChoice = Read-Host "Enter selection"

    } While ($ValidWA -notcontains $WAChoice)

    # EXECUTES SELECTED OPTION
    Switch ($WAChoice) {
        1 {slmgr /dli ; sc_Set-WinAct ; break}
        2 {Write-Host -ForegroundColor Yellow "Processing activation attempt. This may take awhile..." ; slmgr /ato ; sc_Set-WinAct ; break}
        3 {$Key = Read-Host "Input license key" ; slmgr /ipk $Key ; sc_Set-WinAct ; break}
        4 {sc_Create-MainMenu ; break}
    }
}

###################################################### CONFIGURE WINDOWS DEFENDER ######################################################
function sc_Set-WinDefend (

)
{
    # RESETS VARIABLES FOR FUNCTION
    $OutputText = $null
    $RTPStatus = $null
    $CBPStatus = $null
    $ASSStatus = $null
    $WDChoice = $null
    $ValidWD = $null

    # GATHERS WINDOWS DEFENDER SETTINGS
    $MPInfo = Get-MpPreference
    
    # TRANSLATES DATA FOR REAL-TIME PROTECTION STATUS
    If ($MPInfo.DisableRealtimeMonitoring -eq $false) {
        $RTPStatus = "ON"
    } ElseIf ($MPInfo.DisableRealtimeMonitoring -eq $true) {
        $RTPStatus = "OFF"
    } Else {
        $RTPStatus = "Query failed"
    }

    # TRANSLATES DATA FOR CLOUD-BASED PROTECTION STATUS
    If ($MPInfo.MAPSReporting -eq 2) {
        $CBPStatus = "ON"
    } ElseIf ($MPInfo.MAPSReporting -eq 0) {
        $CBPStatus = "OFF"
    } Else {
        $CBPStatus = "Query failed"
    }

    # TRANSLATES DATA FOR AUTOMATIC SAMPLE SUBMISSION STATUS
    If ($MPInfo.SubmitSamplesConsent -eq 1) {
        $ASSStatus = "ON"
    } ElseIf ($MPInfo.SubmitSamplesConsent -eq 0) {
        $ASSStatus = "OFF"
    } Else {
        $ASSStatus = "Query failed"
    }

    # SETS VALID OPTIONS
    $ValidWD = @(1,2,3,4)

    # GENERATES OUTPUT TEXT
    $OutputText = "
 
----------------------------------
    Configure Windows Defender
----------------------------------
 
Real-time Protection: $RTPStatus
Cloud-based Protection: $CBPStatus
Automatic Sample Submission: $ASSStatus
 
1) Toggle Real-time Protection
2) Toggle Cloud-base Protection
3) Toggle Automatic Sample Submission
 
4) Return to main menu
 
    "


    # RETURNS TEXT DATA
    Write-Output $OutputText

    # GATHERS OPTION UNTIL VALID CHOICE IS SELECTED
    Do {
        $WDChoice = Read-Host "Enter selection"

    } While ($ValidWD -notcontains $WDChoice)

    # EXECUTES SELECTED OPTION
    Switch ($WDChoice) {
        1 {If ($RTPStatus -eq "ON") {Set-MpPreference -DisableRealtimeMonitoring $true ; sc_Set-WinDefend} ElseIf ($RTPStatus -eq "OFF") `
            {Set-MpPreference -DisableRealtimeMonitoring $false ; sc_Set-WinDefend} Else `
            {Write-Host -ForegroundColor Yellow "Cannot toggle due to failed query" ; sc_Set-WinDefend} ; break}
        2 {If ($CBPStatus -eq "ON") {Set-MpPreference -MAPSReporting 0 ; sc_Set-WinDefend} ElseIf ($CBPStatus -eq "OFF") `
            {Set-MpPreference -MAPSReporting 2 ; sc_Set-WinDefend} Else `
            {Write-Host -ForegroundColor Yellow "Cannot toggle due to failed query" ; sc_Set-WinDefend} ; break}
        3 {If ($ASSStatus -eq "ON") {Set-MpPreference -SubmitSamplesConsent 0 ; sc_Set-WinDefend} ElseIf `
            ($ASSStatus -eq "OFF") {Set-MpPreference -SubmitSamplesConsent 1 ; sc_Set-WinDefend} Else `
            {Write-Host -ForegroundColor Yellow "Cannot toggle due to failed query" ; sc_Set-WinDefend} ; break}
        4 {sc_Create-MainMenu ; break}
    }
}

############################################################# CONFIGURE REMOTE MANAGEMENT ############################################################
function sc_Set-RemoteMgmt (

)
{
    # RESETS ALL VARIABLES FOR FUNCTION
    $RCheck = $null
    $RChoice = $null
    $RValid = $null
    $OutputText = $null

    # GATHERS STATUS AND VALID OPTIONS
    $RCheck = Configure-SMRemoting.exe -GET
    $RValid = @(1,2,3,4)

    # GENERATES OUTPUT TEXT
    $OutputText = "
 
----------------------------------
    Configure Remote Management
----------------------------------
     
Current Status: $RCheck
 
1) Enable Remote Management
2) Disable Remote Management
3) Enable Server Response to PING
 
4) Return to main menu
 
    "


    # RETURNS TEXT DATA
    Write-Output $OutputText

    # GATHER INPUT UNTIL VALID OPTION
    Do {
        $RChoice = $null
        $RChoice = Read-Host "Enter selection"
    } While ($RValid -notcontains $RChoice)

    # EXECUTES SELECTED OPTION
    Switch ($RChoice) {
        1 {Write-Host "Enabling Remote Management..." ; Configure-SMRemoting.exe -ENABLE ; sc_Set-RemoteMgmt ; break}
        2 {Write-Host "Disabling Remote Management..." ; Configure-SMRemoting.exe -DISABLE ; sc_Set-RemoteMgmt ; break}
        3 {Write-Host "Enabling PING requests..." ; Get-NetFirewallRule -DisplayName "File and Printer Sharing (Echo Request - ICMPv?-In" | Enable-NetFirewallRule ; sc_Set-RemoteMgmt ; break}
        4 {sc_Create-MainMenu ; break}
    }
}

############################################################# CONFIGURE RDP ############################################################
function sc_Set-RDP (

)
{
    # WHEN ENABLING RDP SETS AUTHENTICATION REQUIREMENT
    function sc_Set-SecureLevel (

    )
    {
        # RESETS ALL VARIABLES FOR FUNCTION
        $OutputText = $null
        $SChoice = $null
        $ValidS = $null

        # SETS VALID OPTIONS
        $ValidS = @(1,2,3)

        # GENERATES OUTPUT TEXT
        $OutputText = "
 
------ RDP Security Level ------
 
1) Allow only clients running Remote Desktop with Network Level Authentication (more secure)
2) Allow clients running any version of Remote Desktop (less secure)
 
3) Return to main menu
 
        "


        # RETURNS TEXT DATA
        Write-Output $OutputText

        # GATHERS OPTION UNTIL VALID CHOICE IS MADE
        Do {
            $SChoice = $null
            $SChoice = Read-Host "Enter selection"
        } While ($ValidS -notcontains $SChoice)

        # EXECUTES SELECTED OPTION
        Switch ($SChoice) {
            1 {Set-ItemProperty -Path "HKLM:\\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-TCP" -Name UserAuthentication -Value 1 ; sc_Create-MainMenu ; break}
            2 {Set-ItemProperty -Path "HKLM:\\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-TCP" -Name UserAuthentication -Value 0 ; sc_Create-MainMenu ; break}
            3 {sc_Create-MainMenu ; break}
        }
    }

    # SETS VALID OPTIONS
    $RDPValid = @(1,2,3)

    # GENERATES OUTPUT TEXT
    $OutputText = "
 
------ RDP Settings ------
 
1) Enable RDP
2) Disable RDP
 
3) Return to main menu
 
    "


    # RETURNS TEXT DATA
    Write-Output $OutputText

    # GATHERS OPTION UNTIL VALID CHOICE IS MADE
    Do {
        $RDPChoice = $null
        $RDPChoice = Read-Host "Enter selection"
    } While ($RDPValid -notcontains $RDPChoice)

    # EXECUTES SELECTED OPTION
    Switch ($RDPChoice) {
        1 {Set-ItemProperty -Path "HKLM:\\SYSTEM\CurrentControlSet\Control\Terminal Server" -Name fDenyTSConnections -Value 0 ; Write-Host "Enabling RDP..." ; sc_Set-SecureLevel ; break}
        2 {Set-ItemProperty -Path "HKLM:\\SYSTEM\CurrentControlSet\Control\Terminal Server" -Name fDenyTSConnections -Value 1 ; Write-Host "Disabling RDP..." ; sc_Create-MainMenu ; break}
        3 {sc_Create-MainMenu ; break}
    }
}

####################################################### CONFIGURE WINDOWS UPDATES ######################################################
function sc_Set-WindowsUpdate (

)
{
    # RESETS ALL VARIABLES FOR FUNCTION
    $AU = $null
    $NoAU = $null
    $WU = $null
    $WUChoice = $null
    $OutputText = $null
    $ValidWU = $null

    # GATHERS WINDOWS UPDATE DATA
    $AU = Get-ItemProperty -Path "HKLM:\\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU"
    $NoAU = $AU.NoAutoUpdate
    $AU = $AU.AUOptions

    # TRANSLATES REGISTRY FOR WINDOWS UPDATE TO USER FRIENDLY OUTPUT
    Switch ($AU) {
        $null {If ($NoAU -eq 1) {$WU = "Manual"} ElseIf ($NoAU -eq $null) {$WU = "Failed Query"} ; break}
        1 {$WU = "Never check for updates" ; break}
        2 {$WU = "Notify before download" ; break}
        3 {$WU = "DownloadOnly" ; break}
        4 {$WU = "Automatic" ; break}
    }

    # SETS VALID OPTIONS
    $ValidWU = @(1,2,3,4)

    # RETURNS WINDOWS UPDATE STATUS
    $OutputText = "
 
------ WINDOWS UPDATE SETTINGS ------
 
Windows Update currently set to: $WU
 
1) Set to Automatic
2) Set to DownloadOnly
3) Set to Manual
 
4) Return to main menu
 
    "


    # RETURNS TEXT DATA
    Write-Output $OutputText

    # GATHERS INPUT UNTIL VALID OPTION IS SELECTED
    Do {
        $WUChoice = $null
        $WUChoice = Read-Host "Enter selection"
    } While ($ValidWU -notcontains $WUChoice)

    # EXECUTES SELECTED OPTION
    Switch ($WUChoice) {
        1 {
            Stop-Service -Name wuauserv
            Remove-ItemProperty -Path "HKLM:\\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name NoAutoUpdate -ErrorAction SilentlyContinue
            Remove-ItemProperty -Path "HKLM:\\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name AUOptions -ErrorAction SilentlyContinue
            New-ItemProperty -Path "HKLM:\\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name AUOptions -Value 4 | Out-Null
            Start-Service -Name wuauserv
            sc_Create-MainMenu
            break
        }
        2 {
            Stop-Service -Name wuauserv
            Remove-ItemProperty -Path "HKLM:\\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name NoAutoUpdate -ErrorAction SilentlyContinue
            Remove-ItemProperty -Path "HKLM:\\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name AUOptions -ErrorAction SilentlyContinue
            New-ItemProperty -Path "HKLM:\\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name AUOptions -Value 3 | Out-Null
            Start-Service -Name wuauserv
            sc_Create-MainMenu
            break
        }
        3 {
            Stop-Service -Name wuauserv
            Remove-ItemProperty -Path "HKLM:\\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name AUOptions -ErrorAction SilentlyContinue
            New-ItemProperty -Path "HKLM:\\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name NoAutoUpdate -Value 1 | Out-Null
            Start-Service -Name wuauserv
            sc_Create-MainMenu
            break
        }
        4 {sc_Create-MainMenu ; break}
    }
}

######################################################## EXECUTE WINDOWS UPDATES #######################################################
function sc_Execute-WindowsUpdate (

)
{
    # RESETS ALL VARIABLES FOR FUNCTION
    $UpdateSession = $null
    $UpdateSearcher = $null
    $SearchResults = $null
    $cnt = $null
    $UpdateList = @()
    $UpdateSelection = $null
    $UpdatesToDownload = $null
    $UTitle = $null
    $Update = $null
    $Downloader = $null
    $UpdatesToInstall = $null
    $Installer = $null
    $InstallationResult = $null

    # EXECUTES SYSTEM SCAN FOR RELAVENT PATCHES
    Write-Host "Beginning system scan. This may take a while..."
    $UpdateSession = New-Object -ComObject Microsoft.Update.Session
    $UpdateSearcher = $UpdateSession.CreateUpdateSearcher()
    $SearchResults = $UpdateSearcher.Search("IsInstalled=0 and Type='Software'")

    # CREATES OUTPUT OBJECT FOR EACH REQUIRED PATCH
    If ($SearchResults.Updates.Count -eq 0) {
        ""
        Write-Host -ForegroundColor Yellow "System is up-to-date. Returning to main menu..."

        Start-Sleep -Seconds 3

        sc_Create-MainMenu
    }

    $cnt = 1
    $SearchResults.Updates | Foreach {$UpdateList += New-Object -TypeName psobject -Property @{
            SelNumber = $cnt
            Title = $_.Title
            Description = "$cnt) $($_.Title)"
        }
        $cnt++
    }

    # RETURNS TEXT DATA
    ""
    $UpdateList.Description
    ""

    # GATHERS OPTION UNTIL VALID CHOICE IS MADE
    Do {
        $UpdateSelection = $null
        $UpdateSelection = Read-Host "Input number to install specific patch or `'A`' for all (Blank=Cancel)"
        If ($UpdateSelection -eq "") {
            Write-Host "Cancelling Windows Update..."
            sc_Create-MainMenu
        }
    } While (($UpdateSelection -notlike 'A') -and (($UpdateList | Where {$_.SelNumber -eq $UpdateSelection}) -eq $null))

    # FILTERS TO ONLY SELECTED UPDATES
    $UpdatesToDownload = New-Object -ComObject Microsoft.Update.UpdateColl
    If ($UpdateSelection -like 'A') {
        Foreach ($KB in $SearchResults.Updates) {
            $UpdatesToDownload.Add($KB) | Out-Null
        }
    } Else {
        $UTitle = ($UpdateList | Where {$_.SelNumber -eq $UpdateSelection}).Title
        $Update = $SearchResults.Updates | Where {$_.Title -eq $UTitle}
        $UpdatesToDownload.Add($Update) | Out-Null
    }

    # EXECUTES DOWNLOAD OF ALL SELECTED UPDATES
    $Downloader = $UpdateSession.CreateUpdateDownloader()
    $Downloader.Updates = $UpdatesToDownload
    ""
    Write-Host "Beginning download of patches. This may take a while..."
    $Downloader.Download() | Out-Null

    # FILTERS TO ONLY DOWNLOADED UPDATES
    $UpdatesToInstall = New-Object -ComObject Microsoft.Update.UpdateColl
    Foreach ($KB in $SearchResults.Updates) {
        If ($KB.IsDownloaded -eq $true) {
            $UpdatesToInstall.Add($KB) | Out-Null
        } Else {
            Write-Host -ForegroundColor Red "$($KB.Title) failed to download. Skipping..."
        }
    }

    # EXECUTES INSTALLATION OF ALL DOWNLOADED UPDATES
    $Installer = $UpdateSession.CreateUpdateInstaller()
    $Installer.Updates = $UpdatesToInstall
    Write-Host "Beginning installation of patches. This may take awhile..."
    $InstallationResult = $Installer.Install()

    # REUTRNS STATUS OF ALL UPDATES ATTEMPTED TO BE INSTALLED
    $cnt = 0
    Foreach ($Result in $Installer.Updates) {
        Switch ($InstallationResult.GetUpdateResult($cnt).ResultCode) {
            0 {Write-Host "$($Result.Title): Not Started" ; break}
            1 {Write-Host "$($Result.Title): In Progress" ; break}
            2 {Write-Host "$($Result.Title): Succeeded" ; break}
            3 {Write-Host "$($Result.Title): Succeeded with errors" ; break}
            4 {Write-Host "$($Result.Title): Failed" ; break}
            5 {Write-Host "$($Result.Title): Process stopped before completing" ; break}
        }
        $cnt++
    }

    # RETURNS TO MAIN MENU AFTER A PAUSE SO RESULTS CAN BE EASILY VIEWED
    Write-Host -ForegroundColor Yellow "Returning to main menu..."

    Start-Sleep -Seconds 3

    sc_Create-MainMenu
}

################################################################ LOGOFF ################################################################
function sc_Logoff (

)
{
    logoff
}

################################################################ RESTART ###############################################################
function sc_Restart (

)
{
    Restart-Computer -Force
}

############################################################### SHUTDOWN ###############################################################
function sc_Shutdown (

)
{
    Stop-Computer -Force
}

################################################################# EXIT #################################################################
function sc_Exit (

)
{
    CMD
}

########################################################### MAIN SCRIPT BODY ###########################################################

# SETS WINDOW AND BUFFER SIZE
$Width = 95
$Buffer = New-Object -TypeName System.Management.Automation.Host.Size ($Width,3000)
$Window = New-Object -TypeName System.Management.Automation.Host.Size ($Width,($Host.UI.RawUI.MaxWindowSize.Height * .7))
$Host.UI.RawUI.WindowSize = $Window
$Host.UI.RawUI.BufferSize = $Buffer

# INITIATES CORE FUNCTION
sc_Create-MainMenu