Repository navigation
Constants and Error Codes
Relevant source files
The following files were used as context for generating this wiki page:
This page documents all constants, error codes, return values, and exit codes used throughout OfficeScrubC2R. The system defines constants in multiple locations: the native C# library (OfficeConstants class), Win32 API P/Invoke declarations (NativeMethods class), and the original VBScript conversion reference (Constants class).
For information about the three-stage pipeline that generates these errors, see Three-Stage Execution Pipeline. For troubleshooting guidance based on error codes, see Troubleshooting.
OfficeScrubC2R uses three categories of constants:
-
Office Detection Constants - Product identification strings, GUID patterns, process names, and path patterns defined in
OfficeConstants -
Win32 API Constants - Registry access flags, file operation flags, and Windows error codes defined in
NativeMethods - Error Codes - Bitmask-based error tracking system inherited from the original VBScript implementation
Each constant category serves a specific purpose in the cleanup pipeline. Office detection constants identify what to remove, Win32 API constants control how native operations are performed, and error codes track the success or failure of each stage.
Sources: OfficeScrubC2R-Native.cs:29-56, OfficeScrubC2R-Native.cs:62-153, direct_conversion.cs:27-62
The OfficeConstants static class defines Office-specific identification constants used throughout the cleanup process. These constants are used by detection logic, path validation, and process termination.
classDiagram
class OfficeConstants {
+const string OFFICE_ID
+const int PROD_LEN
+const int SQUISHED
+const int COMPRESSED
+static readonly string[] C2R_PATTERNS
+static readonly string[] OFFICE_PROCESSES
}
class OfficeScrubOrchestrator {
+bool IsC2RPath(string path)
+bool IsInScope(string productCode)
}
class ProcessHelper {
+List~int~ TerminateProcesses(string[] processNames)
}
class GuidHelper {
+string GetExpandedGuid(string compressedGuid)
+string GetCompressedGuid(string expandedGuid)
+bool GetDecodedGuid(string encodedGuid, out string decodedGuid)
}
OfficeConstants --> OfficeScrubOrchestrator : "used by IsInScope()"
OfficeConstants --> OfficeScrubOrchestrator : "used by IsC2RPath()"
OfficeConstants --> ProcessHelper : "used by TerminateProcesses()"
OfficeConstants --> GuidHelper : "COMPRESSED constant"
OfficeConstants Usage Throughout System
| Constant | Value | Type | Purpose |
|---|---|---|---|
OFFICE_ID |
"{0000000FF1CE}" |
string | Office product GUID suffix - all Office product codes end with this identifier |
PROD_LEN |
13 |
int | Expected length of product identifier segment in product codes |
SQUISHED |
20 |
int | Length of Base85-encoded GUID format (20 characters) used in published components |
COMPRESSED |
32 |
int | Length of compressed GUID format (32 characters) used in Windows Installer metadata |
Sources: OfficeScrubC2R-Native.cs:31-34
Click-to-Run installation path patterns used by IsC2RPath() method to identify C2R installations:
public static readonly string[] C2R_PATTERNS = new[]
{
@"\ROOT\OFFICE1", // Root Office folder pattern
@"Microsoft Office\Root\", // Modern C2R structure
@"\microsoft shared\ClickToRun", // ClickToRun service folder
@"\Microsoft Office\PackageManifests", // Package manifest location
@"\Microsoft Office\PackageSunrisePolicies",// Policy configuration
@"Microsoft Office 15", // Office 2013 C2R
@"Microsoft Office 16" // Office 2016+ C2R
};Any path containing one of these patterns is identified as a Click-to-Run installation path. The comparison is case-insensitive via StringComparison.OrdinalIgnoreCase.
Sources: OfficeScrubC2R-Native.cs:36-45
Known Office executable names for process termination:
public static readonly string[] OFFICE_PROCESSES = new[]
{
"appvshnotify.exe", // App-V notification
"integratedoffice.exe", // Integration component
"integrator.exe", // C2R integrator
"firstrun.exe", // First run experience
"communicator.exe", // Lync/Skype for Business
"msosync.exe", // OneDrive sync
"OneNoteM.exe", // OneNote Modern app
"iexplore.exe", // Internet Explorer (Office integration)
"mavinject32.exe", // App-V injector
"werfault.exe", // Windows Error Reporting
"perfboost.exe", // Performance optimization
"roamingoffice.exe", // Roaming settings
"officeclicktorun.exe", // C2R service
"officeondemand.exe", // On-demand streaming
"OfficeC2RClient.exe", // C2R client
"winword.exe", // Microsoft Word
"excel.exe", // Microsoft Excel
"powerpnt.exe", // Microsoft PowerPoint
"outlook.exe", // Microsoft Outlook
"onenote.exe", // Microsoft OneNote
"mspub.exe", // Microsoft Publisher
"msaccess.exe", // Microsoft Access
"lync.exe", // Lync
"skype.exe", // Skype for Business
"teams.exe" // Microsoft Teams
};The ProcessHelper.TerminateProcesses() method iterates this array and terminates all matching processes in parallel.
Sources: OfficeScrubC2R-Native.cs:47-55
The NativeMethods internal static class defines Win32 API constants for P/Invoke declarations. These constants control registry access, file operations, and error handling.
graph TB
subgraph "Registry Operations"
RegOpen["RegOpenKeyEx()"]
RegDelete["RegDeleteKeyEx()"]
RegEnum["RegEnumKeyEx()"]
KEY_WOW64_64KEY["KEY_WOW64_64KEY<br/>0x0100"]
KEY_WOW64_32KEY["KEY_WOW64_32KEY<br/>0x0200"]
KEY_READ["KEY_READ<br/>0x20019"]
KEY_WRITE["KEY_WRITE<br/>0x20006"]
KEY_ALL_ACCESS["KEY_ALL_ACCESS<br/>0xF003F"]
end
subgraph "File Operations"
MoveFileEx["MoveFileEx()"]
MOVEFILE_DELAY_UNTIL_REBOOT["MOVEFILE_DELAY_UNTIL_REBOOT<br/>0x4"]
end
subgraph "Error Codes"
ERROR_SUCCESS["ERROR_SUCCESS<br/>0"]
ERROR_NO_MORE_ITEMS["ERROR_NO_MORE_ITEMS<br/>259"]
end
RegOpen --> KEY_WOW64_64KEY
RegOpen --> KEY_WOW64_32KEY
RegOpen --> KEY_READ
RegDelete --> KEY_WOW64_64KEY
RegDelete --> KEY_WOW64_32KEY
RegEnum --> KEY_READ
MoveFileEx --> MOVEFILE_DELAY_UNTIL_REBOOT
RegOpen --> ERROR_SUCCESS
RegEnum --> ERROR_NO_MORE_ITEMS
Win32 API Constants Usage
| Constant | Hex Value | Decimal | Purpose |
|---|---|---|---|
KEY_WOW64_64KEY |
0x0100 |
256 | Access 64-bit registry view on 64-bit Windows |
KEY_WOW64_32KEY |
0x0200 |
512 | Access 32-bit registry view (WOW64 redirected) on 64-bit Windows |
KEY_READ |
0x20019 |
131097 | Read-only access (STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) |
KEY_WRITE |
0x20006 |
131078 | Write access (STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) |
KEY_ALL_ACCESS |
0xF003F |
983103 | Full access (STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK) |
These flags are combined with bitwise OR when opening registry keys. For example, KEY_READ | KEY_WOW64_64KEY opens a key for reading from the 64-bit registry view.
Sources: OfficeScrubC2R-Native.cs:145-149
| Constant | Hex Value | Decimal | Purpose |
|---|---|---|---|
MOVEFILE_DELAY_UNTIL_REBOOT |
0x4 |
4 | Schedules file/directory deletion on next system restart via MoveFileEx()
|
This flag is used by FileHelper.ScheduleDeleteOnReboot() to delete files that are currently locked by running processes. The file path is added to the PendingFileRenameOperations registry value.
Sources: OfficeScrubC2R-Native.cs:150
| Constant | Decimal Value | Meaning |
|---|---|---|
ERROR_SUCCESS |
0 |
Operation completed successfully |
ERROR_NO_MORE_ITEMS |
259 |
No more registry keys or values to enumerate |
These are return values from Win32 API functions, not to be confused with the OfficeScrubC2R error codes documented later on this page.
Sources: OfficeScrubC2R-Native.cs:151-152
GUID transformation operations use constants from OfficeConstants to validate and convert between different GUID encodings.
graph LR
subgraph "GUID Formats"
Expanded["Expanded GUID<br/>38 characters<br/>{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"]
Compressed["Compressed GUID<br/>32 characters<br/>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<br/>(COMPRESSED constant)"]
Encoded["Encoded GUID<br/>20 characters<br/>Base85 format<br/>(SQUISHED constant)"]
end
subgraph "Validation"
CheckLength38["Length == 38?"]
CheckLength32["Length == 32?<br/>(COMPRESSED)"]
CheckLength20["Length == 20?<br/>(SQUISHED)"]
end
Expanded --> CheckLength38
Compressed --> CheckLength32
Encoded --> CheckLength20
CheckLength38 --> GetCompressedGuid["GetCompressedGuid()"]
CheckLength32 --> GetExpandedGuid["GetExpandedGuid()"]
CheckLength20 --> GetDecodedGuid["GetDecodedGuid()"]
GUID Format Validation Using Constants
| Constant | Value | Used By | Validates |
|---|---|---|---|
COMPRESSED |
32 |
GetExpandedGuid(), Windows Installer helpers |
Compressed GUID format (registry key names) |
SQUISHED |
20 |
GetDecodedGuid() |
Base85-encoded GUID format (published components) |
| N/A (literal) | 38 |
GetCompressedGuid() |
Standard GUID format with braces and dashes |
Sources: OfficeScrubC2R-Native.cs:33-34, OfficeScrubC2R-Native.cs:173-328
The error code system implements a bitmask-based architecture where multiple error conditions can be combined into a single exit code. Each error condition is represented by a unique power of 2, allowing multiple errors to be combined using bitwise OR operations.
The error code system serves three primary purposes:
- Precise Failure Tracking - Multiple error conditions can be tracked simultaneously in a single integer value
-
Automated Error Cascading - Critical errors automatically set the
ERROR_FAILflag - Reboot State Management - The system tracks when system restart is required to complete cleanup
Error codes are defined in the original VBScript Constants class and maintained for compatibility. The system uses 13 distinct error flags.
| Constant | Decimal Value | Binary Value | Hex Value | Description |
|---|---|---|---|---|
ERROR_SUCCESS |
0 | 0b0000000000000 | 0x0000 | No errors - operation completed successfully |
ERROR_FAIL |
1 | 0b0000000000001 | 0x0001 | Generic failure flag - set automatically for critical errors |
ERROR_REBOOT_REQUIRED |
2 | 0b0000000000010 | 0x0002 | System restart required to complete uninstall |
ERROR_USERCANCEL |
4 | 0b0000000000100 | 0x0004 | User cancelled the operation |
ERROR_STAGE1 |
8 | 0b0000000001000 | 0x0008 | Stage 1 (Uninstall) failed - msiexec or ODT error |
ERROR_STAGE2 |
16 | 0b0000000010000 | 0x0010 | Stage 2 (Cleanup) failed - registry or file cleanup error |
ERROR_INCOMPLETE |
32 | 0b0000000100000 | 0x0020 | Removal incomplete - rerun after reboot needed |
ERROR_DCAF_FAILURE |
64 | 0b0000001000000 | 0x0040 | Second attempt cleanup still incomplete (DCAF = Delete Content And Folders) |
ERROR_ELEVATION_USERDECLINED |
128 | 0b0000010000000 | 0x0080 | User declined UAC elevation prompt |
ERROR_ELEVATION |
256 | 0b0000100000000 | 0x0100 | Elevation failed - insufficient privileges |
ERROR_SCRIPTINIT |
512 | 0b0001000000000 | 0x0200 | Script initialization failed |
ERROR_RELAUNCH |
1024 | 0b0010000000000 | 0x0400 | Unhandled error during relaunch attempt |
ERROR_UNKNOWN |
2048 | 0b0100000000000 | 0x0800 | Unknown error occurred |
Maximum Possible Error Code: 4095 (0xFFF) - all error flags set simultaneously
Sources: direct_conversion.cs:45-61
The error code system uses bitwise operations to combine multiple error states into a single integer value. This allows the script to track multiple failure conditions simultaneously while returning only a single exit code.
Error codes are set using the bitwise OR operation (-bor in PowerShell), which adds the error flag to the existing error code without clearing other flags.
Example:
Current ErrorCode: 0 (binary: 0000000000000)
Set ERROR_REBOOT_REQUIRED (2)
New ErrorCode: 2 (binary: 0000000000010)
Then set ERROR_STAGE1 (8)
New ErrorCode: 10 (binary: 0000000001010) [Both flags are preserved]
Error codes are cleared using the bitwise AND operation with the NOT of the error flag (-band (-bnot $ErrorBit)), which removes only the specified flag while preserving others.
Example:
Current ErrorCode: 10 (binary: 0000000001010) [REBOOT_REQUIRED + STAGE1]
Clear ERROR_STAGE1 (8)
New ErrorCode: 2 (binary: 0000000000010) [Only REBOOT_REQUIRED remains]
Sources: OfficeScrubC2R-Utilities.psm1:333-346, OfficeScrubC2R-Utilities.psm1:349-362
flowchart TD
Start["Operation encounters error"]
SetError["Call Set-ErrorCode($ErrorBit)"]
BitwiseOR["$script:ErrorCode = $script:ErrorCode -bor $ErrorBit"]
CheckCritical{"Is error bit in<br/>critical set?"}
CriticalSet["$criticalErrors =<br/>DCAF_FAILURE | STAGE2 |<br/>ELEVATION_USERDECLINED |<br/>ELEVATION | SCRIPTINIT"]
SetFail["$script:ErrorCode =<br/>$script:ErrorCode -bor ERROR_FAIL"]
Done["Error code updated"]
Start --> SetError
SetError --> BitwiseOR
BitwiseOR --> CheckCritical
CheckCritical -->|Yes| CriticalSet
CheckCritical -->|No| Done
CriticalSet --> SetFail
SetFail --> Done
Error Code Setting Process
This diagram shows how the Set-ErrorCode function adds error flags to the global error code. Critical errors automatically trigger the ERROR_FAIL flag through cascading logic.
Sources: OfficeScrubC2R-Utilities.psm1:333-346
flowchart TD
Start["Operation succeeds after retry"]
ClearError["Call Clear-ErrorCode($ErrorBit)"]
BitwiseAND["$script:ErrorCode = $script:ErrorCode -band (-bnot $ErrorBit)"]
CheckClearable{"Is error bit in<br/>clearable set?"}
ClearableSet["$clearableErrors =<br/>ELEVATION_USERDECLINED |<br/>ELEVATION | SCRIPTINIT"]
ClearFail["$script:ErrorCode =<br/>$script:ErrorCode -band (-bnot ERROR_FAIL)"]
Done["Error code updated"]
Start --> ClearError
ClearError --> BitwiseAND
BitwiseAND --> CheckClearable
CheckClearable -->|Yes| ClearableSet
CheckClearable -->|No| Done
ClearableSet --> ClearFail
ClearFail --> Done
Error Code Clearing Process
This diagram shows how the Clear-ErrorCode function removes error flags. Clearing certain clearable errors (elevation/initialization) also clears the ERROR_FAIL flag if no other critical errors remain.
Sources: OfficeScrubC2R-Utilities.psm1:349-362
The system implements automatic error cascading where critical errors automatically set the ERROR_FAIL flag. This ensures that severe failures are always reflected in the exit code.
The following errors are considered critical and automatically set ERROR_FAIL:
| Error Code | Reason for Criticality |
|---|---|
ERROR_DCAF_FAILURE |
Second cleanup attempt failed - persistent system state corruption |
ERROR_STAGE2 |
Registry/file cleanup failed - incomplete removal |
ERROR_ELEVATION_USERDECLINED |
User denied admin access - cannot proceed |
ERROR_ELEVATION |
Failed to obtain admin privileges - insufficient permissions |
ERROR_SCRIPTINIT |
Initialization failed - script cannot operate |
Only elevation and initialization errors can be cleared (typically after successful retry):
| Error Code | When Cleared |
|---|---|
ERROR_SCRIPTINIT |
After successful initialization on retry |
ERROR_ELEVATION |
After successful elevation on retry |
ERROR_ELEVATION_USERDECLINED |
After user accepts UAC on retry |
Sources: OfficeScrubC2R-Utilities.psm1:340-346, OfficeScrubC2R-Utilities.psm1:356-361
stateDiagram-v2
[*] --> Initialize_Script
Initialize_Script --> Check_ERROR_SUCCESS: Success
Initialize_Script --> Set_ERROR_SCRIPTINIT: Init failure
Check_ERROR_SUCCESS --> Stage0_Detection
Set_ERROR_SCRIPTINIT --> Show_Summary
Stage0_Detection --> Stage1_Uninstall: Products found
Stage0_Detection --> Show_Summary: No products
Stage1_Uninstall --> Set_ERROR_REBOOT_REQUIRED: ODT exit 3010
Stage1_Uninstall --> Set_ERROR_STAGE1: Msiexec failure
Stage1_Uninstall --> Stage2_Cleanup: Success
Set_ERROR_REBOOT_REQUIRED --> Stage2_Cleanup
Set_ERROR_STAGE1 --> Stage2_Cleanup
Stage2_Cleanup --> Set_ERROR_REBOOT_REQUIRED2: Files locked
Stage2_Cleanup --> Set_ERROR_STAGE2: Cleanup failure
Stage2_Cleanup --> Stage3_Summary: Success
Set_ERROR_REBOOT_REQUIRED2 --> Stage3_Summary
Set_ERROR_STAGE2 --> Stage3_Summary
Stage3_Summary --> Show_Summary
Show_Summary --> [*]
note right of Set_ERROR_SCRIPTINIT
Line 928:
ERROR_SCRIPTINIT (512)
Auto-sets ERROR_FAIL (1)
end note
note right of Set_ERROR_REBOOT_REQUIRED
Line 276-278:
ERROR_REBOOT_REQUIRED (2)
$script:RebootRequired = $true
end note
note right of Set_ERROR_STAGE1
Line 489:
ERROR_STAGE1 (8)
end note
note right of Set_ERROR_REBOOT_REQUIRED2
Lines 494-496, 522-525:
ERROR_REBOOT_REQUIRED (2)
Files scheduled for reboot
end note
note right of Set_ERROR_STAGE2
ERROR_STAGE2 (16)
Auto-sets ERROR_FAIL (1)
end note
Error Code Generation Through Pipeline Stages
This diagram shows where error codes are set during the three-stage execution pipeline. Each error condition has specific trigger points in the code.
Sources: OfficeScrubC2R.ps1:115-117, OfficeScrubC2R.ps1:276-278, OfficeScrubC2R.ps1:474-477, OfficeScrubC2R.ps1:489, OfficeScrubC2R.ps1:494-496, OfficeScrubC2R.ps1:522-525, OfficeScrubC2R.ps1:928
Since multiple error flags can be set simultaneously, the final error code must be decomposed using bitwise AND operations to determine which individual errors occurred.
Given an error code value, use bitwise AND (-band) to test for individual error flags:
# Example: Error code 11 (0x0B)
$errorCode = 11
# Test for individual flags
if ($errorCode -band $ERROR_FAIL) {
# True: 11 & 1 = 1
Write-Host "Generic failure occurred"
}
if ($errorCode -band $ERROR_REBOOT_REQUIRED) {
# True: 11 & 2 = 2
Write-Host "Reboot required"
}
if ($errorCode -band $ERROR_STAGE1) {
# True: 11 & 8 = 8
Write-Host "Stage 1 failed"
}
# Binary breakdown of 11:
# 11 = 0b00000001011 = ERROR_FAIL (1) + ERROR_REBOOT_REQUIRED (2) + ERROR_STAGE1 (8)| Exit Code | Binary | Flags Set | Meaning |
|---|---|---|---|
| 0 | 0b0000000000000 | ERROR_SUCCESS |
Complete success |
| 1 | 0b0000000000001 | ERROR_FAIL |
Generic failure (may indicate code bug) |
| 2 | 0b0000000000010 | ERROR_REBOOT_REQUIRED |
Reboot needed but otherwise successful |
| 3 | 0b0000000000011 |
ERROR_FAIL + ERROR_REBOOT_REQUIRED
|
Failed with reboot required |
| 4 | 0b0000000000100 | ERROR_USERCANCEL |
User cancelled operation |
| 10 | 0b0000000001010 |
ERROR_REBOOT_REQUIRED + ERROR_STAGE1
|
Stage 1 had issues, reboot needed |
| 11 | 0b0000000001011 |
ERROR_FAIL + ERROR_REBOOT_REQUIRED + ERROR_STAGE1
|
Stage 1 failed, reboot needed |
| 257 | 0b0000100000001 |
ERROR_FAIL + ERROR_ELEVATION
|
Elevation failed |
| 513 | 0b0001000000001 |
ERROR_FAIL + ERROR_SCRIPTINIT
|
Initialization failed |
| 2049 | 0b0100000000001 |
ERROR_FAIL + ERROR_UNKNOWN
|
Unknown error occurred |
Sources: OfficeScrubC2R.ps1:874-896
The Show-Summary function decodes the final error code and logs individual error conditions. This provides detailed diagnostics in the log file.
flowchart TD
Start["Show-Summary function"]
CheckIncomplete{"ErrorCode -band<br/>ERROR_INCOMPLETE?"}
LogIncomplete["Log: INCOMPLETE<br/>Reboot required"]
CheckUserCancel{"ErrorCode -band<br/>ERROR_USERCANCEL?"}
CheckFail{"ErrorCode -band<br/>ERROR_FAIL?"}
LogSuccess["Log: SUCCESS"]
LogUserCancel["Log: USER CANCELED"]
LogFail["Log: FAIL"]
TestFlags["Test each flag<br/>with -band"]
LogReboot{"REBOOT_REQUIRED?"}
LogCancel{"USERCANCEL?"}
LogStage1{"STAGE1?"}
LogStage2{"STAGE2?"}
LogDCAF{"DCAF_FAILURE?"}
LogElevDeclined{"ELEVATION_USERDECLINED?"}
LogElev{"ELEVATION?"}
LogInit{"SCRIPTINIT?"}
LogRelaunch{"RELAUNCH?"}
LogUnknown{"UNKNOWN?"}
LogRebootMsg["Write-Log 'Reboot required'"]
LogCancelMsg["Write-Log 'User cancel'"]
LogStage1Msg["Write-Log 'Msiexec failed'"]
LogStage2Msg["Write-Log 'Cleanup failed'"]
LogDCAFMsg["Write-Log 'Second attempt cleanup<br/>still incomplete'"]
LogElevDeclinedMsg["Write-Log 'User declined elevation'"]
LogElevMsg["Write-Log 'Elevation failed'"]
LogInitMsg["Write-Log 'Initialization error'"]
LogRelaunchMsg["Write-Log 'Unhandled error<br/>during relaunch'"]
LogUnknownMsg["Write-Log 'Unknown error'"]
Done["Return final ErrorCode"]
Start --> CheckIncomplete
CheckIncomplete -->|Yes| LogIncomplete
CheckIncomplete -->|No| CheckUserCancel
LogIncomplete --> Done
CheckUserCancel -->|Yes| LogUserCancel
CheckUserCancel -->|No| CheckFail
CheckFail -->|Yes| LogFail
CheckFail -->|No| LogSuccess
LogSuccess --> Done
LogUserCancel --> Done
LogFail --> TestFlags
TestFlags --> LogReboot
LogReboot -->|Yes| LogRebootMsg
LogReboot -->|No| LogCancel
LogRebootMsg --> LogCancel
LogCancel -->|Yes| LogCancelMsg
LogCancel -->|No| LogStage1
LogCancelMsg --> LogStage1
LogStage1 -->|Yes| LogStage1Msg
LogStage1 -->|No| LogStage2
LogStage1Msg --> LogStage2
LogStage2 -->|Yes| LogStage2Msg
LogStage2 -->|No| LogDCAF
LogStage2Msg --> LogDCAF
LogDCAF -->|Yes| LogDCAFMsg
LogDCAF -->|No| LogElevDeclined
LogDCAFMsg --> LogElevDeclined
LogElevDeclined -->|Yes| LogElevDeclinedMsg
LogElevDeclined -->|No| LogElev
LogElevDeclinedMsg --> LogElev
LogElev -->|Yes| LogElevMsg
LogElev -->|No| LogInit
LogElevMsg --> LogInit
LogInit -->|Yes| LogInitMsg
LogInit -->|No| LogRelaunch
LogInitMsg --> LogRelaunch
LogRelaunch -->|Yes| LogRelaunchMsg
LogRelaunch -->|No| LogUnknown
LogRelaunchMsg --> LogUnknown
LogUnknown -->|Yes| LogUnknownMsg
LogUnknown -->|No| Done
LogUnknownMsg --> Done
Error Code Reporting Logic
The Show-Summary function at OfficeScrubC2R.ps1:867-918 systematically tests each error flag and logs a human-readable description. This provides detailed diagnostics in the log file for troubleshooting.
Sources: OfficeScrubC2R.ps1:867-918
The error code is returned through two mechanisms:
The main script returns the error code as its exit code, which can be captured by the calling process:
# From Main function
return $script:ErrorCode # Line 988
# Script execution
$exitCode = Main
exit $exitCode # Lines 1005-1006For compatibility with scheduled tasks and other automation scenarios, the error code is also written to a file:
# File path: %TEMP%\OfficeScrubC2R\ScrubRetValFile.txt
$retValFile = Join-Path $script:ScrubDir "ScrubRetValFile.txt"
[System.IO.File]::WriteAllText($retValFile, $Value.ToString())This allows external processes to read the error code even if they cannot capture the script's exit code directly.
Sources: OfficeScrubC2R.ps1:988, OfficeScrubC2R.ps1:1005-1006, OfficeScrubC2R-Utilities.psm1:364-376
classDiagram
class Set_ErrorCode {
+int ErrorBit
-BitwiseOR()
-CheckCritical()
-SetFailIfCritical()
}
class Clear_ErrorCode {
+int ErrorBit
-BitwiseAND_NOT()
-CheckClearable()
-ClearFailIfClearable()
}
class Set_ReturnValue {
+int Value
-WriteToFile()
}
class Show_Summary {
-LogErrorCode()
-TestAllFlags()
-LogIndividualErrors()
-HandleReboot()
}
class Initialize_Script {
-InitErrorCode()
-SetERROR_SCRIPTINIT()
-ClearERROR_SCRIPTINIT()
}
class Main {
-CallInitialize()
-ExecutePipeline()
-ReturnErrorCode()
}
Set_ErrorCode --> script_ErrorCode : updates
Clear_ErrorCode --> script_ErrorCode : updates
Set_ReturnValue --> ScrubRetValFile_txt : writes
Show_Summary --> script_ErrorCode : reads
Initialize_Script --> Set_ErrorCode : calls
Initialize_Script --> Clear_ErrorCode : calls
Main --> Set_ErrorCode : calls
Main --> Show_Summary : calls
Main --> script_ErrorCode : returns
Error Code Functions and Their Relationships
This diagram shows the key functions involved in error code management and how they interact with the global $script:ErrorCode variable.
| Function | File | Lines | Purpose |
|---|---|---|---|
Set-ErrorCode |
OfficeScrubC2R-Utilities.psm1 | 333-346 | Sets error flags using bitwise OR with automatic cascading |
Clear-ErrorCode |
OfficeScrubC2R-Utilities.psm1 | 349-362 | Clears error flags using bitwise AND NOT |
Set-ReturnValue |
OfficeScrubC2R-Utilities.psm1 | 364-376 | Writes error code to return value file |
Initialize-Script |
OfficeScrubC2R.ps1 | 87-136 | Initializes error code, sets/clears ERROR_SCRIPTINIT
|
Show-Summary |
OfficeScrubC2R.ps1 | 867-918 | Decodes and logs all error flags |
Main |
OfficeScrubC2R.ps1 | 924-1001 | Orchestrates pipeline, catches errors, returns final code |
Sources: OfficeScrubC2R-Utilities.psm1:333-376, OfficeScrubC2R.ps1:87-136, OfficeScrubC2R.ps1:867-918, OfficeScrubC2R.ps1:924-1001
The ERROR_REBOOT_REQUIRED flag has special handling because it indicates a non-fatal but important condition: files are locked and will be deleted on next system restart.
| Condition | Code Location | Description |
|---|---|---|
| ODT returns exit code 3010 | OfficeScrubC2R.ps1:276-278 | Office Deployment Tool requires reboot |
| Msiexec returns exit code 3010 | OfficeScrubC2R.ps1:474-477 | Windows Installer requires reboot |
| Directory deletion fails | OfficeScrubC2R.ps1:494-496 | Folder is locked, scheduled for reboot deletion |
| File deletion fails | OfficeScrubC2R.ps1:522-525 | File is locked, scheduled for reboot deletion |
| Pending file operations added | OfficeScrubC2R-Utilities.psm1:541-543 | PendingFileRenameOperations registry updated |
When $script:RebootRequired is $true, the user is prompted to restart (unless running in quiet mode):
# From Show-Summary function (lines 902-914)
if ($script:RebootRequired) {
Write-Log "REBOOT REQUIRED - System restart needed to complete uninstall"
if (-not $script:Quiet) {
$response = Read-Host "Do you want to reboot now? (Y/N)"
if ($response -match "^[Yy]") {
Restart-Computer -Force
}
}
}Sources: OfficeScrubC2R.ps1:276-278, OfficeScrubC2R.ps1:474-477, OfficeScrubC2R.ps1:494-496, OfficeScrubC2R.ps1:522-525, OfficeScrubC2R.ps1:902-914, OfficeScrubC2R-Utilities.psm1:541-543
The current system supports 13 distinct error flags (ERROR_SUCCESS through ERROR_UNKNOWN), yielding a maximum theoretical error code of 4095 (0xFFF) if all flags are set simultaneously. This is an edge case that should never occur in normal operation.
The system does not implement severity levels (warning vs. error vs. critical). All error codes represent actual failures, with the exception of ERROR_SUCCESS (0) and ERROR_REBOOT_REQUIRED (2), which can indicate successful completion with required follow-up action.
Interpreting error codes requires bitwise AND operations. Simple integer equality checks will fail for combined error codes:
# WRONG: This will fail if multiple errors are set
if ($errorCode -eq $ERROR_REBOOT_REQUIRED) { }
# CORRECT: Use bitwise AND to test flags
if ($errorCode -band $ERROR_REBOOT_REQUIRED) { }Sources: OfficeScrubC2R-Utilities.psm1:9-22
All error code constants are exported from the utilities module for use in the main script and by external callers:
# From OfficeScrubC2R-Utilities.psm1 lines 1047-1062
Export-ModuleMember -Variable @(
'ERROR_SUCCESS',
'ERROR_FAIL',
'ERROR_REBOOT_REQUIRED',
'ERROR_USERCANCEL',
'ERROR_STAGE1',
'ERROR_STAGE2',
'ERROR_INCOMPLETE',
'ERROR_DCAF_FAILURE',
'ERROR_ELEVATION_USERDECLINED',
'ERROR_ELEVATION',
'ERROR_SCRIPTINIT',
'ERROR_RELAUNCH',
'ERROR_UNKNOWN',
'ErrorCode' # Current error code value
)The $script:ErrorCode variable is also exported, allowing external scripts to read (but not modify) the current error state.