<# .SYNOPSIS Removes the BIOS admin (setup) password from a Dell PC with the Dell Command | PowerShell Provider. .DESCRIPTION Loads the DellBIOSProvider module, confirms an admin password is set, clears it, and reports the admin and system password state before and after, so you can see if the model cleared anything else along with it. The current admin password comes in as a SecureString or from a Configuration Manager task sequence variable at runtime. It is never stored in the script. Exit codes: 0 = cleared, not set, or not a Dell; 1 = the BIOS refused the change; 2 = provider module missing; 3 = no password supplied. .PARAMETER CurrentPassword The admin password that's set today. .PARAMETER PasswordVariable Task sequence variable to read the password from when -CurrentPassword isn't given. .EXAMPLE .\Clear-DellAdminPassword.ps1 -CurrentPassword (Read-Host -AsSecureString 'Current BIOS admin password') .EXAMPLE .\Clear-DellAdminPassword.ps1 -PasswordVariable BIOSAdminPassword #> [CmdletBinding(SupportsShouldProcess)] param( [securestring]$CurrentPassword, [ValidateNotNullOrEmpty()][string]$PasswordVariable = 'BIOSAdminPassword' ) function Get-TSSecret { param([string]$Name) try { $ts = New-Object -ComObject Microsoft.SMS.TSEnvironment -ErrorAction Stop } catch { return $null } $value = $ts.Value($Name) if ([string]::IsNullOrEmpty($value)) { return $null } ConvertTo-SecureString -String $value -AsPlainText -Force } function Import-DellProvider { if (Get-Module -ListAvailable -Name DellBIOSProvider) { Import-Module DellBIOSProvider -ErrorAction Stop; return } # Fall back to a copy shipped in the package (Save-Module puts it in a version subfolder). $bundled = Get-ChildItem -Path (Join-Path $PSScriptRoot 'DellBIOSProvider') -Filter 'DellBIOSProvider.psd1' -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 if ($bundled) { Import-Module $bundled.FullName -ErrorAction Stop; return } throw 'DellBIOSProvider not found. Install it, or copy the module folder into the package next to this script.' } function Get-PasswordState { # Returns 'True', 'False', or 'Unknown' if this model doesn't expose the attribute. param([string]$Attribute) $value = (Get-Item -Path "DellSmbios:\Security\$Attribute" -ErrorAction SilentlyContinue).CurrentValue if ($null -eq $value) { 'Unknown' } else { "$value" } } $result = [ordered]@{ ComputerName = $env:COMPUTERNAME; Status = '' AdminBefore = ''; SystemBefore = ''; AdminAfter = ''; SystemAfter = ''; Detail = '' } $manufacturer = (Get-CimInstance -ClassName Win32_ComputerSystem).Manufacturer if ($manufacturer -notlike 'Dell*') { $result.Status = 'NotApplicable'; $result.Detail = "Manufacturer is '$manufacturer'." [pscustomobject]$result; exit 0 } try { Import-DellProvider } catch { $result.Status = 'Failed'; $result.Detail = $_.Exception.Message; [pscustomobject]$result; exit 2 } $result.AdminBefore = Get-PasswordState -Attribute 'IsAdminPasswordSet' $result.SystemBefore = Get-PasswordState -Attribute 'IsSystemPasswordSet' if ($result.AdminBefore -eq 'False') { $result.Status = 'NotSet'; $result.AdminAfter = 'False'; $result.SystemAfter = $result.SystemBefore [pscustomobject]$result; exit 0 } if (-not $CurrentPassword) { $CurrentPassword = Get-TSSecret -Name $PasswordVariable } if (-not $CurrentPassword) { $result.Status = 'Failed'; $result.Detail = "No password given and task sequence variable '$PasswordVariable' is empty or unavailable." [pscustomobject]$result; exit 3 } $exitCode = 0 if ($PSCmdlet.ShouldProcess($env:COMPUTERNAME, 'Remove the BIOS admin password')) { $plain = [System.Net.NetworkCredential]::new('', $CurrentPassword).Password try { Set-Item -Path 'DellSmbios:\Security\AdminPassword' -Value '' -Password $plain -ErrorAction Stop $result.Status = 'Cleared' } catch { # Nine times out of ten this is a wrong password. $result.Status = 'Failed'; $result.Detail = $_.Exception.Message; $exitCode = 1 } finally { $plain = $null } } else { $result.Status = 'WhatIf' } $result.AdminAfter = Get-PasswordState -Attribute 'IsAdminPasswordSet' $result.SystemAfter = Get-PasswordState -Attribute 'IsSystemPasswordSet' if ($result.SystemBefore -eq 'True' -and $result.SystemAfter -eq 'False') { Write-Warning 'The system (power-on) password was cleared along with the admin password on this model.' } [pscustomobject]$result exit $exitCode