Skip to content

Commit

Permalink
Merge pull request #7 from LarryWisherMan/fix/FolderName-ProcessFolders
Browse files Browse the repository at this point in the history
Add `Remove-UserProfilesFromRegistry`
  • Loading branch information
LarryWisherMan authored Sep 24, 2024
2 parents 14b4d65 + 7c818aa commit ac68f80
Show file tree
Hide file tree
Showing 63 changed files with 5,620 additions and 509 deletions.
2 changes: 1 addition & 1 deletion .vscode/analyzersettings.psd1
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@{
CustomRulePath = '.\output\RequiredModules\DscResource.AnalyzerRules'
includeDefaultRules = $true
IncludeRules = @(
IncludeRules = @(
# DSC Resource Kit style guideline rules.
'PSAvoidDefaultValueForMandatoryParameter',
'PSAvoidDefaultValueSwitchParameter',
Expand Down
87 changes: 60 additions & 27 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,89 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
### Fixed

- New helper function `Validate-SIDFormat` to verify SID value upon retrieval
in `Get-ProfilePathFromSID`
- Removed bug from `Process-RegistryProfiles` regarding populating the `FolderName`
variable.

- **Admin Detection and Environment Variable**: Added logic to detect whether the
current user is an administrator and set an environment variable
`WinProfileOps_IsAdmin` accordingly.
### Added

- If the user is an administrator, `$ENV:WinProfileOps_IsAdmin` is set to
`$true`. If not, it's set to `$false`.
#### Functions

- The environment variable is automatically removed when the module is
unloaded or when PowerShell exits.
- New helper function `Validate-SIDFormat` to verify SID value upon retrieval in
`Get-ProfilePathFromSID`.

- **Admin Detection and Environment Variable**: Added logic to detect whether
the current user is an administrator and set an environment variable
`WinProfileOps_IsAdmin` accordingly.

- If the user is an administrator, `$env:WinProfileOps_IsAdmin` is set to
`$true`. If not, it's set to `$false`.

- The environment variable is automatically removed when the module is unloaded
or when PowerShell exits.

- Registered an `OnRemove` script block and a `PowerShell.Exiting` event to
ensure cleanup of the environment variable on module removal or session exit.
ensure cleanup of the environment variable on module removal or session exit.

- **Remove-UserProfilesFromRegistry**: Added a new function to remove user profiles
from the Windows registry based on SIDs, Usernames, or UserProfile objects.

- Supports three parameter sets: `UserProfileSet`, `SIDSet`, and `UserNameSet`.

- Can be run in `AuditOnly` mode, where no actual deletion is performed, or
in deletion mode where profiles are removed.

- Includes a `Force` switch to bypass confirmation prompts and a
`ComputerName` parameter for targeting remote computers.

- Graceful error handling and logging for cases where the registry key cannot
be opened or profiles cannot be processed for specific computers.

#### Environment Variables

- **`$env:WinProfileOps_IsAdmin`**: A boolean value that determines if the current
user has administrative privileges. This is set by checking the user's security
role against the built-in Administrator group using Windows security principals.

- **`$env:WinProfileOps_RegistryPath`**: Specifies the registry path used to
manage user profiles. Default value: `"SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"`.

- **Get-SIDProfileInfoFallback**: Introduced a new fallback function
`Get-SIDProfileInfoFallback` that retrieves non-special user profile
information using the CIM/WMI method.
- **`$env:WinProfileOps_RegistryHive`**: Defines the registry hive to use, which
is set to `LocalMachine` by default.

- **`$env:WinProfileOps_RegBackUpDirectory`**: Specifies the directory where
registry backups are stored. Default value: `"C:\LHStuff\RegBackUp"`.

- **`$env:WinProfileOps_ProfileFolderPath`**: The profile folder path, defaulting
to the system drive's `Users` folder. Example: `"C:\Users"`.

### Changed

- **Get-UserProfilesFromRegistry**: Updated the function to handle scenarios
where the current user does not have administrative privileges.

- The function now checks if the user is an administrator by evaluating the
`WinProfileOps_IsAdmin` environment variable.

- If the user has administrator privileges, the function retrieves user
profiles from the registry using `Get-SIDProfileInfo`.

- If the user lacks administrative privileges, the function falls back to the
`Get-SIDProfileInfoFallback` method, which retrieves user profiles using
CIM/WMI without requiring registry access.

- A warning is logged when the fallback method is used, indicating that
special system accounts are excluded.
- A warning is logged when the fallback method is used, indicating that special
system accounts are excluded.

- Refactored `Process-RegistryProfiles` to better account for access denied errors
when testing profile paths with `Test-FolderExists`
when testing profile paths with `Test-FolderExists`.

- Updated `UserProfile` object creation in `Test-OrphanedProfile` for
`$AccessError` Scenarios
`$AccessError` scenarios.

- Module is now using `WinRegOps` Version `0.4.0` for more refined registry value
retrieval
- The module is now using `WinRegOps` version `0.4.0` for more refined registry
value retrieval.

## [0.2.0] - 2024-09-12

Expand Down Expand Up @@ -97,7 +132,7 @@ retrieval
- These supporting functions are now utilized within `Invoke-UserProfileAudit`
to audit user profiles from both the file system and registry sources.

- **`Process-RegistryProfiles`**:
- **`Process-RegistryProfiles`**:
- Processes profiles retrieved from the registry,
compares them with folder profiles, and identifies orphaned profiles.

Expand Down Expand Up @@ -128,7 +163,6 @@ an internal function for `Get-RegistryUserProfiles`
- Optimized function behavior to handle scenarios with no SIDs, invalid SID formats,
and missing `ProfileImagePath` values gracefully.


- **`Get-UserFolders`**
- The function now logs errors when folder retrieval fails, improving diagnostic
feedback.
Expand Down Expand Up @@ -173,7 +207,6 @@ an internal function for `Get-RegistryUserProfiles`
- Returns an empty array `@()` when an error occurs while accessing the user
folders, logging an error message.


- **`Invoke-UserProfileAudit`**
- Renamed the previous `Get-AllUserProfiles` function to `Invoke-UserProfileAudit`.
- Added `Get-AllUserProfiles` as an alias for `Invoke-UserProfileAudit`
Expand Down
103 changes: 67 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,36 @@ computers.

- **Retrieve user profile information** from both the registry and the file system
(local and remote).

- **Detect orphaned profiles**, such as profiles missing from the file system or
registry.

- **Filter and exclude special accounts** like system or service accounts (e.g.,
`defaultuser0`, `S-1-5-18`).

- **Remote profile management** with support for handling user profiles across
different systems.

- **Error handling** for permission issues, unreachable systems, and missing data.

- **Class-based profile objects** for easy integration with other automation tasks
or scripts.

---

## Typical Use Cases

- **Cleaning up orphaned profiles** after system migrations, user deactivations, or
profile corruption.
- **Cleaning up orphaned profiles** after system migrations,
user deactivations, or profile corruption.

- **Managing user profiles in large-scale environments**, such as terminal servers,
Citrix environments, or multi-user systems.

- **Excluding system accounts** from profile cleanup operations to prevent accidental
deletion of important system profiles.
- **System maintenance routines** that include profile validation and management as
part of a broader system health check.

- **System maintenance routines** that include profile validation
and management as part of a broader system health check.

---

Expand All @@ -71,9 +79,9 @@ You have two options to install **WinProfileOps**:
Install-Module -Name WinProfileOps
```

2. **Install from GitHub Releases**
1. **Install from GitHub Releases**
You can also download the latest release from the
[GitHub Releases page](https://github.com/LarryWisherMan/WinProfileOps/releases).
[GitHub Releases page](https://github.com/LarryWisherMan/WinProfileOps/releases).
Download the `.zip` file, extract it, and place it in one of your `$PSModulePath`
directories.

Expand Down Expand Up @@ -116,7 +124,8 @@ This retrieves user profiles from the registry on `LocalHost`.

#### Example 4: Auditing User Profiles

Use the `Invoke-UserProfileAudit` function to audit profiles across the file system and
Use the `Invoke-UserProfileAudit` function to audit profiles across the file
system and
registry:

```powershell
Expand All @@ -126,6 +135,36 @@ $allProfiles = Invoke-UserProfileAudit -ComputerName "Server01"
This audits user profiles on `Server01`, returning both file system and registry
profile information.

#### Example 5: Removing User Profiles from the Registry

Use the `Remove-UserProfilesFromRegistry` function to remove user profiles from
the Windows registry based on SIDs, Usernames, or UserProfile objects:

- Remove profiles by SIDs:

```powershell
Remove-UserProfilesFromRegistry -SIDs "S-1-5-21-1234567890-1", "S-1-5-21-1234567890-2"
```

- Remove profiles by usernames on a remote computer:

```powershell
Remove-UserProfilesFromRegistry -Usernames "john.doe", "jane.smith"
-ComputerName "Server01" -Force -Confirm:$false
```

- Audit user profiles before removal:

```powershell
Remove-UserProfilesFromRegistry -UserProfiles $userProfileList -AuditOnly
```

**Note:** To bypass any confirmation prompts during profile removal, both the
`-Force` switch and `-Confirm:$false` must be specified.

This allows you to either remove or audit profiles based on their SIDs,
usernames, or UserProfile objects.

---

## Key Functions
Expand All @@ -138,41 +177,33 @@ profile information.
registry.
- **`Get-UserProfilesFromFolders`**: Retrieves user profile folders from the file
system.
- **`Remove-UserProfilesFromRegistry`**: Removes user profiles from the Windows
registry based on SIDs, Usernames, or UserProfile objects,
with options for audit-only mode or forced removal.

---

## Upcoming Features

### `Remove-UserProfile` (Coming Soon!)
## Environment Variables

The `Remove-UserProfile` function will provide the ability to remove user
profiles safely from both the registry and the file system. Here are some of the
key features being tested for this functionality:
The **WinProfileOps** module uses several environment variables to configure
certain default paths and behaviors. These variables are automatically set
when the module is loaded and can be adjusted as needed:

- **Safely remove user profiles** either from the file system (i.e., user profile
folders) or from the Windows registry.
- **`$env:WinProfileOps_IsAdmin`**: Determines if the current user has
administrative privileges. It is determined by the current context of the
user.

- **`$env:WinProfileOps_RegistryPath`**: Specifies the registry path used for
managing user profiles. Default value: `"SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"`.

- **Flexible inputs**: Accepts a UserProfile object, a username, or a SID for
profile removal.
- **`$env:WinProfileOps_RegistryHive`**: Defines the registry hive used in
operations, set to `LocalMachine` by default.

- **Powerful safeguards**: Uses `ShouldProcess`, `-WhatIf`, and `-Confirm` to
ensure that deletion is intentional and carefully reviewed.

- **Handles special accounts**: Prevents accidental removal of critical system
or service accounts (e.g., `S-1-5-18`).

- **Remote profile removal**: Enables profile deletion from both local and remote
computers.

- **Verbose and error handling**: Logs every action taken and handles errors to
provide full transparency and avoid unexpected issues.

The feature is being heavily tested to ensure safety, reliability, and accuracy.

---
- **`$env:WinProfileOps_RegBackUpDirectory`**: Specifies the directory where
registry backups are stored. Default value: `"C:\LHStuff\RegBackUp"`.

## Contributing
- **`$env:WinProfileOps_ProfileFolderPath`**: The profile folder path, defaulting
to `"C:\Users"`, but can be customized based on the system's configuration.

Contributions are welcome! Feel free to fork the repository, submit pull requests,
or report issues. You can contribute by adding new features, improving the existing
code, or enhancing the documentation.
These variables are set automatically when the module is imported and are cleared
when the module is unloaded or the PowerShell session ends.
2 changes: 1 addition & 1 deletion RequiredModules.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#'WinRegOps' = '0.3.0'

'WinRegOps' = @{
Version = '0.4.0-preview0001'
Version = '0.4.0-preview0003'
Parameters = @{
AllowPrerelease = $true
Repository = "PSGallery"
Expand Down
41 changes: 38 additions & 3 deletions source/Classes/ProfileDeletionResult.ps1
Original file line number Diff line number Diff line change
@@ -1,16 +1,51 @@
class ProfileDeletionResult {
class ProfileDeletionResult
{
[string]$SID
[string]$ProfilePath
[bool]$DeletionSuccess
[string]$DeletionMessage
[string]$ComputerName

# Constructor to initialize the properties
ProfileDeletionResult([string]$sid, [string]$profilePath, [bool]$deletionSuccess, [string]$deletionMessage, [string]$computerName) {
# Constructor 1: Full constructor
ProfileDeletionResult([string]$sid, [string]$profilePath, [bool]$deletionSuccess, [string]$deletionMessage, [string]$computerName)
{
$this.SID = $sid
$this.ProfilePath = $profilePath
$this.DeletionSuccess = $deletionSuccess
$this.DeletionMessage = $deletionMessage
$this.ComputerName = $computerName
}

# Constructor 2: Only SID and DeletionSuccess, with default values for others
ProfileDeletionResult([string]$sid, [bool]$deletionSuccess)
{
$this.SID = $sid
$this.ProfilePath = $null
$this.DeletionSuccess = $deletionSuccess
if ($deletionSuccess)
{
$this.DeletionMessage = "Operation successful"
}
else
{
$this.DeletionMessage = "Operation failed"
}
$this.ComputerName = $env:COMPUTERNAME
}

# Constructor 3: Minimal constructor with defaults for all except SID
ProfileDeletionResult([string]$sid)
{
$this.SID = $sid
$this.ProfilePath = $null
$this.DeletionSuccess = $false
$this.DeletionMessage = "No action performed"
$this.ComputerName = $env:COMPUTERNAME
}

# Optional method
[string] ToString()
{
return "[$($this.SID)] DeletionSuccess: $($this.DeletionSuccess), Message: $($this.DeletionMessage)"
}
}
4 changes: 4 additions & 0 deletions source/Classes/UserProfile.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ class UserProfile
[string]$OrphanReason = $null
[string]$ComputerName
[bool]$IsSpecial
[string] GetUserNameFromPath() {
return [System.IO.Path]::GetFileName($this.ProfilePath) # Extract the leaf (username) from the ProfilePath
}


# Constructor to initialize the properties
UserProfile([string]$sid, [string]$profilePath, [bool]$isOrphaned, [string]$orphanReason, [string]$computerName, [bool]$isSpecial)
Expand Down
Loading

0 comments on commit ac68f80

Please sign in to comment.