Thursday, December 5, 2019

Check/Set/Change/Clear HP BIOS Password with Powershell

# Check if password is set
Get-WmiObject -Namespace root/hp/InstrumentedBIOS -Class HP_BIOSSetting | Where-Object Name -eq "Setup Password").IsSet


# Set password
(Get-WmiObject -Namespace root/hp/InstrumentedBIOS -Class HP_BIOSSettingInterface).SetBIOSSetting("Setup Password","<utf-16/>" + "NewPassword","<utf-16/>")


# Change password
(Get-WmiObject -Namespace root/hp/InstrumentedBIOS -Class HP_BIOSSettingInterface).SetBIOSSetting("Setup Password","<utf-16/>" + "NewPassword","<utf-16/>" + "OldPassword")


# Clear password
(Get-WmiObject -Namespace root/hp/InstrumentedBIOS -Class HP_BIOSSettingInterface).SetBIOSSetting("Setup Password","<utf-16/>","<utf-16/>" + "OldPassword")

CI to Check HP BIOS settings

# Check-BIOSSetting.ps1
# by Mark Randol - randoltech.blogspot.com
# Checks the setting for the BIOS item in $BIOSItem
# Against the desired state in $DesiredValue
# If good returns the exact text in $DesiredValue
# If bad returns the string from BIOS
# If item is not found retruns $BIOSItem not found in BIOS settings.
# If script properly runs but is indeterminent then returns Error (should never happen)


$BIOSItem = "Boot Mode"
$DesiredValue = "*UEFI Native (Without CSM)"
$OutputString = "Error"
$ItemValue = (Get-WmiObject -Namespace root\HP\InstrumentedBIOS -Class HP_BIOSEnumeration | Where-Object Name -eq $BIOSItem).Value
if ($ItemValue) {
    $CheckString = (($DesiredValue.Replace("*","\*")).Replace("(","\(")).Replace(")","\)")
    if ($ItemValue -match $CheckString) {
        $OutputString = $DesiredValue
    }
    else {
        $OutputString = $ItemValue
    }
}
else {
    $OutputString = "$BIOSItem not found in BIOS settings."
}
Write-Output $OutputString



----------------------------------

Remediation Script:

(Get-WmiObject -Namespace root\HP\InstrumentedBIOS -Class HP_BIOSSettingInterface).SetBIOSSetting("TPM Device","Available","<utf-16/>" + "YourBIOSPasswordHere")

Thursday, November 21, 2019

Extracting Microsoft Surface Drivers

For the Surface Pro 6 I ended up downloading four .msi files and needed to extract them to get the drivers for import into SCCM.  I wrote this little PowerShell script to iterate through all four and extract them for me complete with logs in case anything went wrong.  Figured I would post it here in case anyone else finds it useful.


#Extract-MSIFiles.PS1
#Creates folders for each .msi and extracts contents into the folders
#By Mark Randol - randoltech.blogspot.com

$BasePath = "C:\Users\me\Downloads\Drivers\Surface Pro 6 1796 Commercial"

Start-Transcript -Path "$BasePath\Extract-MSIFiles.log" -Force

$SearchPath = $BasePath + "\*"
$MSIFiles = Get-ChildItem $SearchPath -Include *.msi
foreach ($File in $MSIFiles) {
    $FileName = $File.Name
    New-Item -Path "$BasePath" -Name $File.BaseName -ItemType "Directory"
    $ExtractFolder = $BasePath + "\" + $File.BaseName
    $ArguementString = "/a ""$BasePath" + "\" + "$Filename"" targetdir=""$ExtractFolder"" /l*v ""$BasePath\$FileName.log"" /qn"
    Start-Process -FilePath "msiexec.exe" -ArgumentList $ArguementString
    Wait-Process -Name msiexec -Timeout 90
}

Stop-Transcript



-Enjoy

Wednesday, November 6, 2019

Detection Method for an APPX package

None of the standard SCCM application detection methods work for APPX packages.  For an APPX package use "Use a custom script to detect the presence of this deployment type" and this command line as the script (modify for the package name and version number that you need obviously):

if ([version]((Get-AppxPackage *AppUp.ThunderboltControlCenter*).Version) -ge ([version]("1.41.648.5"))) { write-output $true }

Enjoy!

Tuesday, October 1, 2019

A little script to back up your BitLocker keys to Active Directory

If you are using Azure AD then change Backup-BitLockerKeyProtector to BackupToAAD-BitLockerKeyProtector

# Backup-BitlockerKeys.ps1
# by Mark Randol
# randoltech.blogspot.com
# This script iterates through all of your possibly encryptable drives
# and if they are encrypted, backs up the keys to Active Directory.

$PossibleDrives = Get-BitLockerVolume
foreach ($Drive in $PossibleDrives)
{
    $DriveLetter = $Drive.MountPoint
    $Protectors = ((Get-BitLockerVolume -MountPoint $DriveLetter).KeyProtector)
    foreach ($Protectors in $Protectors) {
        $ProtectorID = $Protector.KeyProtectorId
        $ProtectorType = $Protector.KeyProtectorType
        if ($ProtectorType -eq "RecoveryPassword") {
            Backup-BitLockerKeyProtector -MountPoint $DriveLetter -KeyProtectorId $ProtectorID -Verbose
        }
    }
}

Wednesday, September 11, 2019

ThunderBolt Security Configuration Item for SCCM

This comes out of a need to secure ThunderBolt PCIe against DMA attacks while still allowing users (rather than just administrators) to approve attached devices.  This attack is very serious as it can done on a machine that is in sleep or hibernate.  As we know most laptop users never turn their computers off, they just close the lid.  The computer goes to sleep and everything it was doing gets stored in memory.  DMA = Direct Memory Access, so someone comes along, plugs in a malicious device and grabs everything stored in memory without even opening the lid of the computer.

Mitigation is two parts.  One part is BIOS configuration.  By default any modern ThunderBolt enabled computer will come with the BIOS set to require "User Approval" of any device that gets attached.  The problem is (in the operating system) that approval require that the user actually be an administrator not just any user.  That is not a usable solution in an enterprise environment.  It also requires that the device(s) be approved every single time they are used.  So, let's say you have a Thunderbolt dock... an administrator has to come and approve it every time you dock your laptop.  That's just not workable.

So, we configure that BIOS to a newer standard, Secure Connect.  That allows the device to only require approval the first time it is used.  Unfortunately that approval still needs to be an administrator.

Finally we are to the point of my post.  Here are two scripts to create a configuration item to detect existence of ThunderBolt and remediate the registry so that normal users can approve device connections.

A tech said to me "I don't see how this is any different than setting the BIOS to No Security".  Well, as I explained to him, you must understand how the DMA attack works in this instance.  The attack happens by simply attaching a malicious device (USB Key, SD Card, whatever) to the machine and the machine accepts its DMA request.  This can happen even while the machine is in Sleep mode (no user interface).  So, the difference between this and no security is that a user must actually be logged in and active to approve the connection.  I can't just walk up to your machine while you are at lunch, plug in a USB key, and take everything that your OS has in memory away with me.  I would have to have a valid login to approve the connection.  The attack is a way around drive encryption.  Having a valid logon is a way around drive encryption so this method makes your machine as secure as a machine that does not have ThunderBolt at all, meaning that nobody can run this particular DMA without a valid logon.  Once someone has a valid logon, you have other mitigation that you need to have in place but that's a story for another time.

The first script, detection:
This script will detect the existence of the ThunderBolt registry branch.  If it doesn't exist then your machine doesn't have ThunderBolt (or at least doesn't have drivers for it which amounts to the same thing, you are not vulnerable to the DMA attack) so it is compliant.  If your machine does have the branch then it checks the AccessRule item to ensure that it is set to 1.  By default this item will either not exist (IBM Lenovo) or be set to 0 (HP).

Create a new CI of type Script.  I named mine "Win10 Core - ThunderBolt PCIe Security" to add it to my Win10 Core baseline.
   The Setting Type is Script.
   The Data Type is String.
   Here is the Discovery Script:

#Created by Mark Randol - randoltech.blogspot.com
#This script detects existence of teh Thunderbolt Service registry branch
#and the setting of the "Approval Level" item within it
#Non-existence of the branch = compliant
#Non-existence ApprovalLevel within the branch = noncompliant
#ApprovalLevel 1 = compliant
#Any other value for ApprovalLevel = noncompliant
 
if (Test-Path -Path "HKLM:SYSTEM\CurrentControlSet\Services\ThunderboltService\TbtServiceSettings") {
$OutString = (Get-ItemProperty "HKLM:SYSTEM\CurrentControlSet\Services\ThunderboltService\TbtServiceSettings").ApprovalLevel
}
else {
$OutString = "1"
}
Write-Output $OutString
Return $OutString

Here is the Remediation Script:

# Change Thundebolt security approval level to allow users
# to accept Thundebolt equpiment without being local admin
# Originally created by Jens-Kristian Myklebust <jensmyklebust@outlook.com>
# Modified to work as an SCCM CI by Mark Randol - randoltech.blogspot.com

$logfile = "$env:windir\ccm\logs\Install_Fix-ThunderboltRegistry.log"
Start-Transcript -Path $logfile -force #start logging

$RegistryKey = "SYSTEM\CurrentControlSet\Services\ThunderboltService\TbtServiceSettings" #Registry key to modify
$RegistryPath = "HKLM:\$RegistryKey" #Full path to the registry key
$ServiceName = "AdobeARMservice" #"ThunderboltService"

#Set the registry Value
if ((Test-Path -Path $RegistryPath)){ #make sure we're on a machine that actually has the key
       
    $TheService = Get-Service -Name $ServiceName
    #Stop the Thunderbolt Service
    if (($TheService)) {
        $TheService | Stop-Service -Confirm:$false -Verbose
        $TheService.WaitForStatus('Stopped')
    }

    $ACLinfo = Get-Acl "HKLM:\$RegistryKey" #Store original ACL info

    #Give "SYSTEM" user full access to registry key
        $RegKeyDotNETItem = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($RegistryKey,[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::ChangePermissions)
        $DotNET_ACL = $RegKeyDotNETItem.GetAccessControl()
        $DotNET_AccessRule = New-Object System.Security.AccessControl.RegistryAccessRule ("System","FullControl","Allow") -Verbose
        $DotNET_ACL.SetAccessRule($DotNET_AccessRule)
        $DotNET_AccessRule = New-Object System.Security.AccessControl.RegistryAccessRule ($env:USERNAME,"FullControl","Allow") -Verbose
        $DotNET_ACL.SetAccessRule($DotNET_AccessRule)
        $RegKeyDotNETItem.SetAccessControl($DotNET_ACL)

    #check for existence of the property in the key
    #if the property doesn't exist, create it
    if (!((Get-ItemProperty $RegistryPath).ApprovalLevel)){
        New-ItemProperty -Path $RegistryPath -Name 'ApprovalLevel' -Value 1 -PropertyType DWORD -Force -Verbose
    }
    #if the property does exist, change it to the correct value
    else {
        Set-ItemProperty -Path $RegistryPath -Name 'ApprovalLevel' -Value 1 -Verbose
    }

    #Put the security back on the registry
    $RegKeyDotNETItem.SetAccessControl($ACLinfo)

    #Restart service
    if (($TheService)) {
        $TheService | Start-Service -Confirm:$false -Verbose
        $TheService.WaitForStatus('Running')
    }
#>
}
Stop-Transcript #stop logging

Create a compliance rule, I named mine "ApprovalLevel" as that is the registry item that we are dealing with.  Here are the settings for it:
Value = 1
Check the checkbox "Run the specified remediation script when this setting is noncompliant"
Check the checkbox "Report noncompliance if the setting instance is not found"

From there, add your new CI to a baseline, deploy the baseline at your (suspected) Thunderbolt enabled machines and it should set the setting for you.

With BIOS set to SecureConnect and this registry entry your users should be able to approve devices to connect to their computer and will only need to do it the first time similar to pairing a Bluetooth device.

- Enjoy

Wednesday, April 17, 2019

File Rename Script

Just a quick script to rename all files in a folder:

$theFolder = "\\server.domain.com\share\folder"
$theFiles = (Get-ChildItem -Path $myFolder -Filter Prefix*.type ).Name
foreach ($File in $myFiles)
{
    $FullPathFileName = $theFolder + "\" + $File
    $newName = ($File).Replace(" ","_")
    Rename-Item -Path $FullPathFileName -NewName $newName -Force
}

Wednesday, February 20, 2019

MBR to GPT conversion

This will run the MBR2GPT tool's validation before attempting conversion:

@ECHO OFF
MBR2GPT.EXE /validate
IF %ERRORLEVEL% NEQ 0 GOTO ERROR

MBR2GPT.EXE /convert
IF %ERRORLEVEL% NEQ 0 GOTO ERROR

:ERROR
EXIT /B %ERRORLEVEL%

Tuesday, February 19, 2019

Decrypt all of the BitLocker encrypted drives

I needed Bitlocker actually OFF, not just suspended, so here's the script that I used to ensure that it got there:


For Win10:
-----------------------------------
#Decrypt-BitlockerDrives.PS1
#Script by Mark Randol
#randoltech.blogspot.com
#This script finds all local encrypted volumes and decrypt them.
#Does not exit until decryption is completed.

CLS
Clear-BitLockerAutoUnlock #Since we're decrypting all of the drives, and any Auto-Unlock protectors are tied to the encryption on the system drive, these need to go away.

$PossibleDrives = (Get-BitLockerVolume).MountPoint  #get all of the drives that could possibly be encrypted

#Disable-BitLocker -MountPoint $PossibleDrives #start all of the discovered drives decrypting in parallel

foreach ($DriveLetter in $PossibleDrives) {  #step through the drives in series to ensure they get decrypted
    [int]$LastEncryptPercent = 100  #This variable stores the most recent change to the encryption percentage 
    [int]$CurrentEncryptPercent = 2  #This variable stores the current check that we are making on the encryption level
    #If these two variables are equal we know that no progress has been made in decryption since the last check
    do { #check the encryption level of the drive every five minutes until it is fully decrypted
        $CurrentEncryptPercent = (Get-BitLockerVolume -MountPoint $DriveLetter).EncryptionPercentage
        if ($CurrentEncryptPercent -ne $LastEncryptPercent) { #if the percentage of encryption has changed since the last check then write that to the output
            $OutputString = "Drive " + $DriveLetter + $CurrentEncryptPercent.ToString() + "% encrypted"
            Write-Output $OutputString
            $LastEncryptPercent = (Get-BitLockerVolume -MountPoint $DriveLetter).EncryptionPercentage #Since the encryption percentage has changed, lets store the this percentage as our "last" (most recent)
        }
        Start-Sleep -Seconds 300  #wait five minutes before checking again
    }
    while ($CurrentEncryptPercent -ne 0)
}
Write-Output (Get-BitLockerVolume)

---------------------------------



For Win7
#Decrypt-BitlockerDrives.PS1
#Script by Mark Randol
#randoltech.blogspot.com
#
#This script will list out all of the encryptable volumes on the local machine and decrypt them
#Do not exit until decryption is completed.
#there are simpler ways to do this with modern Powershell commands (Get-BitLockerVolume for example)
#but those methods do not work with a native Windows 7 PowerShell environment so this was
#developed to help facilitate Windows 7 to Windows 10 migration.
$WMINameSpace = "root\CIMv2\Security\MicrosoftVolumeEncryption"
$WMIClass = "Win32_EncryptableVolume"
$BitLockerDrives = (Get-Wmiobject -Namespace $WMINameSpace -Class $WMIClass -ComputerName $env:COMPUTERNAME).DriveLetter
foreach ($LockedDrive in $BitLockerDrives) {
    $Status = (Get-Wmiobject -Namespace $WMINameSpace -Class $WMIClass -ComputerName $env:COMPUTERNAME -Filter “DriveLetter=""$LockedDrive""”).ConversionStatus
    if ($Status -ne 0) {
        if ($Status -eq 1) {
            Invoke-Command {manage-bde.exe -off C:}
        }
}
foreach ($LockedDrive in $BitLockerDrives) {
    $Status = (Get-Wmiobject -Namespace $WMINameSpace -Class $WMIClass -ComputerName $env:COMPUTERNAME -Filter “DriveLetter=""$LockedDrive""”).ConversionStatus
    if ($Status -ne 0) {
        do {
            Start-Sleep 15
            $Status = (Get-Wmiobject -Namespace $WMINameSpace -Class $WMIClass -ComputerName $env:COMPUTERNAME -Filter “DriveLetter=""$LockedDrive""”).ConversionStatus
        }
        until ($Status -eq 0)
    }
}
{Exit $LASTEXITCODE}


Wednesday, January 16, 2019

Script to stamp the registry with your OSD variables


# Script by Mark Randol
# randoltech.blogspot.com

$registryPath = "HKLM:\Software\MyCompany\SCCM Operating System Deployment"
[String[]]$OSDVariables = "OSArchitecture","OSDAnswerFilePath","OSDComputerName","OSDImagePackageId","OSDImageVersion","OSDTargetSystemDrive","OSDTargetSystemParition","OSDTargetSystemRoot","OSVersionNumber","_OSDOSImagePackageId","_OSDTargetSystemRoot","_SMSTSAdvertID","_SMSTSAssignedSiteCode","_SMSTSBootImageID","_SMSTSBootMediaPackageID","_SMSTSLaunchMode","_SMSTSLogPath","_SMSTSMachineName","_SMSTSMediaType","_SMSTSOrgName","_SMSTSPackageID","_SMSTSPackageName","_SMSTSSiteCode","_SMSTSStandAloneMedia","_SMSTSSupportUnknownMachines","_SMSTSUserStatePath"

if (!(Test-Path $registryPath)) { New-Item -Path $registryPath -Force | Out-Null }

$InstallDate = Get-Date
New-ItemProperty -Path $registryPath -Name "OSInstallDateTime" -Value $InstallDate -PropertyType STRING -Force | Out-Null

$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
foreach ($OSDVariableName in $OSDVariables)
{
  $OSDVariableValue = $tsenv.Value($OSDVariableName)
  New-ItemProperty -Path $registryPath -Name $OSDVariableName -Value $OSDVariableValue -PropertyType STRING -Force | Out-Null
}

Thursday, January 10, 2019

Command lines for creating a bootable USB thumb drive

Command lines for creating a bootable USB thumb drive:

diskpart
list disk
sel dis #
clean
create par pri
sel par 1
format fs=ntfs quick <--- for Legacy
format fs=fat32 quick <--- for UEFI
act
exit