WinProfileOps.psm1

#Region './prefix.ps1' -1

# Your functions


# Check if the current user is an administrator
$windowsIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
$windowsPrincipal = New-Object Security.Principal.WindowsPrincipal($windowsIdentity)
$isAdmin = $windowsPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

# Set the environment variable based on whether the user is an admin
if ($isAdmin)
{
    $ENV:WinProfileOps_IsAdmin = $true
}
else
{
    $ENV:WinProfileOps_IsAdmin = $false
}

Write-Verbose "User is an administrator: $ENV:WinProfileOps_IsAdmin"

[scriptblock]$SB = {
    if (Test-Path Env:\WinProfileOps_IsAdmin)
    {
        Remove-Item Env:\WinProfileOps_IsAdmin
        Write-Verbose "WinProfileOps: Removed WinProfileOps_IsAdmin environment variable."
    }
}

Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {
    $sb.Invoke()
}

# Define the OnRemove script block for the module
$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
    $sb.Invoke()
}
#EndRegion './prefix.ps1' 37
#Region './Classes/ProfileDeletionResult.ps1' -1

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) {
        $this.SID = $sid
        $this.ProfilePath = $profilePath
        $this.DeletionSuccess = $deletionSuccess
        $this.DeletionMessage = $deletionMessage
        $this.ComputerName = $computerName
    }
}
#EndRegion './Classes/ProfileDeletionResult.ps1' 17
#Region './Classes/UserProfile.ps1' -1

class UserProfile
{
    [string]$SID
    [string]$ProfilePath
    [bool]$IsOrphaned
    [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)
    {
        $this.SID = $sid
        $this.ProfilePath = $profilePath
        $this.IsOrphaned = $isOrphaned
        $this.OrphanReason = $orphanReason
        $this.ComputerName = $computerName
        $this.IsSpecial = $isSpecial
    }
}
#EndRegion './Classes/UserProfile.ps1' 21
#Region './Private/Get-ProfilePathFromSID.ps1' -1

<#
.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
    }
}
#EndRegion './Private/Get-ProfilePathFromSID.ps1' 39
#Region './Private/Get-RegistryKeyForSID.ps1' -1

<#
.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
    }
}
#EndRegion './Private/Get-RegistryKeyForSID.ps1' 41
#Region './Private/Get-SIDProfileInfo.ps1' -1

<#
.SYNOPSIS
    Retrieves profile information from the registry for all SIDs on a specified computer.

.DESCRIPTION
    The Get-SIDProfileInfo function queries the ProfileList registry key on the specified computer and retrieves
    profile information for each Security Identifier (SID). It validates the SID format, opens the corresponding
    registry subkeys, and fetches the ProfileImagePath for each valid SID. The function returns a list of profiles,
    including details such as the SID, profile path, and whether the profile exists in the registry.

.PARAMETER ComputerName
    The name of the computer from which to retrieve profile information. Defaults to the local computer.

.EXAMPLE
    Get-SIDProfileInfo -ComputerName "Server01"
    Retrieves profile information for all valid SIDs stored in the registry on "Server01".

.EXAMPLE
    Get-SIDProfileInfo
    Retrieves profile information for all valid SIDs stored in the registry on the local computer.

.OUTPUTS
    [PSCustomObject[]]
    An array of custom objects, where each object contains the following properties:
        - SID: [string] The Security Identifier of the profile.
        - ProfilePath: [string] The path to the user profile folder in the file system.
        - ComputerName: [string] The name of the computer from which the profile information was retrieved.
        - ExistsInRegistry: [bool] Indicates whether the profile exists in the registry.

.NOTES
    - If a registry subkey for an SID cannot be opened, a warning is written to the output.
    - Invalid SID formats are skipped with a warning.
    - If a ProfileImagePath is not found for a valid SID, a verbose message is logged and the profile is returned
      with a null ProfilePath.
    - The function returns an empty array if no SIDs are found or if the registry path cannot be opened.
#>

function Get-SIDProfileInfo
{
    [OutputType([PSCustomObject[]])]
    [CmdletBinding()]
    param (
        [string]$ComputerName = $env:COMPUTERNAME
    )

    $RegistryPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
    $ProfileListKey = Open-RegistryKey -RegistryPath $RegistryPath -ComputerName $ComputerName

    # Handle null or empty registry key
    if (-not $ProfileListKey)
    {
        Write-Error "Failed to open registry path: $RegistryPath on $ComputerName."
        return @()  # Return an empty array
    }

    $subKeyNames = $ProfileListKey.GetSubKeyNames()

    # If no SIDs are found, return an empty array
    if (-not $subKeyNames -or $subKeyNames.Count -eq 0)
    {
        Write-Verbose "No SIDs found in the registry key on $ComputerName."
        return @()  # Return an empty array
    }

    $ProfileRegistryItems = foreach ($sid in $subKeyNames)
    {
        # Validate SID format (SIDs typically start with 'S-1-' and follow a specific pattern)
        if (-not (Validate-SIDFormat -SID $sid))
        {
            continue
        }

        # Use Open-RegistrySubKey to get the subkey for the SID
        $subKey = Open-RegistrySubKey -ParentKey $ProfileListKey -SubKeyName $sid

        if ($subKey -eq $null)
        {
            Write-Warning "Registry key for SID '$sid' could not be opened."
            continue
        }

        # Use Get-ProfilePathFromSID to get the ProfileImagePath for the SID
        $profilePath = Get-ProfilePathFromSID -SidKey $subKey

        if (-not $profilePath)
        {
            Write-Verbose "ProfileImagePath not found for SID '$sid'."
            $profilePath = $null
        }

        # Return a PSCustomObject with SID, ProfilePath, and ComputerName
        [PSCustomObject]@{
            SID              = $sid
            ProfilePath      = $profilePath
            ComputerName     = $ComputerName
            ExistsInRegistry = $true
        }
    }

    return $ProfileRegistryItems
}


#EndRegion './Private/Get-SIDProfileInfo.ps1' 103
#Region './Private/Get-SIDProfileInfoFallback.ps1' -1

<#
.SYNOPSIS
    Retrieves non-special user profile information from a remote or local computer.

.DESCRIPTION
    The Get-SIDProfileInfoFallback function uses the CIM (Common Information Model) method to retrieve user profile
    information from the specified computer. It filters out special profiles and returns the SID, profile path, and other
    relevant information for each user profile found on the system. This function serves as a fallback method for obtaining
    profile information without requiring administrative privileges to access the registry.

.PARAMETER ComputerName
    The name of the computer to query for user profiles. If not provided, the function will default to the local computer.

.OUTPUTS
    [PSCustomObject[]]
        Returns an array of PSCustomObject where each object contains:
            - SID: The security identifier for the user profile.
            - ProfilePath: The local file system path to the user profile.
            - ComputerName: The name of the computer from which the profile was retrieved.
            - ExistsInRegistry: Always set to $true, as this function is a fallback and does not query the registry directly.

.EXAMPLE
    Get-SIDProfileInfoFallback

    Retrieves non-special user profiles from the local computer and returns their SID, profile path, and other details.

.EXAMPLE
    Get-SIDProfileInfoFallback -ComputerName "Server01"

    Retrieves non-special user profiles from the remote computer "Server01" and returns their SID, profile path, and other details.

.NOTES
    This function does not require administrative privileges to access profile information, as it relies on CIM/WMI methods
    to retrieve data. It specifically filters out special profiles (such as system profiles) using the "Special=False" filter.
#>


function Get-SIDProfileInfoFallback
{
    [OutputType([PSCustomObject[]])]
    [CmdletBinding()]
    param (
        [string]$ComputerName = $env:COMPUTERNAME
    )
    # Use CIM as a fallback method to get user profile information
    $profiles = Get-CimInstance -ClassName Win32_UserProfile -ComputerName $ComputerName -Filter "Special=False"

    $ProfileRegistryItems = foreach ($profile in $profiles)
    {
        # Return a PSCustomObject similar to what Get-SIDProfileInfo returns
        [PSCustomObject]@{
            SID              = $profile.SID
            ProfilePath      = $profile.LocalPath
            ComputerName     = $ComputerName
            ExistsInRegistry = $true
        }
    }

    return $ProfileRegistryItems
}
#EndRegion './Private/Get-SIDProfileInfoFallback.ps1' 60
#Region './Private/Get-UserFolders.ps1' -1

<#
.SYNOPSIS
    Retrieves a list of user profile folders from a specified computer.
.DESCRIPTION
    The Get-UserFolders function scans the user profile directory on the specified computer
    and returns a list of folders that represent user profiles. It determines whether the
    target computer is local or remote and retrieves information such as the folder name,
    profile path, and computer name for each folder.

    If an error occurs during the folder retrieval, the function logs the error and returns
    an empty array.
.PARAMETER ComputerName
    The name of the computer from which to retrieve user profile folders. If not provided,
    defaults to the local computer.
.PARAMETER ProfileFolderPath
    The path to the folder where user profiles are stored. Defaults to "$env:SystemDrive\Users".
    This can be overridden to target a custom directory path for user profiles.
.OUTPUTS
    [PSCustomObject[]]
    An array of custom objects, where each object contains the following properties:
        - FolderName: [string] The name of the user profile folder.
        - ProfilePath: [string] The full path to the user profile folder.
        - ComputerName: [string] The name of the computer from which the user profile folder
          was retrieved.
.EXAMPLE
    Get-UserFolders -ComputerName "Server01" -ProfileFolderPath "D:\UserProfiles"
    Retrieves a list of user profile folders from the "D:\UserProfiles" directory on "Server01".
.EXAMPLE
    Get-UserFolders -ComputerName $env:COMPUTERNAME
    Retrieves a list of user profile folders from the local computer's default user directory.
.EXAMPLE
    Get-UserFolders -ComputerName "RemotePC"
    Retrieves a list of user profile folders from the default user directory on the remote computer
    "RemotePC".
.NOTES
    - If the Get-ChildItem command fails (e.g., due to access issues), the function logs an error
      and returns an empty array.
    - The ProfilePath for local computers is returned as a local path, while for remote computers,
      the folder is first accessed using a UNC path, but the returned ProfilePath is formatted as a
      local path for consistency.
    - Use the optional ProfileFolderPath parameter to target custom directories for user profiles.
#>


function Get-UserFolders
{
    [OutputType([PSCustomObject[]])]
    [CmdletBinding()]
    param (
        [string]$ComputerName = $env:COMPUTERNAME,
        [string]$ProfileFolderPath = "$env:SystemDrive\Users"
    )

    $IsLocal = ($ComputerName -eq $env:COMPUTERNAME)
    $FolderPath = Get-DirectoryPath -BasePath $ProfileFolderPath -ComputerName $ComputerName -IsLocal $IsLocal

    try
    {
        # Get list of all folders in the user profile directory
        $ProfileFolders = Get-ChildItem -Path $FolderPath -Directory | ForEach-Object {
            [PSCustomObject]@{
                FolderName   = $_.Name
                ProfilePath  = Get-DirectoryPath -BasePath $_.FullName -ComputerName $ComputerName -IsLocal $true
                ComputerName = $ComputerName
            }
        }

        return $ProfileFolders
    }
    catch
    {
        # Handle the error when Get-ChildItem fails
        Write-Error "Failed to retrieve folders from '$FolderPath' on '$ComputerName'. Error: $_"
        return @()  # Return an empty array in case of failure
    }
}
#EndRegion './Private/Get-UserFolders.ps1' 76
#Region './Private/New-UserProfileObject.ps1' -1

<#
.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
    )
}
#EndRegion './Private/New-UserProfileObject.ps1' 46
#Region './Private/Remove-RegistryKeyForSID.ps1' -1

<#
.SYNOPSIS
    Deletes a registry key associated with a specific SID from the ProfileList.
.DESCRIPTION
    The Remove-RegistryKeyForSID function deletes the registry key corresponding to a specific Security Identifier (SID) from the ProfileList in the Windows registry. It supports confirmation prompts and simulates actions with the -WhatIf parameter.
.PARAMETER SID
    The Security Identifier (SID) for which the registry key should be deleted.
.PARAMETER ProfileListKey
    The opened registry key representing the ProfileList where the profile's SID is located.
.PARAMETER ComputerName
    The name of the computer where the profile registry key resides. By default, this is the current computer.
.EXAMPLE
    Remove-RegistryKeyForSID -SID "S-1-5-21-123456789-1001" -ProfileListKey $profileListKey -ComputerName "Server01"
    Deletes the registry key for the specified SID from the ProfileList on "Server01".
.NOTES
    This function supports 'ShouldProcess', so it can be used in conjunction with the -WhatIf or -Confirm parameters to simulate the deletion.
    It also includes error handling to ensure any failure during the registry key deletion is captured.
#>


function Remove-RegistryKeyForSID
{
    # Deletes a single registry key for a SID.
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    param (
        [Parameter(Mandatory = $true)]
        [string]$SID,

        [Parameter(Mandatory = $true)]
        [Microsoft.Win32.RegistryKey]$ProfileListKey,

        [Parameter(Mandatory = $true)]
        [string]$ComputerName = $env:COMPUTERNAME
    )

    try
    {
        # Check if ShouldProcess is approved (with -WhatIf and -Confirm support)
        if ($PSCmdlet.ShouldProcess("SID: $SID on $ComputerName", "Remove registry key"))
        {
            # Use the general Remove-RegistrySubKey function to delete the SID's subkey
            return Remove-RegistrySubKey -ParentKey $ProfileListKey -SubKeyName $SID -ComputerName $ComputerName -Confirm:$false
        }
        else
        {
            Write-Verbose "Removal of registry key for SID '$SID' was skipped."
            return $false
        }
    }
    catch
    {
        Write-Error "Failed to remove the profile registry key for SID '$SID' on $ComputerName. Error: $_"
        return $false
    }
}
#EndRegion './Private/Remove-RegistryKeyForSID.ps1' 55
#Region './Private/Remove-SIDProfile.ps1' -1

<#
.SYNOPSIS
    Coordinates the deletion of a profile registry key for a given SID.

.DESCRIPTION
    The Remove-SIDProfile function removes the registry key associated with a specific Security Identifier (SID) from the ProfileList on the specified computer. It supports confirmation prompts and -WhatIf scenarios by using the ShouldProcess pattern. The function also handles errors that occur during the deletion process and returns a ProfileDeletionResult object indicating success or failure.

.PARAMETER SID
    The Security Identifier (SID) of the profile to be deleted.

.PARAMETER ProfileListKey
    The registry key representing the ProfileList from which the SID's registry key will be removed.

.PARAMETER ComputerName
    The name of the computer where the profile registry key resides. Defaults to the current computer.

.PARAMETER ProfilePath
    The file path of the profile to be deleted, used for logging purposes in the ProfileDeletionResult object.

.OUTPUTS
    [ProfileDeletionResult]
    An object that indicates whether the profile registry key was successfully deleted or if the action was skipped or failed. Includes the SID, ProfilePath, DeletionSuccess status, DeletionMessage, and ComputerName.

.EXAMPLE
    Remove-SIDProfile -SID "S-1-5-21-123456789-1001" -ProfileListKey $profileListKey -ComputerName "Server01" -ProfilePath "C:\Users\John"
    Removes the registry key for the specified SID from the ProfileList on "Server01" and deletes the profile.

.EXAMPLE
    Remove-SIDProfile -SID "S-1-5-21-123456789-1001" -ProfileListKey $profileListKey -ProfilePath "C:\Users\John" -WhatIf
    Simulates the removal of the profile registry key for the specified SID using the -WhatIf parameter, showing what would have been done without performing the action.

.NOTES
    - The function supports 'ShouldProcess', allowing the use of -WhatIf and -Confirm parameters for safety.
    - In case of an error, the function returns a ProfileDeletionResult object with DeletionSuccess set to $false and logs the error message.
    - If the action is skipped (e.g., due to -WhatIf or confirmation denial), the function returns a ProfileDeletionResult with a status indicating that the action was skipped.
#>


function Remove-SIDProfile
{
    [outputtype([ProfileDeletionResult])]
    # Coordinates the registry key deletion and provides a result for a single SID.
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    param (
        [string]$SID,
        [Microsoft.Win32.RegistryKey]$ProfileListKey,
        [string]$ComputerName,
        [string]$ProfilePath
    )

    try
    {
        # Use ShouldProcess to check if the action should proceed (with -WhatIf and -Confirm support)
        if ($PSCmdlet.ShouldProcess("SID: $SID on $ComputerName", "Remove profile registry key"))
        {
            # Attempt to remove the registry key
            $deletionSuccess = Remove-RegistryKeyForSID -SID $SID -ProfileListKey $ProfileListKey -ComputerName $ComputerName

            if ($deletionSuccess)
            {
                return [ProfileDeletionResult]::new(
                    $SID,
                    $ProfilePath,
                    $true,
                    "Profile registry key for SID '$SID' successfully deleted.",
                    $ComputerName
                )
            }
            else
            {
                return [ProfileDeletionResult]::new(
                    $SID,
                    $ProfilePath,
                    $false,
                    "Failed to delete the profile registry key for SID '$SID'.",
                    $ComputerName
                )
            }
        }
        else
        {
            Write-Verbose "Removal of profile registry key for SID '$SID' on '$ComputerName' was skipped."
            return [ProfileDeletionResult]::new(
                $SID,
                $ProfilePath,
                $false,
                "Action skipped.",
                $ComputerName
            )
        }
    }
    catch
    {
        Write-Error "Failed to remove the profile registry key for SID '$SID' on $ComputerName. Error: $_"
        return [ProfileDeletionResult]::new(
            $SID,
            $ProfilePath,
            $false,
            "Failed to delete the profile registry key for SID '$SID'. Error: $_",
            $ComputerName
        )
    }
}
#EndRegion './Private/Remove-SIDProfile.ps1' 103
#Region './Private/Test-FolderExists.ps1' -1

<#
.SYNOPSIS
    Checks if a profile folder exists on a specified computer.
.DESCRIPTION
    The Test-FolderExists function determines whether a given profile folder exists on the specified computer by testing the path.
    If the profile path or computer name is not provided, the function will default to using the local computer.
    In the event of any errors (e.g., invalid paths or inaccessible directories), the function returns $false and logs the error.

.PARAMETER ProfilePath
    The file path of the profile folder to check. This parameter is required. If it is null or empty, the function will return $false.
.PARAMETER ComputerName
    The name of the computer where the profile folder is located. If not provided, the local computer is used by default.
.OUTPUTS
    [bool]
        Returns $true if the folder exists at the specified path, and $false if it does not exist, or if an error occurs during execution.

.EXAMPLE
    Test-FolderExists -ProfilePath "C:\Users\John" -ComputerName "Server01"
    Checks if the folder "C:\Users\John" exists on "Server01".

.EXAMPLE
    Test-FolderExists -ProfilePath "C:\Users\Public"
    Checks if the folder "C:\Users\Public" exists on the local computer (since ComputerName is not specified).

.EXAMPLE
    Test-FolderExists -ProfilePath "C:\InvalidPath" -ComputerName "Server01"
    Returns $false if the specified folder does not exist or if an error occurs while accessing the path.

.NOTES
    The function includes error handling to catch and log any exceptions. In case of an error, the function returns $false.
#>


function Test-FolderExists
{
    [outputType([bool])]
    [cmdletbinding()]
    param (
        [string]$ProfilePath,
        [string]$ComputerName = $env:COMPUTERNAME
    )

    # Check for null or empty ProfilePath
    if (-not $ProfilePath)
    {
        Write-Warning "ProfilePath is null or empty."
        return $false
    }

    # Check for null or empty ComputerName and default to the local computer if it's null
    if (-not $ComputerName)
    {
        Write-Warning "ComputerName is null or empty. Defaulting to the local computer."
        $ComputerName = $env:COMPUTERNAME
    }

    try
    {
        # Determine if the computer is local or remote
        $IsLocal = $ComputerName -eq $env:COMPUTERNAME

        # Get the directory path to check
        $pathToCheck = Get-DirectoryPath -BasePath $ProfilePath -ComputerName $ComputerName -IsLocal $IsLocal

        # Return whether the path exists
        return Test-Path $pathToCheck
    }
    catch
    {
        Write-Error "An error occurred: $_"
        return $false
    }
}
#EndRegion './Private/Test-FolderExists.ps1' 73
#Region './Private/Test-OrphanedProfile.ps1' -1

<#
.SYNOPSIS
    Tests whether a profile is orphaned.
.DESCRIPTION
    The Test-OrphanedProfile function checks if a profile is orphaned by evaluating the profile path, folder existence, and whether it's a special account.
.PARAMETER SID
    The Security Identifier (SID) of the profile being tested.
.PARAMETER ProfilePath
    The file path of the profile folder.
.PARAMETER FolderExists
    Indicates whether the profile folder exists on the computer.
.PARAMETER IgnoreSpecial
    Switch to ignore special or default profiles when determining if the profile is orphaned.
.PARAMETER IsSpecial
    Indicates whether the profile is a special account.
.PARAMETER ComputerName
    The name of the computer where the profile is being tested.
.EXAMPLE
    Test-OrphanedProfile -SID "S-1-5-21-123456789-1001" -ProfilePath "C:\Users\John" -FolderExists $true -IgnoreSpecial -IsSpecial $false -ComputerName "Server01"
    Tests if the profile associated with the given SID is orphaned on "Server01".
#>


function Test-OrphanedProfile
{
    param (
        [string]$SID,
        [string]$ProfilePath,
        [bool]$FolderExists,
        [bool]$IgnoreSpecial,
        [bool]$IsSpecial,
        [string]$ComputerName
    )

    if (-not $ProfilePath)
    {
        return New-UserProfileObject $SID $null $true "MissingProfileImagePath" $ComputerName $IsSpecial
    }
    elseif (-not $FolderExists)
    {
        return New-UserProfileObject $SID $ProfilePath $true "MissingFolder" $ComputerName $IsSpecial
    }
    else
    {
        return New-UserProfileObject $SID $ProfilePath $false $null $ComputerName $IsSpecial
    }
}
#EndRegion './Private/Test-OrphanedProfile.ps1' 47
#Region './Private/Test-SpecialAccount.ps1' -1

<#
.SYNOPSIS
    Tests if a profile is considered a special or default account.
.DESCRIPTION
    The Test-SpecialAccount function checks whether the profile is a special or default account by comparing the folder name, Security Identifier (SID), and profile path to predefined lists of ignored accounts, SIDs, and paths.
    If the profile matches any of the predefined entries, it is considered a special account.
.PARAMETER FolderName
    The name of the folder representing the profile being tested.
.PARAMETER SID
    The Security Identifier (SID) of the profile being tested.
.PARAMETER ProfilePath
    The file path of the profile being tested.
.EXAMPLE
    Test-SpecialAccount -FolderName "DefaultAppPool" -SID "S-1-5-18" -ProfilePath "C:\WINDOWS\system32\config\systemprofile"
    Checks if the profile associated with the folder "DefaultAppPool", SID "S-1-5-18", and profile path "C:\WINDOWS\system32\config\systemprofile" is a special account.
.EXAMPLE
    Test-SpecialAccount -FolderName "JohnDoe" -SID "S-1-5-21-123456789-1001" -ProfilePath "C:\Users\JohnDoe"
    Tests a non-special account, which does not match any predefined special accounts.
.NOTES
    This function returns $true if the account is considered special, and $false otherwise.
#>

function Test-SpecialAccount
{
    param (
        [string]$FolderName,
        [string]$SID,
        [string]$ProfilePath
    )

    # List of default or special accounts to ignore
    $IgnoredAccounts = @(
        "defaultuser0", "DefaultAppPool", "servcm12", "Public", "PBIEgwService", "Default",
        "All Users", "win2kpro"
    )
    $IgnoredSIDs = @(
        "S-1-5-18", # Local System
        "S-1-5-19", # Local Service
        "S-1-5-20"  # Network Service
    )
    $IgnoredPaths = @(
        "C:\WINDOWS\system32\config\systemprofile", # System profile
        "C:\WINDOWS\ServiceProfiles\LocalService", # Local service profile
        "C:\WINDOWS\ServiceProfiles\NetworkService"  # Network service profile
    )

    # Check if the account is special based on the folder name, SID, or profile path
    return ($IgnoredAccounts -contains $FolderName) -or ($IgnoredSIDs -contains $SID) -or ($IgnoredPaths -contains $ProfilePath)
}
#EndRegion './Private/Test-SpecialAccount.ps1' 49
#Region './Private/UserProfileAudit/Process-FolderProfiles.ps1' -1

<#
.SYNOPSIS
    Processes user profile folders to identify profiles missing in the registry.

.DESCRIPTION
    The Process-FolderProfiles function compares user profiles found in the file system (folders)
    against those found in the registry. It identifies folder profiles that do not have a corresponding
    entry in the registry and marks them as orphaned. The function also allows the option to ignore
    special or default profiles, such as system or service accounts.

.PARAMETER UserFolders
    An array of user profile folders found in the file system (e.g., C:\Users).

.PARAMETER RegistryProfiles
    An array of user profiles found in the registry.

.PARAMETER ComputerName
    The name of the computer being audited for user profiles.

.PARAMETER IgnoreSpecial
    Switch to ignore special or default profiles (such as system or service accounts) during processing.

.OUTPUTS
    [UserProfile[]]
    Returns an array of UserProfile objects representing user profiles found in the file system but missing in the registry.

.EXAMPLE
    $userFolders = Get-UserProfilesFromFolders -ComputerName "Server01"
    $registryProfiles = Get-UserProfilesFromRegistry -ComputerName "Server01"
    Process-FolderProfiles -UserFolders $userFolders -RegistryProfiles $registryProfiles -ComputerName "Server01"

    Processes the user profile folders on "Server01" to identify any profiles missing from the registry.

.EXAMPLE
    Process-FolderProfiles -UserFolders $folders -RegistryProfiles $registryProfiles -ComputerName "Server01" -IgnoreSpecial

    Processes the user profile folders on "Server01" while ignoring special or system profiles.

.NOTES
    This function compares profiles in the file system with those in the registry to identify orphaned
    profiles that exist only in the file system. Special profiles can be ignored with the -IgnoreSpecial switch.
#>

function Process-FolderProfiles
{
    [OutputType ([UserProfile[]])]
    param (
        [array]$UserFolders,
        [array]$RegistryProfiles,
        [string]$ComputerName,
        [switch]$IgnoreSpecial
    )

    $processedProfiles = @()

    foreach ($folder in $UserFolders)
    {
        $registryProfile = $RegistryProfiles | Where-Object { $_.ProfilePath -eq $folder.ProfilePath }
        $isSpecial = Test-SpecialAccount -FolderName $folder.FolderName -SID $null -ProfilePath $folder.ProfilePath

        if ($IgnoreSpecial -and $isSpecial)
        {
            continue
        }

        if (-not $registryProfile)
        {
            $processedProfiles += New-UserProfileObject $null $folder.ProfilePath $true "MissingRegistryEntry" $ComputerName $isSpecial
        }
    }

    return $processedProfiles
}
#EndRegion './Private/UserProfileAudit/Process-FolderProfiles.ps1' 73
#Region './Private/UserProfileAudit/Process-RegistryProfiles.ps1' -1

<#
.SYNOPSIS
    Processes user profiles found in the registry to identify orphaned profiles.

.DESCRIPTION
    The Process-RegistryProfiles function compares user profiles found in the registry against the
    corresponding profile folders on the file system. It identifies registry profiles that are orphaned,
    meaning they exist in the registry but are missing in the file system. The function also provides an
    option to ignore special or default profiles, such as system or service accounts.

.PARAMETER RegistryProfiles
    An array of user profiles retrieved from the registry.

.PARAMETER ComputerName
    The name of the computer being audited for user profiles.

.PARAMETER IgnoreSpecial
    Switch to ignore special or default profiles (such as system or service accounts) during processing.

.OUTPUTS
    [UserProfile[]]
    Returns an array of UserProfile objects representing user profiles found in the registry but missing in the file system.

.EXAMPLE
    $registryProfiles = Get-UserProfilesFromRegistry -ComputerName "Server01"
    Process-RegistryProfiles -RegistryProfiles $registryProfiles -ComputerName "Server01"

    Processes the registry profiles on "Server01" to identify any profiles that are orphaned in the registry.

.EXAMPLE
    Process-RegistryProfiles -RegistryProfiles $registryProfiles -ComputerName "Server01" -IgnoreSpecial

    Processes the registry profiles on "Server01" while ignoring special or system profiles.

.NOTES
    This function compares profiles in the registry with their corresponding profile folders on the file system
    to identify orphaned profiles that exist only in the registry. Special profiles can be ignored with the -IgnoreSpecial switch.
#>

function Process-RegistryProfiles
{
    [OutputType ([UserProfile[]])]
    param (
        [array]$RegistryProfiles,
        [string]$ComputerName,
        [switch]$IgnoreSpecial
    )

    $processedProfiles = @()

    foreach ($regProfile in $RegistryProfiles)
    {
        $profilePath = $regProfile.ProfilePath
        $folderExists = Test-FolderExists -ProfilePath $profilePath -ComputerName $ComputerName
        $folderName = Split-Path -Path $profilePath -Leaf
        $isSpecial = Test-SpecialAccount -FolderName $folderName -SID $regProfile.SID -ProfilePath $profilePath

        if ($IgnoreSpecial -and $isSpecial)
        {
            continue
        }

        $userProfile = Test-OrphanedProfile -SID $regProfile.SID -ProfilePath $profilePath `
            -FolderExists $folderExists -IgnoreSpecial $IgnoreSpecial `
            -IsSpecial $isSpecial -ComputerName $ComputerName
        $processedProfiles += $userProfile
    }

    return $processedProfiles
}
#EndRegion './Private/UserProfileAudit/Process-RegistryProfiles.ps1' 70
#Region './Private/UserProfileAudit/Test-ComputerReachability.ps1' -1

<#
.SYNOPSIS
    Tests whether a specified computer is reachable by performing a network ping.

.DESCRIPTION
    The Test-ComputerReachability function checks whether a specified computer is reachable by using a ping
    test. If the computer is unreachable, the function logs a warning message and returns `$false`. If the
    computer is reachable, it returns `$true`.

.PARAMETER ComputerName
    The name of the computer to test for network reachability.

.OUTPUTS
    [bool]
    Returns `$true` if the computer is reachable, `$false` if the computer is offline or unreachable.

.EXAMPLE
    Test-ComputerReachability -ComputerName "Server01"

    Tests the reachability of "Server01" and returns `$true` if it is reachable, `$false` otherwise.

.NOTES
    This function uses Test-ComputerPing to perform the ping test. If the computer is offline or unreachable,
    a warning is logged and the function returns `$false`.
#>

function Test-ComputerReachability
{
    [OutputType ([bool])]
    param (
        [string]$ComputerName = $env:COMPUTERNAME
    )

    if ($ComputerName -eq $null)
    {
        Write-Warning "No computer name provided."
        return $false
    }

    if (-not (Test-ComputerPing -ComputerName $ComputerName))
    {
        Write-Warning "Computer '$ComputerName' is offline or unreachable."
        return $false
    }
    return $true
}
#EndRegion './Private/UserProfileAudit/Test-ComputerReachability.ps1' 46
#Region './Private/Validate-SIDFormat.ps1' -1

<#
.SYNOPSIS
    Validates whether a given string follows the correct SID (Security Identifier) format.

.DESCRIPTION
    The Validate-SIDFormat function checks if a given string matches the standard SID format.
    SIDs typically start with 'S-1-' followed by a series of digits separated by hyphens.
    This function returns $true if the SID format is valid and $false if it is not.

.PARAMETER SID
    The SID string to validate. This should follow the typical format: 'S-1-' followed by
    a series of digits and hyphens.

.OUTPUTS
    [bool]
    Returns $true if the SID format is valid; otherwise, returns $false.

.EXAMPLE
    PS> Validate-SIDFormat -SID 'S-1-5-18'
    True

    This example checks if the SID 'S-1-5-18' is valid.

.EXAMPLE
    PS> Validate-SIDFormat -SID 'Invalid-SID'
    WARNING: Invalid SID format encountered: 'Invalid-SID'.
    False

    This example demonstrates how the function handles an invalid SID format by returning $false
    and issuing a warning.

.NOTES

.LINK
    https://docs.microsoft.com/en-us/windows/win32/secauthz/security-identifiers

#>

function Validate-SIDFormat
{
    param (
        [OutPutType([bool])]
        [CmdletBinding()]
        [Parameter(Mandatory = $true)]
        [string]$SID
    )

    # Regular expression pattern for validating the SID format
    $sidPattern = '^S-1-\d+(-\d+)+$'

    if ($SID -notmatch $sidPattern)
    {
        Write-Warning "Invalid SID format encountered: '$SID'."
        return $false
    }

    return $true
}
#EndRegion './Private/Validate-SIDFormat.ps1' 58
#Region './Public/Get-OrphanedProfiles.ps1' -1

<#
.SYNOPSIS
    Retrieves orphaned user profiles from a specified computer.
.DESCRIPTION
    The Get-OrphanedProfiles function scans both the user profile folders and registry on a specified computer and returns profiles that are considered orphaned. Orphaned profiles are those that exist either in the file system but not in the registry, or in the registry but no longer have a corresponding folder in the file system.
.PARAMETER ComputerName
    The name of the computer from which to retrieve orphaned user profiles. Defaults to the local computer.
.PARAMETER ProfileFolderPath
    The path to the folder where user profiles are stored. Defaults to "$env:SystemDrive\Users".
.PARAMETER IgnoreSpecial
    Switch to ignore special or default profiles during the profile retrieval process.
.OUTPUTS
    [UserProfile[]]
    Returns an array of UserProfile objects that represent the profiles found during the audit. Each UserProfile object contains the following properties:
    - SID: [string] The security identifier of the user profile.
    - ProfilePath: [string] The file system path of the user profile.
    - IsOrphaned: [bool] Whether the profile is considered orphaned.
    - OrphanReason: [string] The reason for orphaned status if applicable.
    - ComputerName: [string] The name of the computer where the audit was performed.
    - IsSpecial: [bool] Whether the profile is considered special or a system account.
.EXAMPLE
    Get-OrphanedProfiles -ComputerName "Server01"
    Retrieves all orphaned user profiles from both the file system and registry on "Server01".
.EXAMPLE
    Get-OrphanedProfiles -ProfileFolderPath "D:\UserProfiles" -IgnoreSpecial
    Retrieves orphaned user profiles from the specified folder and ignores special or default profiles.
.NOTES
    This function filters orphaned profiles based on the results of the Invoke-UserProfileAudit function.
#>

function Get-OrphanedProfiles
{
    [CmdletBinding()]
    [OutputType([UserProfile[]])]
    param (
        [string]$ComputerName = $env:COMPUTERNAME,
        [string]$ProfileFolderPath = "$env:SystemDrive\Users",
        [switch]$IgnoreSpecial
    )

    # Call Invoke-UserProfileAudit to get all profiles
    $allProfiles = Invoke-UserProfileAudit -ComputerName $ComputerName -ProfileFolderPath $ProfileFolderPath -IgnoreSpecial:$IgnoreSpecial

    # Filter to return only orphaned profiles
    $orphanedProfiles = $allProfiles | Where-Object { $_.IsOrphaned }

    # Handle the case where no orphaned profiles are found
    if (-not $orphanedProfiles)
    {
        Write-Verbose "No orphaned profiles found on computer '$ComputerName'."
        return @()  # Return an empty array
    }

    return $orphanedProfiles
}
#EndRegion './Public/Get-OrphanedProfiles.ps1' 55
#Region './Public/Get-UserProfilesFromFolders.ps1' -1

<#
.SYNOPSIS
    Retrieves user profile folders from a specified computer.
.DESCRIPTION
    The Get-UserProfilesFromFolders function scans the user profile directory on the specified
    computer and returns information about the user profile folders found. This function is useful
    for identifying profile folders stored on disk, which may or may not match entries in the registry.
    The function checks if the specified computer is online before attempting to retrieve the profile folders.
    If the computer is unreachable, it logs a warning and returns an empty array.
.PARAMETER ComputerName
    The name of the computer from which to retrieve user profile folders. Defaults to the local computer.
.PARAMETER ProfileFolderPath
    The path to the folder where user profiles are stored. Defaults to "$env:SystemDrive\Users".
.OUTPUTS
    PSCustomObject[]
    Returns an array of custom objects representing the user profile folders found. Each object contains:
    - FolderName: The name of the user profile folder.
    - ProfilePath: The full path to the user profile folder.
    - ComputerName: The name of the computer where the profile folder was retrieved from.
.EXAMPLE
    Get-UserProfilesFromFolders -ComputerName "Server01" -ProfileFolderPath "D:\UserProfiles"
    Retrieves user profile folders from the "D:\UserProfiles" directory on "Server01".
.EXAMPLE
    Get-UserProfilesFromFolders
    Retrieves user profile folders from the default "$env:SystemDrive\Users" directory on the local computer.
.NOTES
    This function returns an array of objects representing the user profile folders found in the specified
    directory on the specified computer. It logs a warning if the target computer is unreachable and
    returns an empty array in case of errors during the retrieval process.
#>


function Get-UserProfilesFromFolders
{
    [OutputType([PSCustomObject[]])]
    [CmdletBinding()]
    param (
        [string]$ComputerName = $env:COMPUTERNAME,
        [string]$ProfileFolderPath = "$env:SystemDrive\Users"
    )

    try
    {
        # Test if the computer is online before proceeding
        if (-not (Test-ComputerPing -ComputerName $ComputerName))
        {
            Write-Warning "Computer '$ComputerName' is offline or unreachable."
            return @()  # Return an empty array
        }

        # Get user folders and return them
        $UserFolders = Get-UserFolders -ComputerName $ComputerName -ProfileFolderPath $ProfileFolderPath -ErrorAction Stop
        return $UserFolders
    }
    catch
    {
        Write-Error "Error retrieving user folders from '$ProfileFolderPath' on computer '$ComputerName'. Error: $_"
        return @()  # Return an empty array in case of failure
    }
}
#EndRegion './Public/Get-UserProfilesFromFolders.ps1' 60
#Region './Public/Get-UserProfilesFromRegistry.ps1' -1

<#
.SYNOPSIS
    Retrieves user profiles from the registry of a specified computer.
.DESCRIPTION
    The Get-UserProfilesFromRegistry function queries the ProfileList registry key on the specified computer
    and returns information about the user profiles found in the registry. This includes details such as the
    security identifier (SID) and the profile path. The function checks if the computer is reachable before
    proceeding with the operation and handles errors gracefully if there are issues accessing the registry.
.PARAMETER ComputerName
    The name of the computer from which to retrieve user profiles. Defaults to the local computer.
.OUTPUTS
    PSCustomObject[]
    Returns an array of custom objects representing the user profiles found in the registry. Each object contains
    the following properties:
    - SID: [string] The security identifier (SID) of the user profile.
    - ProfilePath: [string] The path to the user profile.
    - ComputerName: [string] The name of the computer where the profile was retrieved.
.EXAMPLE
    Get-UserProfilesFromRegistry -ComputerName "Server01"
    Retrieves the user profiles from the registry on "Server01".
.EXAMPLE
    Get-UserProfilesFromRegistry
    Retrieves the user profiles from the local computer's registry.
.NOTES
    - The function first checks if the target computer is reachable. If the computer is unreachable, a warning
      is logged, and the function returns an empty array.
    - If an error occurs while accessing the registry, an error is logged, and the function returns an empty array.
#>

function Get-UserProfilesFromRegistry
{
    [OutputType([PSCustomObject[]])]
    [CmdletBinding()]
    param (
        [string] $ComputerName = $env:COMPUTERNAME
    )

    try
    {
        # Test if the computer is online before proceeding
        if (-not (Test-ComputerPing -ComputerName $ComputerName))
        {
            Write-Warning "Computer '$ComputerName' is offline or unreachable."
            return @()  # Return an empty array
        }

        # If user is an admin, use Get-SIDProfileInfo (Registry-based)
        if ($ENV:WinProfileOps_IsAdmin -eq $true)
        {
            Write-Verbose "User has administrator privileges, using registry-based method."
            return Get-SIDProfileInfo -ComputerName $ComputerName
        }
        else
        {
            Write-Warning "User lacks administrator privileges. Switching to fallback method which excludes special accounts from the results."
            return Get-SIDProfileInfoFallback -ComputerName $ComputerName
        }

    }
    catch
    {
        Write-Error "Error accessing registry profiles on computer '$ComputerName'. Error: $_"
        return @()  # Return an empty array in case of failure
    }
}
#EndRegion './Public/Get-UserProfilesFromRegistry.ps1' 65
#Region './Public/Invoke-UserProfileAudit.ps1' -1

<#
.SYNOPSIS
    Audits user profiles on a specified computer by comparing profiles found in the registry and file system.

.DESCRIPTION
    The Invoke-UserProfileAudit function retrieves user profile information from both the file system (user folders)
    and the registry on a specified computer. It compares these profiles to identify orphaned profiles,
    profiles that exist in one location but not the other, and optionally ignores special or default profiles.
    This function is useful for auditing user profiles and detecting inconsistencies across the registry and file system.

.PARAMETER ComputerName
    The name of the computer from which to audit user profiles. Defaults to the local computer.

.PARAMETER ProfileFolderPath
    The path to the folder where user profiles are stored. Defaults to "$env:SystemDrive\Users".

.PARAMETER IgnoreSpecial
    Switch to ignore special or default profiles (such as system accounts or service accounts) during the audit process.

.OUTPUTS
    [UserProfile[]]
    Returns an array of UserProfile objects that represent the profiles found during the audit. Each UserProfile object contains the following properties:
    - SID: [string] The security identifier of the user profile.
    - ProfilePath: [string] The file system path of the user profile.
    - IsOrphaned: [bool] Whether the profile is considered orphaned.
    - OrphanReason: [string] The reason for orphaned status if applicable.
    - ComputerName: [string] The name of the computer where the audit was performed.
    - IsSpecial: [bool] Whether the profile is considered special or a system account.

.EXAMPLE
    Invoke-UserProfileAudit -ComputerName "Server01"
    Audits all user profiles from both the file system and the registry on "Server01".

.EXAMPLE
    Invoke-UserProfileAudit -ProfileFolderPath "D:\UserProfiles" -IgnoreSpecial
    Audits user profiles from the "D:\UserProfiles" folder on the local computer, ignoring special or default profiles.

.EXAMPLE
    Get-AllUserProfiles -ComputerName "Server01"
    This alias performs the same audit as Invoke-UserProfileAudit, returning all user profiles for "Server01".

.NOTES
    This function performs a profile audit by comparing user profiles in the file system and registry.
    It supports pipeline input for multiple computer names and includes an alias `Get-AllUserProfiles`.
#>


function Invoke-UserProfileAudit
{
    [OutputType([UserProfile[]])]
    [CmdletBinding()]
    [Alias("Get-AllUserProfiles")]
    param (
        [Parameter(Mandatory = $false, ValueFromPipeline = $true)]
        [string]$ComputerName = $env:COMPUTERNAME,

        [string]$ProfileFolderPath = "$env:SystemDrive\Users",
        [switch]$IgnoreSpecial
    )

    begin
    {
        $AllProfiles = @()
    }

    process
    {
        if (-not (Test-ComputerReachability -ComputerName $ComputerName))
        {
            return
        }

        try
        {
            $UserFolders = Get-UserProfilesFromFolders -ComputerName $ComputerName -ProfileFolderPath $ProfileFolderPath
            $RegistryProfiles = Get-UserProfilesFromRegistry -ComputerName $ComputerName

            $AllProfiles += Process-RegistryProfiles -RegistryProfiles $RegistryProfiles -ComputerName $ComputerName -IgnoreSpecial:$IgnoreSpecial
            $AllProfiles += Process-FolderProfiles -UserFolders $UserFolders -RegistryProfiles $RegistryProfiles -ComputerName $ComputerName -IgnoreSpecial:$IgnoreSpecial
        }
        catch
        {
            Write-Error "Error processing profiles for computer '$ComputerName'. Error: $_"
        }
    }

    end
    {
        $AllProfiles
    }
}
#EndRegion './Public/Invoke-UserProfileAudit.ps1' 91