Set-LenovoBIOSSetting

 


[CmdletBinding()]
Param ()

##*=============================================
##* VARIABLE DECLARATION
##*=============================================
#region VariableDeclaration

# Start here

#endregion VariableDeclaration
##*=============================================
##* END VARIABLE DECLARATION
##*=============================================

##*=============================================
##* FUNCTION LISTINGS
##*=============================================
#region FunctionListings

#region Function Set-LenovoBIOSSetting
Function Set-LenovoBIOSSetting
    {
        [cmdletbinding(SupportsShouldProcess=$True)]
        Param
            (
                [Parameter(Mandatory=$false,ValueFromPipelineByPropertyName)]
                    [string[]]$ComputerName = $env:computername,

                [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName)]
                    [string]$Setting,

                [Parameter(Mandatory=$true)]
                [Alias('NewValue')]
                    [string]$Value,

                [Parameter(Mandatory=$false)]
                [Alias('Password')]
                    [string]$Credential,

                [Parameter(Mandatory=$false)]
                [ValidateSet('ascii','scancode')]
                [Alias('Encoding')]
                    [string]$PasswordEncoding = 'ascii',

                [Parameter(Mandatory=$false)]
                [ValidateSet('us','fr','gr')]
                    [string]$KeyboardLanguage = 'us',

                [Parameter(Mandatory=$false)]
                    [switch]$SkipCheck = $false,

                [Parameter(Mandatory=$false)]
                    [switch]$Commit,

                [Parameter(Mandatory=$false)]
                    [switch]$SaveForReal
            )

        Begin
            {
                [string]$Setting = $Setting.ToString().Trim()
                [string]$Value = $Value.ToString().Trim()

                if($Credential)
                    {
                        if($PasswordEncoding -eq 'ascii')
                            {
                                [string]$AuthenticationBits = $Credential + ',' + $PasswordEncoding + ',' + $KeyboardLanguage
                            }
                        else
                            {
                                [string]$AuthenticationBits = $Credential + ',' + $PasswordEncoding
                            }

                        Write-Host "AuthenticationBits [$AuthenticationBits]"
                    }
            }

        Process
            {
                foreach($Computer in $ComputerName)
                    {
                        Remove-Variable DNSLookupError,PingResult -ErrorAction SilentlyContinue

                        if(!(Resolve-DnsName -Name $Computer -ErrorAction SilentlyContinue -ErrorVariable DNSLookupError))
                            {
                                Switch -Wildcard ($DNSLookupError)
                                    {
                                        '*DNS name does not exist'
                                            {
                                                Write-Host "ERROR: NO DNS RECORD FOR [$Computer]: $_" -ForegroundColor Red
                                                Continue
                                            }

                                        default
                                            {
                                                Write-Host "ERROR: AN UNKNOWN ERROR OCCURRED TRYING TO CONNECT TO MACHINE [$Computer]: $_" -ForegroundColor Red
                                                Continue
                                            }
                                    }
                                continue
                            }
                        else
                            {
                                $PingResult = (New-Object System.Net.NetworkInformation.Ping).Send($Computer,1000).Status.ToString()
                                if($PingResult -ne 'Success')
                                    {
                                        Switch($PingResult)
                                            {
                                                'Success'
                                                    {
                                                        # Machine is online - good
                                                    }

                                                'TimedOut'
                                                    {
                                                        Write-Host "WARNING: Unable to connect to machine [$Computer] because it is offline: $_" -ForegroundColor Gray
                                                        Continue
                                                    }

                                                default
                                                    {
                                                        Write-Host "ERROR: AN UNKNOWN ERROR OCCURRED TRYING TO CONNECT TO MACHINE [$Computer]: $_" -ForegroundColor Red
                                                        Continue
                                                    }
                                            }
                                        continue
                                    }
                            }

                        Write-Host "Attempting to set [$Setting] to [$Value]"

                        if($SkipCheck -eq $false)
                            {
                                # Validate Setting - Part 1: Ensure this is a legitimate setting in the BIOS
                                $CurrentSettings = Get-LenovoBIOSSetting -ComputerName $Computer -Setting $Setting
                                Write-Verbose "CurrentSettings [$CurrentSettings]"
                                if([string]::IsNullOrEmpty($CurrentSettings)) { throw "ERROR 110: ERROR: INVALID SETTING SPECIFIED: [$Setting] ON [$Computer]" }

                                # Validate Setting - Part 2: Ensure an 'exact' BIOS setting was specified like 'USB Port 1' not 'USB%' which could match several.
                                if(@($CurrentSettings).Count -gt 1) { throw "ERROR 115: ERROR: SETTING [$Setting] RETURNED TOO MANY MATCHES DURING SETTING VALIDATION CHECK ON [$Computer]: [$($CurrentSettings.Setting -join ', ')]" }

                                # Validate Setting - Part 3: Use the returned setting name because the Lenovo_SetBiosSetting class is case SeNsItIvE whereas the Lenovo_BiosSetting isn't.
                                if($Setting -cne $CurrentSettings.Setting) { $Setting = $CurrentSettings.Setting }
                                Write-Verbose "Setting [$Setting]"
                                Write-Verbose "CurrentSettings.ValidValues [$($CurrentSettings.ValidValues)]"

                                # Validate New Value - Part 1: If the Value contains 'Show Only' then it's not a setting we can adjust
                                if($CurrentSettings.ValidValues -like 'ShowOnly: *')
                                    {
                                        Write-Verbose "Is not an editable setting"
                                        throw "ERROR 120: SETTING [$Setting] ON [$Computer] IS NOT AN EDITABLE ONE"
                                    }
                                # Validate New Value - Part 1: If the Value contains : it's probably BootOrder which accepts multiple values
                                elseif($Value.IndexOf(':') -gt 0)
                                    {
                                        # Split on : and verify that each setting exists in $CurrentSettings.ValidValues
                                        Write-Verbose "has : $($CurrentSettings.ValidValues)[$($CurrentSettings.ValidValues.Count)]"
                                        foreach($SubValue in $($Value -split ':'))
                                            {
                                                if(@($CurrentSettings.ValidValues -split ',') -inotcontains $SubValue)
                                                    {
                                                        throw "ERROR 120: INVALID VALUE SPECIFIED [$Value] FOR SETTING [$Setting] ON [$Computer] - IT MUST BE ONE OF: [$($CurrentSettings.ValidValues)]"
                                                    }
                                            }
                                    }
                                elseif($($CurrentSettings.ValidValues -split ',') -inotcontains $Value)
                                    {
                                        # Validate New Value - Part 2: If the ValidValues does NOT contain the user supplied value, then the user entered an invalid value.
                                        throw "ERROR 120: INVALID VALUE SPECIFIED [$Value] FOR SETTING [$Setting] ON [$Computer] - IT MUST BE ONE OF: [$($CurrentSettings.ValidValues)]"
                                    }
                                else
                                    {
                                        # Validate New Value - Part 3: If the ValidValues DOES contain the user supplied value, then we evaluate further
                                        # If the user supplied value contains a comma, we don't validate any further - it's just a tad complex to handle intelligently and I don't want to deal with it right now
                                        # If the user supplied value does NOT contain a comma, we use the value returned by Get-LenovoBIOSSetting because it returns valid values in the proper casing for use with the Lenovo_SetBiosSetting class.
                                        if($Value -notlike ',') { foreach($ValidValue in $($CurrentSettings.ValidValues -split ',')) { If($ValidValue -ieq $Value) { $Value = $ValidValue; break } } }
                                    }

                                if($CurrentSettings.CurrentValue -eq $Value)
                                    {
                                        Write-Warning "No change made for [$Setting] on [$Computer] because new and current values are identical:`r`nCurrent Value: [$($CurrentSettings.CurrentValue)]`r`nUpdated Value: [$Value]`r`n"
                                        return
                                    }

                                $Action = "from [$($CurrentSettings.CurrentValue)] to [$Value] on [$Computer]"
                            }
                        else { $Action = "to [$Value] on [$Computer]" }

                        if($PSCmdlet.ShouldProcess("Setting [$Setting] on [$Computer] $Action"))
                            {
                                If($Commit -eq $true)
                                    {
                                        $OriginalEAP = $ErrorActionPreference
                                        $ErrorActionPreference = 'Stop'

                                        Try
                                            {
                                                if($Credential) { $SetResult = (gwmi -class Lenovo_SetBiosSetting -namespace root\wmi -ComputerName $Computer -ErrorAction Stop).SetBiosSetting("$Setting,$Value,$AuthenticationBits") }
                                                else { $SetResult = (gwmi -class Lenovo_SetBiosSetting -namespace root\wmi -ComputerName $Computer -ErrorAction Stop).SetBiosSetting("$Setting,$Value") }
                                                $ErrorActionPreference = $OriginalEAP

                                                if($SaveForReal -eq $true)
                                                    {
                                                        if($Credential) { Save-LenovoBIOSSetting -Credential $Credential -PasswordEncoding $PasswordEncoding -KeyboardLanguage $KeyboardLanguage -ComputerName $Computer -Commit }
                                                        else { Save-LenovoBIOSSetting -ComputerName $Computer -Commit }
                                                    }
                                            }
                                        Catch
                                            {
                                                $ErrorActionPreference = $OriginalEAP
                                                throw "ERROR 125: FAILED TO SET BIOS SETTING [$Setting] TO [$Value] ON [$Computer]: $_"
                                            }

                                        Switch($SetResult.return)
                                            {
                                                'Success'
                                                    {
                                                        Write-Output "$($SetResult.Return)fully set [$Setting] $Action!"
                                                        if($SkipCheck -eq $false) { Get-LenovoBIOSSetting -ComputerName $Computer -Setting $Setting | Select ComputerName,Setting,CurrentValue | ft -a }
                                                        Write-Output "Don't forget to truly commit your configuration changes via Save-LenovoBIOSSetting on $Computer!`r`n`r`n"
                                                    }

                                                'Access Denied'
                                                    {
                                                        if($Credential)
                                                            {
                                                                throw "ERROR 5: FAILED TO SET [$Setting] TO [$Value] ON [$Computer]: [$($SetResult.Return)]`r`nERROR HINT: The Supervisor Password was either incorrect or the issue lies with the Password Encoding or Keyboard Language."
                                                            }
                                                        else
                                                            {
                                                                throw "ERROR 5: FAILED TO SET [$Setting] TO [$Value] ON [$Computer]: [$($SetResult.Return)]`r`nERROR HINT: If a Supervisor Password is set, you must specify the -Credential, -PasswordEncoding and -KeyboardLanguage switches."
                                                            }
                                                    }

                                                default
                                                    {
                                                        $FailureReason = "ERROR: FAILED TO SET [$Setting] TO [$Value] ON [$Computer]: [$($SetResult.Return)]`r`nERROR HINT: Firmware is"
                                                        if (Confirm-SecureBootUEFI -ErrorAction SilentlyContinue) { $FailureReason = $FailureReason + " UEFI" } else { $FailureReason = $FailureReason + " BIOS" }
                                                        $FailureReason =  $FailureReason + " and you //may// first need to toggle either [OS Optimized Defaults] and/or [SecureBoot'] as these lock and/or hide certain BIOS settings depending on the current boot firmware."
                                                        throw "ERROR 135: $FailureReason"
                                                    }
                                            }
                                    }
                                Else { Write-Warning "Not changing WMI/BIOS [$Setting] $Action`: Commit is false [$Commit]`r`n" }
                            }
                    }
            }

        End {  }
    }
#endregion Function Set-LenovoBIOSSetting

#endregion FunctionListings
##*=============================================
##* END FUNCTION LISTINGS
##*=============================================

##*=============================================
##* SCRIPT BODY
##*=============================================
#region ScriptBody

#Set-LenovoBIOSSetting -Setting 'WakeOnLan' -Value 'ACOnly'

#Set-LenovoBIOSSetting -Setting 'WakeOnLan' -Value 'ACOnly' -Commit

#Set-LenovoBIOSSetting -Setting 'WakeOnLan' -Value 'ACOnly' -Commit -Credential Passw0rd -PasswordEncoding ascii -KeyboardLanguage us

#Set-LenovoBIOSSetting -Setting 'WaKeonLaN' -Value 'enable' -Commit

#Set-LenovoBIOSSetting -Setting 'WakeOnLan' -Value 'DiSaBle' -Commit

#Set-LenovoBIOSSetting -Setting 'Boot Up Num-Lock Status' -Value 'On'

#Set-LenovoBIOSSetting -Setting BluetoothAccess -Value Disable

#endregion ScriptBody
##*=============================================
##* END SCRIPT BODY
##*=============================================
Advertisements