Skip to content

Commit

Permalink
Merge pull request #2 from LarryWisherMan/feature/DocsAndTests
Browse files Browse the repository at this point in the history
Add comment-based help for all functions and completed Private unit tests
  • Loading branch information
LarryWisherMan authored Sep 11, 2024
2 parents 6690141 + ec96265 commit b5b8137
Show file tree
Hide file tree
Showing 37 changed files with 1,911 additions and 235 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added core functions
- configured `WinRegOps` as a dependant module
- Updated build file for release

- Comment-based help documentation added for the following public functions:
- `Get-AllUserProfiles`
- `Get-OrphanedProfiles`
- `Remove-OrphanedProfiles`
- `Remove-SIDProfile`
- `Get-UserProfileFolders`
- `Get-RegistryUserProfiles`
- `Get-UserFolders`
- `Get-SIDProfileInfo`

- Comment-based help documentation added for the following public functions:
- `New-UserProfileObject`
- `Remove-RegistryKeyForSID`
- `Remove-ProfilesForSIDs`
- `Get-RegistryKeyForSID`
- `Get-ProfilePathFromSID`
- `Test-FolderExists`
- `Test-OrphanedProfile`
- `Test-SpecialAccount`

- Implemented and completed Unit Tests for private functions
168 changes: 150 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,156 @@

# WinProfileOps

The WinProfileOps module provides an essential toolkit for managing Windows user profiles across local and remote computers. This module automates complex profile management tasks such as detecting orphaned profiles, validating profile paths, and removing stale or corrupted profiles. It handles both filesystem and registry operations, leveraging its dependency on WinRegOps for registry-related functions.
<p align="center">
<img src="https://raw.githubusercontent.com/LarryWisherMan/ModuleIcons/main/WinProfileOps.png"
alt="WinProfileOps Icon" width="400" />
</p>

The **WinProfileOps** module provides a robust toolkit for managing Windows user
profiles on both local and remote computers. This module simplifies and automates
complex profile management tasks, such as detecting orphaned profiles, validating
profile paths, and removing stale or corrupted profiles. It handles both filesystem
and registry operations, utilizing the **WinRegOps** module for registry-related
functions.

**WinProfileOps** seamlessly integrates with **WinRegOps** to manage profiles by
querying, validating, and deleting user profile-related data from the Windows
registry. This module is ideal for system administrators who want to streamline
profile management operations, especially in environments with numerous users and
computers.

---

## Dependencies

- **WinRegOps**: The **WinProfileOps** module depends on
[**WinRegOps**](https://github.com/LarryWisherMan/WinRegOps) for registry
operations such as querying, opening, and modifying registry keys related to user
profiles.

---

## Key Features

- **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.
- **Remove orphaned or unused profiles** from the system safely.
- **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.
- **Automating stale profile removal** on both local and remote systems to save disk
space and improve performance.
- **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.

---

## Installation

You have two options to install **WinProfileOps**:

1. **Install from PowerShell Gallery**
You can install the module directly from the
[PowerShell Gallery](https://www.powershellgallery.com/packages/WinProfileOps)
using the `Install-Module` command:

```powershell
Install-Module -Name WinProfileOps
```

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

---

## Usage

#### Example 1: Detecting Orphaned Profiles

Use the `Get-OrphanedProfiles` function to detect orphaned profiles on a local or
remote machine:

```powershell
$orphanedProfiles = Get-OrphanedProfiles -ComputerName "RemotePC" -IgnoreSpecial
```

This retrieves all orphaned profiles on `RemotePC`, excluding special accounts.

#### Example 2: Removing Orphaned Profiles

The `Remove-OrphanedProfiles` function allows you to remove orphaned profiles from
a system:

```powershell
Remove-OrphanedProfiles -ComputerName "RemotePC" -WhatIf
```

This will show what would happen if the orphaned profiles on `RemotePC` were
deleted, without performing the deletion.

#### Example 3: Retrieving User Profiles from the Registry

Use the `Get-UserProfilesFromRegistry` function to query user profiles from the
Windows registry:

```powershell
$registryProfiles = Get-UserProfilesFromRegistry -ComputerName "LocalHost"
```

This retrieves user profiles from the registry on `LocalHost`.

#### Example 4: Removing a Specific Profile

You can remove a specific profile from the registry using `Remove-SIDProfile`:

```powershell
Remove-SIDProfile -SID "S-1-5-21-123456789-1001" -ComputerName "Server01"
```

This removes the registry key for the profile associated with the specified SID on
`Server01`.

---

## Key Functions

WinProfileOps integrates with WinRegOps to seamlessly manage profiles by querying, validating, and deleting user profile-related data from the Windows registry. This module is ideal for system administrators seeking to streamline profile management operations, especially in environments with numerous users and computers.
- **`Get-OrphanedProfiles`**: Detects orphaned profiles by checking both the
registry and file system.
- **`Remove-OrphanedProfiles`**: Safely removes orphaned profiles, with support for
`-WhatIf` and `-Confirm`.
- **`Get-UserProfilesFromRegistry`**: Retrieves user profiles from the Windows
registry.
- **`Get-UserProfilesFromFolders`**: Retrieves user profile folders from the file
system.
- **`Remove-SIDProfile`**: Removes a user profile from the registry based on the
SID.
- **`Test-SpecialAccount`**: Checks if a user profile is considered special or
system-related.

Dependencies:
- WinRegOps: The WinProfileOps module depends on WinRegOps for registry operations such as querying, opening, and modifying registry keys related to user profiles.
---

Key features:
- Retrieve user profile information from both the registry and file system (local and remote).
- Detect orphaned profiles (e.g., missing profile folders or registry entries).
- Remove orphaned or unused profiles from the system.
- Filter and exclude special accounts like system or service accounts.
- Built-in support for remote profile management.
- Error handling for permission issues or unreachable systems.
- Class-based profile objects for easy integration with other automation tasks.
## Contributing

Typical use cases include:
- Cleaning up orphaned user profiles after system migrations or user deactivations.
- Automating the detection and removal of stale profiles on local and remote systems.
- Managing user profiles in large-scale, multi-user environments (e.g., terminal servers, Citrix environments).
- Excluding system accounts from profile cleanup operations, ensuring important profiles remain intact.
- Providing profile management capabilities as part of system maintenance routines.
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.
12 changes: 2 additions & 10 deletions RequiredModules.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,6 @@
ChangelogManagement = 'latest'
Sampler = 'latest'
'Sampler.GitHubTasks' = 'latest'
#'WisherTools.Helpers' = 'latest'
'WinRegOps' = @{
Version = '0.3.0-preview0003'
Parameters = @{
AllowPrerelease = $true
Repository = "PSGallery"
}
}


'WisherTools.Helpers' = 'latest'
'WinRegOps' = '0.3.0'
}
4 changes: 2 additions & 2 deletions build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Path to the Module Manifest to build (where path will be resolved from)
# SourcePath: ./Sampler/Sampler.psd1
# Output Directory where ModuleBuilder will build the Module, relative to module manifest
OutputDirectory: ../output/module
#OutputDirectory: ../output/module
BuiltModuleSubdirectory: module
CopyPaths:
- en-US
Expand Down Expand Up @@ -103,7 +103,7 @@ Pester:
# - tests/Unit
# - tests/Integration
ExcludeTag:
- helpQuality
#- helpQuality
- FunctionalQuality
- TestQuality
Tag:
Expand Down
8 changes: 5 additions & 3 deletions source/Classes/UserProfile.ps1
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
class UserProfile {
class UserProfile
{
[string]$SID
[string]$ProfilePath
[bool]$IsOrphaned
[string]$OrphanReason
[string]$OrphanReason = $null
[string]$ComputerName
[bool]$IsSpecial

# Constructor to initialize the properties
UserProfile([string]$sid, [string]$profilePath, [bool]$isOrphaned, [string]$orphanReason, [string]$computerName, [bool]$isSpecial) {
UserProfile([string]$sid, [string]$profilePath, [bool]$isOrphaned, [string]$orphanReason, [string]$computerName, [bool]$isSpecial)
{
$this.SID = $sid
$this.ProfilePath = $profilePath
$this.IsOrphaned = $isOrphaned
Expand Down
38 changes: 38 additions & 0 deletions source/Private/Get-ProfilePathFromSID.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<#
.SYNOPSIS
Retrieves the profile path associated with a specific SID from the registry.
.DESCRIPTION
The Get-ProfilePathFromSID function retrieves the "ProfileImagePath" registry value for the provided SID registry key. This path indicates the location of the user profile associated with the SID.
.PARAMETER SidKey
The registry key representing the Security Identifier (SID) from which to retrieve the profile path.
.EXAMPLE
Get-ProfilePathFromSID -SidKey $sidKey
Retrieves the profile path for the given SID from the registry.
.NOTES
If the "ProfileImagePath" cannot be found, the function will return `$null` and a verbose message will indicate the issue.
In case of an error during retrieval, an error message is logged and the function returns `$null`.
#>
function Get-ProfilePathFromSID
{
param (
[Microsoft.Win32.RegistryKey]$SidKey
)

try
{
# Use Get-RegistryValue to retrieve the "ProfileImagePath"
$profileImagePath = Get-RegistryValue -Key $SidKey -ValueName "ProfileImagePath"

if (-not $profileImagePath)
{
Write-Verbose "ProfileImagePath not found for SID '$($SidKey.Name)'."
}

return $profileImagePath
}
catch
{
Write-Error "Failed to retrieve ProfileImagePath for SID '$($SidKey.Name)'. Error: $_"
return $null
}
}
40 changes: 40 additions & 0 deletions source/Private/Get-RegistryKeyForSID.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<#
.SYNOPSIS
Retrieves the registry key associated with a specified SID from the ProfileList.
.DESCRIPTION
The Get-RegistryKeyForSID function attempts to open and retrieve the registry subkey for a given Security Identifier (SID) from the ProfileList. If the SID does not exist or an error occurs while accessing the registry, the function returns `$null` and logs a warning or error message.
.PARAMETER SID
The Security Identifier (SID) for which to retrieve the registry subkey.
.PARAMETER ProfileListKey
The opened registry key representing the ProfileList, which contains the subkeys for user profiles.
.EXAMPLE
Get-RegistryKeyForSID -SID "S-1-5-21-123456789-1001" -ProfileListKey $profileListKey
Retrieves the registry subkey associated with the specified SID from the ProfileList.
.NOTES
If the registry key for the SID cannot be found or accessed, the function returns `$null` and logs an appropriate warning or error message.
The function relies on the Open-RegistrySubKey function to retrieve the subkey.
#>
function Get-RegistryKeyForSID
{
param (
[string]$SID,
[Microsoft.Win32.RegistryKey]$ProfileListKey
)

try
{
# Use the general Open-RegistrySubKey function to get the subkey for the SID
$sidKey = Open-RegistrySubKey -ParentKey $ProfileListKey -SubKeyName $SID
if ($sidKey -eq $null)
{
Write-Warning "The SID '$SID' does not exist in the ProfileList registry."
return $null
}
return $sidKey
}
catch
{
Write-Error "Error accessing registry key for SID '$SID'. Error: $_"
return $null
}
}
45 changes: 45 additions & 0 deletions source/Private/New-UserProfileObject.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<#
.SYNOPSIS
Creates a new UserProfile object.
.DESCRIPTION
The New-UserProfileObject function creates and returns an instance of the UserProfile class. The function takes in various parameters such as SID, profile path, and whether the profile is orphaned or special, and returns a UserProfile object with these details.
.PARAMETER SID
The Security Identifier (SID) of the user profile.
.PARAMETER ProfilePath
The file path to the user profile folder.
.PARAMETER IsOrphaned
A boolean value indicating whether the profile is orphaned (i.e., exists in the registry but not on disk, or vice versa).
.PARAMETER OrphanReason
A description of why the profile is considered orphaned, if applicable.
.PARAMETER ComputerName
The name of the computer where the profile is located.
.PARAMETER IsSpecial
A boolean value indicating whether the profile is for a special account (e.g., system or default accounts).
.EXAMPLE
New-UserProfileObject -SID "S-1-5-21-123456789-1001" -ProfilePath "C:\Users\John" -IsOrphaned $true -OrphanReason "MissingRegistryEntry" -ComputerName "Server01" -IsSpecial $false
Creates a new UserProfile object for the profile associated with the given SID, marking it as orphaned with a reason.
.NOTES
This function returns an instance of the UserProfile class, which is used for managing and reporting on user profiles across different systems.
#>

function New-UserProfileObject
{
[outputType([UserProfile])]
param (
[string]$SID,
[string]$ProfilePath,
[bool]$IsOrphaned,
[string]$OrphanReason = $null,
[string]$ComputerName,
[bool]$IsSpecial
)

return [UserProfile]::new(
$SID,
$ProfilePath,
$IsOrphaned,
$OrphanReason,
$ComputerName,
$IsSpecial
)
}
Loading

0 comments on commit b5b8137

Please sign in to comment.