Bluebeam acting slow in my softdrive machine

Modified on Mon, 8 Sep at 9:19 AM

Issue: Bluebeam is unresponsive and slow when I use is from my softdrive virtual machine.


Solutions: 


The solution is to disable camera access in bluebeam. There are two main ways to disable camera access inside a Softdrive virtual machine:

  1. Disable the camera specifically for Bluebeam Revu (via a registry script).

  2. Disable the camera entirely for the Softdrive machine (using Windows privacy settings).

 




1) Disable Camera for Bluebeam Revu Only (via Registry Script) 

This method blocks Bluebeam Revu from accessing the camera, while leaving camera functionality available for other applications like Teams or Zoom. This script will do the following: 

  • On machines without Bluebeam, the script runs safely and does nothing permanent (no junk keys created).

  • On machines with Bluebeam already installed or launched, the keys exist and the script applies Value="Deny".

  • On machines where Bluebeam is installed later, Windows will create the NonPackaged entry at first camera use, and your Intune remediation will catch it (if deployed as a proactive remediation) and flip it to Deny.



Notes:

  • Scope: current user, all loaded users, all profiles on disk, and Default (new users).

  • Layouts handled: both ...\Bluebeam Revu\21\Revu and ...\Bluebeam Revu 21\Revu, plus any other Revu.exe found under the Bluebeam vendor folder.

  • Keys set: for each match, creates/updates both nested and flat # NonPackaged keys with Value = "Deny" and a zeroed LastUsedTimeStop.

  • Creates Logging in this path: %PROGRAMDATA%\BluebeamCamBlock\log_*.txt.


Steps to Create and Run the Script

  1. Open Notepad

    • On your Softdrive desktop, click Start → Notepad.

  2. Paste the script below into Notepad:

<# Bluebeam Revu camera = Deny (Nested-style only, using .NET Registry API) #>

$ErrorActionPreference = 'Continue'

# --- Logging ---

$LogDir  = Join-Path $env:ProgramData 'BluebeamCamBlock'

$LogFile = Join-Path $LogDir ("log_{0:yyyyMMdd_HHmmss}.txt" -f (Get-Date))

New-Item -ItemType Directory -Path $LogDir -Force | Out-Null

function Write-Log($m){ $l="[${(Get-Date -f 'yyyy-MM-dd HH:mm:ss')}] $m"; Add-Content $LogFile $l; Write-Host $l }

Write-Log "=== Start Bluebeam Camera Block (Nested-only, .NET) ==="

Write-Log "Log: $LogFile"

# --- Targets finder (same as before) ---

function Get-RevuExeTargets {

  $candidates = [System.Collections.Generic.List[string]]::new()

  $common = @(

    'C:\Program Files\Bluebeam Software\Bluebeam Revu\21\Revu\Revu.exe',

    'C:\Program Files\Bluebeam Software\Bluebeam Revu 21\Revu\Revu.exe'

  )

  foreach ($p in $common) { if (Test-Path $p) { $candidates.Add($p) } }

  $vendor = 'C:\Program Files\Bluebeam Software'

  if (Test-Path $vendor) {

    try {

      $found = Get-ChildItem -Path $vendor -Filter 'Revu.exe' -Recurse -Depth 5 -ErrorAction SilentlyContinue |

               Where-Object { $_.FullName -match '\\Bluebeam Revu(  ?\d+)?\\Revu\\Revu\.exe$' } |

               Select-Object -ExpandProperty FullName -Unique

      foreach ($f in $found) { if (-not ($candidates.Contains($f))) { $candidates.Add($f) } }

    } catch {}

  }

  if ($candidates.Count -eq 0) {

    $candidates.Add('C:\Program Files\Bluebeam Software\Bluebeam Revu\21\Revu\Revu.exe')

  }

  return $candidates.ToArray()

}

$ExeTargets = Get-RevuExeTargets

$ExeTargets | ForEach-Object { Write-Log "Target EXE: $_" }

# --- .NET registry helpers ---

Add-Type -AssemblyName 'Microsoft.Win32.Registry'

function Open-UsersHive {

  param([Microsoft.Win32.RegistryView]$View = [Microsoft.Win32.RegistryView]::Default)

  return [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::Users, $View)

}

function OpenWritableSubKey {

  param(

    [Microsoft.Win32.RegistryKey]$RootKey,

    [string]$SubPath,          # e.g. 'S-1-5-21-...\Software\...\NonPackaged'

    [bool]$CreateIfMissing=$true

  )

  $key = $RootKey

  foreach ($seg in $SubPath -split '\\') {

    if (-not $seg) { continue }

    $next = $key.OpenSubKey($seg, $true)

    if (-not $next) {

      if (-not $CreateIfMissing) { return $null }

      $next = $key.CreateSubKey($seg, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree)

    }

    $key = $next

  }

  return $key

}

function EnsureNestedLeafDotNet {

  param(

    [string]$HiveKind,             # 'HKCU' or 'HKU'

    [string]$SidOrEmpty,           # '' for HKCU, or a SID/alias under HKU

    [string[]]$ExePaths

  )

  $view = [Microsoft.Win32.RegistryView]::Default

  if ($HiveKind -eq 'HKCU') {

    $cu = [Microsoft.Win32.Registry]::CurrentUser

    $base = OpenWritableSubKey -RootKey $cu -SubPath 'Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam\NonPackaged'

  } else {

    $users = Open-UsersHive -View $view

    $base  = OpenWritableSubKey -RootKey $users -SubPath ("{0}\Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam\NonPackaged" -f $SidOrEmpty)

  }

  if (-not $base) { Write-Log "Could not open NonPackaged base for $HiveKind\$SidOrEmpty"; return }

  # Flip any existing Bluebeam/Revu entries (packaged or nested) to Deny

  foreach ($name in $base.GetSubKeyNames()) {

    if ($name -match '(?i)bluebeam|revu|revu\.exe|^[A-Za-z]:$') {

      try {

        $k = $base.OpenSubKey($name, $true)

        if ($k) {

          $k.SetValue('Value','Deny',[Microsoft.Win32.RegistryValueKind]::String)

          $k.SetValue('LastUsedTimeStop', (New-Object byte[] 16), [Microsoft.Win32.RegistryValueKind]::Binary)

          $k.Close()

          Write-Log "Set Deny on existing: $($base.Name)\$name"

        }

      } catch { Write-Log "ERROR existing: $($_.Exception.Message)" }

    }

  }

  # Create nested keys: C: \ Program Files \ ... \ Revu.exe

  foreach ($exe in $ExePaths) {

    try {

      $p = ($exe -replace '/', '\').Trim()

      if ($p -notmatch '^[A-Za-z]:\\') { Write-Log "Skip unexpected path: $exe"; continue }

      $drive = $p.Substring(0,2)          # 'C:'

      $rest  = $p.Substring(3)            # after 'C:\'

      $segs  = @($drive)

      if ($rest) { $segs += $rest.Split('\') }

      $cur = $base

      foreach ($seg in $segs) {

        if (-not $seg) { continue }

        $next = $cur.OpenSubKey($seg, $true)

        if (-not $next) { $next = $cur.CreateSubKey($seg, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree) }

        $cur = $next

      }

      $cur.SetValue('Value','Deny',[Microsoft.Win32.RegistryValueKind]::String)

      $cur.SetValue('LastUsedTimeStop', (New-Object byte[] 16), [Microsoft.Win32.RegistryValueKind]::Binary)

      Write-Log "Pre-seeded (nested): $($cur.Name)"

      $cur.Close()

    } catch {

      Write-Log "ERROR nested: $exe :: $($_.Exception.Message)"

    }

  }

  # Cleanup accidental 'rogram Files' sibling if present

  try {

    foreach ($bad in $base.GetSubKeyNames() | Where-Object { $_ -ceq 'rogram Files' }) {

      $base.DeleteSubKeyTree($bad, $true)

      Write-Log "Removed stray key: $($base.Name)\$bad"

    }

  } catch { Write-Log "Cleanup error: $($_.Exception.Message)" }

  $base.Close()

}

# --- Apply to current HKCU ---

Write-Log "Applying to HKCU..."

EnsureNestedLeafDotNet -HiveKind 'HKCU' -SidOrEmpty '' -ExePaths $ExeTargets

# --- Apply to all LOADED HKU SIDs ---

$loadedSids = @()

try {

  $loadedSids = Get-ChildItem 'Registry::HKEY_USERS' |

    Where-Object { $_.PSChildName -match '^S-1-5-21-' -and ($_.PSChildName -notmatch '_Classes$') } |

    Select-Object -ExpandProperty PSChildName

} catch {}

# Skip current user SID if present (their HKCU is already handled)

try {

  $curSid = (New-Object Security.Principal.WindowsIdentity $env:USERNAME).User.Value

  if ($curSid) { $loadedSids = $loadedSids | Where-Object { $_ -ne $curSid } }

} catch {}

foreach ($sid in $loadedSids) {

  Write-Log "Applying to loaded hive: HKEY_USERS\$sid"

  EnsureNestedLeafDotNet -HiveKind 'HKU' -SidOrEmpty $sid -ExePaths $ExeTargets

}

# --- Apply to every PROFILE on disk (offline) ---

$profiles = Get-ChildItem 'C:\Users' -Force | Where-Object {

  $_.PSIsContainer -and $_.Name -notin @('All Users','Default','Default User','Public')

}

foreach ($p in $profiles) {

  $nt = Join-Path $p.FullName 'NTUSER.DAT'

  if (-not (Test-Path $nt)) { Write-Log "Skip (no NTUSER.DAT): $($p.FullName)"; continue }

  # Don’t load current user’s hive (already loaded)

  if ($p.Name -eq $env:USERNAME) { Write-Log "Skip loading current profile: $($p.Name)"; continue }

  $alias = "TempHive_$($p.Name)"

  Write-Log "Loading profile hive: $($p.FullName) -> HKU\$alias"

  $load = & reg.exe load "HKU\$alias" "$nt" 2>&1

  if ($LASTEXITCODE -ne 0) { Write-Log "reg load failed: $load"; continue }

  try {

    EnsureNestedLeafDotNet -HiveKind 'HKU' -SidOrEmpty $alias -ExePaths $ExeTargets

  } catch {

    Write-Log "ERROR applying to HKU\$alias :: $($_.Exception.Message)"

  } finally {

    & reg.exe unload "HKU\$alias" | Out-Null

    Write-Log "Unloaded HKU\$alias"

  }

}

# --- Default profile (new users) ---

$defaultNT = 'C:\Users\Default\NTUSER.DAT'

if (Test-Path $defaultNT) {

  Write-Log "Loading Default user hive..."

  $load = & reg.exe load HKU\DefaultUser "$defaultNT" 2>&1

  if ($LASTEXITCODE -eq 0) {

    try {

      EnsureNestedLeafDotNet -HiveKind 'HKU' -SidOrEmpty 'DefaultUser' -ExePaths $ExeTargets

    } catch {

      Write-Log "ERROR applying to DefaultUser :: $($_.Exception.Message)"

    } finally {

      & reg.exe unload HKU\DefaultUser | Out-Null

      Write-Log "Unloaded HKU\DefaultUser"

    }

  } else {

    Write-Log "reg load DefaultUser failed: $load"

  }

}

Write-Log "=== Completed Bluebeam Camera Block (Nested-only, .NET) ==="

    c. Save the script

  • Click File → Save As.

  • Set File name = BluebeamCamBlock.ps1.

  • Set Save as type = All Files (*.*).

  • Save it to your Desktop.

   d. Run the script

  • Open PowerShell as Administrator:

    • Click Start → type PowerShell, right-click → Run as administrator.

  • Run the script with specifying the path where it was saved. 

    powershell.exe -ExecutionPolicy Bypass -File "C:\Path\BluebeamCamBlock.ps1"

        

    e. Verify the change

  • Open Registry Editor (regedit.exe).

  • Navigate to:

    HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam\NonPackaged
  • You should see a key for ...Revu.exe with Value = Deny.

  • In Bluebeam, the camera tool will no longer function.




2: Disable camera access in Softdrive.


Step 1: Open Privacy Settings

  1. Press Windows Key + I to open Settings.
  2. Click on Privacy (Windows 10) or Privacy & security (Windows 11).
  3. On the left panel (or scroll down), click Camera under App permissions.

Step 2: Modify App Permissions

  • Scroll further down to “Allow desktop apps to access your camera”.
  • Turn OFF the toggle.



Contact your IT team to determine the best option for your situation.