5

For my purpose all I need to know is drive's BitLocker encryption status by its DOS path. Something like this:

enum DriveEncryptionStatus{
    Unprotected,
    Protected,
    Unknown
};

DriveEncryptionStatus = GetDriveBitlockerEncryptionStatus(L"C:\\");

I was able to find the Win32_EncryptableVolume class that unfortunately comes with this caveat:

To use the Win32_EncryptableVolume methods, the following conditions must be met: You must have administrator privileges.

Any idea how to do this without running as an administrator?

c00000fd
  • 20,994
  • 29
  • 177
  • 400

4 Answers4

7

The BitLocker status is available to any ordinary user in the shell. Windows obtains the status using the Windows Property System in the Win32 API to check the undocumented shell property System.Volume.BitLockerProtection. Your program will also be able to check this property without elevation.

If the value of this property is 1, 3, or 5, BitLocker is enabled on the drive. Any other value is considered off.

You can use the Win32 API to check this shell property. As a courtesy, I have ported my managed implementation from my other answer to a similar question.

#include <shlobj.h>
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "propsys.lib")

DriveEncryptionStatus getDriveEncryptionStatus(LPCWSTR parsingName)
{
    IShellItem2 *drive = NULL;
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    hr = SHCreateItemFromParsingName(parsingName, NULL, IID_PPV_ARGS(&drive));
    if (SUCCEEDED(hr)) {
        PROPERTYKEY pKey;
        hr = PSGetPropertyKeyFromName(L"System.Volume.BitLockerProtection", &pKey);
        if (SUCCEEDED(hr)) {
            PROPVARIANT prop;
            PropVariantInit(&prop);
            hr = drive->GetProperty(pKey, &prop);
            if (SUCCEEDED(hr)) {
                int status = prop.intVal;

                drive->Release();

                if (status == 1 || status == 3 || status == 5)
                    return DriveEncryptionStatus::Protected;
                else
                    return DriveEncryptionStatus::Unprotected;
            }
        }
    }

    if (drive)
        drive->Release();

    return DriveEncryptionStatus::Unknown;
}

int main()
{
    DriveEncryptionStatus status = getDriveEncryptionStatus(L"C:");
    return 0;
}
slypete
  • 5,538
  • 11
  • 47
  • 64
  • 1
    Thank you. I'll give it a try. Before I do though, do you know what those values: 1 thru 5 stand for? – c00000fd Nov 09 '17 at 01:07
  • 2
    Believe I found them in Microsoft.BitLocker.Structures.BitLockervolumeStatus in the Bitlocker powershell module: 0 - FullyDecrypted, 1: FullyEncrypted, 2: EncryptionInProgress, 3: DecryptionInProgress, 4: EncryptionSuspended, 5: DecryptionSuspended, 6: FullyEncryptedWipeInProgress, 7: FullyEncryptedWipeSuspended – Zerqent May 03 '18 at 12:24
  • since this is undocumented does anyone know if it still works in the builds of Windows 10 [Version 10.0.17763.973] and beyond? – Weej Jamal Feb 14 '20 at 05:32
  • To make the code work you have to add the following line above the function: enum class DriveEncryptionStatus { Protected, Unprotected, Unknown }; @Weej Jamal: The code runs on Windows 10 (19041). – Holger Schmeken Oct 04 '20 at 21:12
  • A Python implementation: `from win32com.propsys import propsys; bitlocker_status = propsys.SHGetPropertyStoreFromParsingName("C:").GetValue(propsys.PSGetPropertyKeyFromName("System.Volume.BitLockerProtection")).GetValue()` – Vynce Oct 13 '20 at 05:05
  • It seems very odd that this answer considers DecryptionInProgress and DecryptionSuspended as being encrypted. Why not FullyEncryptedWipeInProgress FullyEncryptedWipeSuspended as well? It doesn't seem very thought out. – drewish May 01 '23 at 16:42
  • @drewish just a natural effect of working without documentation. I'm glad that my contribution inspired the community to uncover more details about this property. – slypete May 10 '23 at 18:50
7

Building on this answer...

Values of System.Volume.BitLockerProtection determined empirically on Windows 10 1909 (10.0.18363.1082):

| System.Volume.      | Control Panel                    | manage-bde conversion     | manage-bde     | Get-BitlockerVolume          | Get-BitlockerVolume |
| BitLockerProtection |                                  |                           | protection     | VolumeStatus                 | ProtectionStatus    |
| ------------------- | -------------------------------- | ------------------------- | -------------- | ---------------------------- | ------------------- |
|                   1 | BitLocker on                     | Used Space Only Encrypted | Protection On  | FullyEncrypted               | On                  |
|                   1 | BitLocker on                     | Fully Encrypted           | Protection On  | FullyEncrypted               | On                  |
|                   1 | BitLocker on                     | Fully Encrypted           | Protection On  | FullyEncryptedWipeInProgress | On                  |
|                   2 | BitLocker off                    | Fully Decrypted           | Protection Off | FullyDecrypted               | Off                 |
|                   3 | BitLocker Encrypting             | Encryption In Progress    | Protection Off | EncryptionInProgress         | Off                 |
|                   3 | BitLocker Encryption Paused      | Encryption Paused         | Protection Off | EncryptionSuspended          | Off                 |
|                   4 | BitLocker Decrypting             | Decryption in progress    | Protection Off | DecyptionInProgress          | Off                 |
|                   4 | BitLocker Decryption Paused      | Decryption Paused         | Protection Off | DecryptionSuspended          | Off                 |
|                   5 | BitLocker suspended              | Used Space Only Encrypted | Protection Off | FullyEncrypted               | Off                 |
|                   5 | BitLocker suspended              | Fully Encrypted           | Protection Off | FullyEncrypted               | Off                 |
|                   6 | BitLocker on (Locked)            | Unknown                   | Unknown        | $null                        | Unknown             |
|                   7 |                                  |                           |                |                              |                     |
|                   8 | BitLocker waiting for activation | Used Space Only Encrypted | Protection Off | FullyEncrypted               | Off                 |
Vynce
  • 271
  • 3
  • 4
2

So after many failed attempts at trying to pull this off in C# I finally got to this. I'm still new to C++/C# development in general so if my answer is completely irrelevant please let me know. I'll withdraw

    public static string GetBitLockerStatus()           
    {
        Process process = new Process();
        process.StartInfo.FileName = "powershell.exe";
        process.StartInfo.Arguments = "-command (New-Object -ComObject Shell.Application).NameSpace('C:').Self.ExtendedProperty('System.Volume.BitLockerProtection')"; 
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.RedirectStandardOutput = true;
        process.Start();
        StreamReader reader = process.StandardOutput;
        string output = reader.ReadToEnd().Substring(0,1); //needed as output would otherwise be 1\r\n (if encrypted)
        Console.WriteLine(output);
        process.WaitForExit();
        return output;
    }
  • Yes, it's a high-level way of doing it. Since this question is labeled C++ and WinAPI, I'm wondering what is .NET (or PowerShell by proxy) using internally to determine that? – c00000fd Nov 16 '21 at 10:36
0

Also easy to do in CMD and Powershell In a CMD shell you can use this one-liner to ask Powershell to return the value as an exit code:

powershell -command exit 1000 + (New-Object -ComObject Shell.Application).NameSpace('C:').Self.ExtendedProperty('System.Volume.BitLockerProtection')

and check the %ERRORLEVEL% returned in the CMD shell

Osadhi Virochana
  • 1,294
  • 2
  • 11
  • 21