Wes Ellis./ a personal notebook
Technology. Stories. Side projects.
A few things worth writing down.
← Back to Script Library

SCRIPT LIBRARY · POWERSHELL

Remove a Dell BIOS Admin Password with PowerShell and ConfigMgr

Clear the BIOS setup password on Dell PCs and see exactly what changed, with the password supplied at runtime instead of sitting in a package.

AT A GLANCEClear-DellAdminPassword.ps1
What it does
Removes the BIOS admin (setup) password from a Dell PC and reports the admin and system password state before and after. The current password arrives as a SecureString or a hidden task sequence variable.
Requires
  • Windows PowerShell 5.1
  • DellBIOSProvider module (Dell Command | PowerShell Provider), installed or shipped in the package
  • Microsoft Visual C++ Redistributable
Permissions
Local administrator or SYSTEM on the target PC, plus the current BIOS admin password
Runs on
Dell business PCs on Windows 10/11
Tested
Parse-checked and dry-run with mocked Dell provider cmdlets in PowerShell 7.4

There are a few good reasons to take the admin password off a Dell. The machine's being sold or returned at the end of a lease. It's moving to a group that manages BIOS settings a different way. Or you're about to set a new one and the model is fussy about changing it in place.

The old version of this post had a bigger problem than style: the script defined a function and never called it, so the package ran, reported success, and changed nothing. It also had the current password typed right into the script. This rewrite actually does the job, takes the password at runtime, and tells you what the BIOS looks like afterwards.

That last part matters more than you'd think. On some models, clearing the admin password takes the system (power-on) password with it. The script reports both before and after, and warns you when that happens, so you're not surprised by it later.

Clear-DellAdminPassword.ps1Download
<#
.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

Parameters

ParameterTypeDefaultWhat it's for
-CurrentPasswordsecurestring—The admin password that's set today. Leave it off in a task sequence and the script reads the variable below.
-PasswordVariablestringBIOSAdminPasswordTask sequence variable holding the current admin password. Keep it hidden.
-WhatIfswitch—Reads the current state and shows what it would change, without changing it.

Run it

One machine, password typed at the prompt.

.\Clear-DellAdminPassword.ps1 -CurrentPassword (Read-Host -AsSecureString 'Current BIOS admin password')

In a task sequence, reading the hidden BIOSAdminPassword variable.

powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\Clear-DellAdminPassword.ps1

See the before state without touching anything.

.\Clear-DellAdminPassword.ps1 -CurrentPassword (Read-Host -AsSecureString 'Current BIOS admin password') -WhatIf

A few machines at once, collecting the results.

$pw = Read-Host -AsSecureString 'BIOS admin password'; Invoke-Command -ComputerName PC-0142, PC-0187 -FilePath .\Clear-DellAdminPassword.ps1 -ArgumentList $pw | Export-Csv .\bios-admin-clear.csv -NoTypeInformation

What you'll see

Example outputvalues are illustrative
WARNING: The system (power-on) password was cleared along with the admin password on this model.

ComputerName : PC-0142
Status       : Cleared
AdminBefore  : True
SystemBefore : True
AdminAfter   : False
SystemAfter  : False
Detail       :

How it works

  1. Bail out politely on non-Dells. Exit 0 with NotApplicable, so you can target a mixed collection.
  2. Load DellBIOSProvider. Installed copy first, then a copy shipped in the package folder.
  3. Record the before picture. IsAdminPasswordSet and IsSystemPasswordSet under DellSmbios:\Security. Models that don't expose one show Unknown instead of breaking the script.
  4. Stop early if there's no admin password. Nothing to clear, exit 0.
  5. Clear it. Set-Item -Path DellSmbios:\Security\AdminPassword -Value '' -Password <current>. The SecureString is only converted to plain text for that one call.
  6. Record the after picture and warn if the system password disappeared too. Exit codes are 0 (done or nothing to do), 1 (BIOS refused), 2 (provider missing), 3 (no password supplied).

Packaging it

Same pattern as any BIOS script: a package with no program, used from a task sequence.

$SiteCode    = 'ABC'
$SourceShare = '\\sccm01\Sources\Scripts'
$DPGroup     = 'All DPs'

$source = Join-Path $SourceShare 'Clear-DellAdminPassword'
New-Item -ItemType Directory -Path $source -Force | Out-Null
Copy-Item .\Clear-DellAdminPassword.ps1 -Destination $source
Save-Module -Name DellBIOSProvider -Path $source

Import-Module (Join-Path $env:SMS_ADMIN_UI_PATH '..\ConfigurationManager.psd1')
Push-Location "$($SiteCode):\"
New-CMPackage -Name 'Dell - Clear BIOS Admin Password' -Path $source | Out-Null
Start-CMContentDistribution -PackageName 'Dell - Clear BIOS Admin Password' -DistributionPointGroupName $DPGroup
Pop-Location

Then set BIOSAdminPassword as a hidden collection variable on the collection you deploy the task sequence to, and add a Run PowerShell Script step that calls the script from the package.

Take it further

  • Replace rather than remove. If the goal is a new password, Set-DellAdminPassword.ps1 changes it in one step without a window where the BIOS is wide open.
  • Clear the drive password too. For end-of-life machines, run the HDD password script first, while you still know the admin password is in place.
  • Inventory first. Run it with -WhatIf across a few test machines to see which models report Unknown before you plan the real deployment.

Things that'll trip you up

  • Keep the password out of the package. Anything inside the package is readable on the source share, every distribution point, and every client cache. Supply it at runtime from a hidden task sequence or collection variable, or skip scripting it entirely and let Dell Command | Configure export the change as a package with the password encrypted.
  • Removing it opens the BIOS to anyone with a keyboard. Boot order, Secure Boot, TPM, the lot. Do it for a reason, and if the machine's staying in service, set a new password in the same task sequence.
  • The system password may go with it. Behaviour differs by model and BIOS version. Check SystemAfter in the output before you assume users still get a power-on prompt.
  • Wrong passwords fail cleanly, but they fail. A machine with a different admin password than the one you supplied returns exit code 1 with the BIOS's error in Detail. Collect those from deployment status and handle them separately rather than retrying the same password.