PSPowerAdminTasks.psm1

#Region '.\Classes\01CLASS_COMPUTER.ps1' 0
class COMPUTER
{
    #region <Properties>
    [System.String]$Name
    [System.DateTime]$CheckTime
    [System.String]$Status
    [System.String]$SamAccountName
    [System.String]$CN
    [System.String]$Operatingsystem
    [System.String]$Description
    [System.String]$IPv4Address
    [System.String]$Created
    [System.String]$LastLogontimestamp
    [System.String]$CanonicalName
    [System.String]$MemberOF
    [System.String]$HotFixDescription
    [System.String]$HotfixID
    [System.String]$HotFixInstalledBy
    [System.String]$HotFixInstalledOn
    [System.String]$LastBootUptime
    [System.String]$RebootNeeded
    HIDDEN [System.Management.Automation.PSCredential]$Credential
    #endregion <Properties>

    #region <Constructor>
    COMPUTER()
    {
    }

    COMPUTER([string]$ComputerName)
    {
        $This.CheckTime = Get-Date
        $this.Name = $ComputerName
        $this.TestIfComputerIsOnline($ComputerName)
    }

    COMPUTER([string]$ComputerName, [System.Management.Automation.PSCredential]$Credential)
    {
        $This.Credential = $Credential
        $this.Name = $ComputerName
        $this.TestIfComputerIsOnline($ComputerName)
    }
    #endregion <Constructor>

    #region <Methods>
    [void] GetALlInformation ()
    {
        if ($this.Status -eq "Ping OK")
        {
            $This.CheckTime = Get-Date
            $this.TestIfComputerExistInAd()
            $this.GetComputerLastHotFix()
            $this.GetComputerLastBootUptime()
            $this.TestIfRebootNeeded()
        }
    }

    [void] TestIfComputerIsOnline([string]$ComputerName)
    {
        try
        {
            if (Test-Connection -ComputerName $ComputerName -Count 1 -ErrorAction Stop)
            {
                $this.Status = "Ping OK"
            }
            else
            {
                $this.Status = "Ping KO"
            }
        }
        catch
        {
            $this.Status = "Host Unknown"
        }
    }

    [Boolean] TestIfComputerExistInAd ()
    {
        $Parameter = @{
            Properties  = 'Name', 'SamAccountName', 'CN', 'Operatingsystem', 'Description', 'IPv4Address', 'Created', 'LastLogontimestamp', 'CanonicalName', 'MemberOF'
            Filter      = { Name -eq $This.Name }
            ErrorAction = "SilentlyContinue"
        }

        if ($null -ne $this.Credential)
        {
            $Parameter.Add('Credential', $this.Credential)
        }

        $Computer = Get-ADComputer @Parameter
        if ($Computer)
        {
            try
            {
                $this.SamAccountName = $Computer.SamAccountName
                $this.CN = $Computer.CN
                $this.Operatingsystem = $Computer.Operatingsystem
                $this.Description = $Computer.Description
                $this.IPv4Address = $Computer.IPv4Address
                $this.Created = $Computer.Created
                $this.LastLogontimestamp = [DateTime]::FromFileTime($Computer.LastLogontimestamp)
                $this.CanonicalName = $Computer.CanonicalName
                if ($Computer.MemberOF.Count -gt 0)
                {
                    $this.MemberOF = ($Computer.MemberOf -like "*WSUS*").split("=")[1].split(",")[0]
                } else {
                    $This.MemberOF = "No WSUS Group"
                }
            }
            catch [System.Management.Automation.MethodException]
            {
                   Write-Output ('[{0:O}] ErrorID: {1}' -f (get-date),$_.Exception.Message)
                   Write-Output ('[{0:O}] Exception: {1}' -f (get-date),$_.FullyQualifiedErrorId)
                   Write-Output ('[{0:O}] Category: {1}' -f (get-date),(($_.Exception.GetType() | Select-Object -ExpandProperty UnderlyingSystemType).FullName))
            }
            catch
            {
                Write-Output ('[{0:O}] ErrorID: {1}' -f (get-date),$_.Exception.Message)
                Write-Output ('[{0:O}] Exception: {1}' -f (get-date),$_.FullyQualifiedErrorId)
                Write-Output ('[{0:O}] Category: {1}' -f (get-date),(($_.Exception.GetType() | Select-Object -ExpandProperty UnderlyingSystemType).FullName))
            }
            return $true
        }
        else
        {
            $this.SamAccountName = "Unknown"
            $this.CN = "Unknown"
            $this.Operatingsystem = "Unknown"
            $this.Description = "Unknown"
            $this.IPv4Address = "Unknown"
            $this.Created = "Unknown"
            $this.LastLogontimestamp = "Unknown"
            $this.CanonicalName = "Unknown"
            $this.MemberOF = "Unknown"
            return $false
        }
    }

    [Void] GetComputerLastHotFix ()
    {
        try
        {
            $HotfixParameter = @{
                ComputerName = $this.CN
                ErrorAction  = "Stop"
            }
            if ($null -ne $this.Credential)
            {
                $HotfixParameter['Credential'] = $this.Credential
            }
            $hotfix = Get-HotFix @HotfixParameter  | Sort-Object -Descending -Property InstalledOn | Select-Object -First 1 | Select-Object Description, HotfixID, InstalledBy, InstalledOn
            $this.HotfixID = $hotfix.HotfixID
            $this.HotFixDescription = $hotfix.Description
            $this.HotFixInstalledBy = $hotfix.InstalledBy
            $this.HotFixInstalledOn = $hotfix.InstalledOn

        }
        catch [System.UnauthorizedAccessException]
        {
            $this.HotfixID = "UnauthorizedAccessException"
            $this.HotFixDescription = "UnauthorizedAccessException"
            $this.HotFixInstalledBy = "UnauthorizedAccessException"
            $this.HotFixInstalledOn = "UnauthorizedAccessException"
        }
        catch
        {
            $this.HotfixID = "Unknown"
            $this.HotFixDescription = "Unknown"
            $this.HotFixInstalledBy = "Unknown"
            $this.HotFixInstalledOn = "Unknown"
        }
    }

    [Void] GetComputerLastBootUptime ()
    {
        try
        {
            $Parameter = @{
                ComputerName = $this.CN
                ErrorAction  = "Stop"
            }
            if ($null -ne $this.Credential)
            {
                $Parameter['Credential'] = $this.Credential
            }
            $this.LastBootUptime = Invoke-Command @Parameter -ScriptBlock {(Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object -ExpandProperty LastBootUpTime)}
        }
        catch
        {
            Write-Output ('[{0:O}] ErrorID: {1}' -f (get-date),$_.Exception.Message)
            Write-Output ('[{0:O}] Exception: {1}' -f (get-date),$_.FullyQualifiedErrorId)
            Write-Output ('[{0:O}] Category: {1}' -f (get-date),(($_.Exception.GetType() | Select-Object -ExpandProperty UnderlyingSystemType).FullName))
            $this.LastBootUptime = "Unknown"
        }
    }

    [void] TestIfRebootNeeded ()
    {
        if ($this.Status -eq "Ping OK")
        {
            try
            {
                $CmdParameter = @{
                    ComputerName   = $this.CN
                    ErrorAction    = "Stop"
                    Authentication = "Kerberos"
                }
                if ($null -ne $this.Credential)
                {
                    $CmdParameter['Credential'] = $this.Credential
                }
                $this.RebootNeeded = Invoke-Command @CmdParameter -ScriptBlock {
                    if ((Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending" -ErrorAction SilentlyContinue) -or (Get-Item "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" -ErrorAction SilentlyContinue) )
                    {
                        write-output "YES"
                    }
                    else {
                        Write-output "NO"
                    }
                }
            }
            catch
            {
                $This.RebootNeeded = "Unknown"
            }
        }
    }
    #endregion <Methods>
}
#EndRegion '.\Classes\01CLASS_COMPUTER.ps1' 230
#Region '.\Private\Write-Log.ps1' 0
function Write-Log
{
<#
.SYNOPSIS
Write a log file
 
.DESCRIPTION
Write all operation passed as parameter to a log file
 
.PARAMETER LogPath
Path to logfile. By default, the logfile is created in the temp folder of the current user
 
.PARAMETER Message
Message to write in the log file
 
.PARAMETER Severity
Severity of the message. By default, the severity is set to Information
 
.PARAMETER Console
Show the message in the console
 
.PARAMETER Force
Forece the creation of the log file
 
.EXAMPLE
Write-log -Message 'Starting Set-ChangePasswordAtNextLogon' -Severity Information -Console
 
.NOTES
General notes
#>


    [CmdletBinding()]
    param
    (
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [System.String]$LogPath = "$env:Temp\LogFile.csv",

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$Message,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('Information', 'Warning', 'Error')]
        [string]$Severity = 'Information',

        [Parameter()]
        [switch]$Console,

        [Parameter()]
        [switch]$Force
    )

    $info = [pscustomobject]@{
        Severity = "[$($Severity)]"
        Time     = ((Get-Date).toString("yyyy/MM/dd HH:mm:ss"))
        Message  = $Message
    }

    if ($Console)
    {
        Write-Output "$($info.Severity) $($info.Time) $($info.Message)"
    }

    if ($Force)
    {
        $info | Export-Csv -Path $LogPath -NoTypeInformation -Force
    }
    else
    {
        $info | Export-Csv -Path $LogPath -NoTypeInformation -Append
    }
}
#EndRegion '.\Private\Write-Log.ps1' 75
#Region '.\Public\Disable-CompromisedUser.ps1' 0
function Disable-CompromisedUser
{
<#
    .SYNOPSIS
    Disable compromised user
 
    .DESCRIPTION
    In case of compromission from some users, you can rapidly disable this users.
    You can pass to parameter :
        - a nominative list of user
        - a file with a nominative list of users (one user by line)
        - an OU to disable all users
    Check example for more details (get-help Disable-CompromisedUser -Examples)
    A log file is create in your temp directory ($env:temp)
 
    .PARAMETER Identity
    One or more user(s) to disable
 
    .PARAMETER FileName
    File with a list of users to disable. txt with one name by line
 
    .PARAMETER OU
    One or more OU(s) in which we want to disable all users
 
    .PARAMETER Check
    Only check if the users passed in parameter, whatever the way (Identity, Filename or OU), are disable
 
    .PARAMETER Credential
    Specifies the user account credentials to use when performing this task
 
    .PARAMETER Log
    Log information in a file (in $env:Temp )
 
    .PARAMETER Console
    Show information in console (need Log parameter)
 
    .EXAMPLE
    Disable-CompromisedUser -Identity "User1"
 
    Disable the user account : User1
 
    .EXAMPLE
    Disable-CompromisedUser -Identity "User1" -Log
 
    Disable the user account : User1 and log information in file in $env:temp
 
    .EXAMPLE
    Disable-CompromisedUser -Identity "User1" -Log -Console
 
    Disable the user account : User1, log information in file in $env:temp and log to console the same information
 
    .EXAMPLE
    Disable-CompromisedUser -Identity "User1" -Check
 
    Check if user account User1 is disable
 
    .EXAMPLE
    Disable-CompromisedUser -Identity "User1","User2","User3"
 
    Disable users account : User1, User2 and User3
 
    .EXAMPLE
    Disable-CompromisedUser -Identity "User1","User2","User3" -Check
 
    Check if users account User1, User2 and User3 are disable
 
    .EXAMPLE
    Disable-CompromisedUser -FileName "c:\temp\CompromisedUser.txt"
 
    File template CompromisedUser.txt :
    User1
    User2
    User3
 
    Disable users account : User1, User2 and User3
 
    .EXAMPLE
    Disable-CompromisedUser -FileName "c:\temp\CompromisedUser.txt" -Check
 
    File template CompromisedUser.txt :
    User1
    User2
    User3
 
    Check if users account User1, User2 and User3 are disable
 
    .EXAMPLE
    Disable-CompromisedUser -OU "OU=OU1,DC=contoso,DC=com"
 
    Disable all users present in OU1
 
    .EXAMPLE
    Disable-CompromisedUser -OU "OU=OU1,DC=contoso,DC=com" -Check
 
    Check if all users present in OU1 are disable
 
    .EXAMPLE
    Disable-CompromisedUser -OU "OU=OU1,DC=contoso,DC=com","OU=OU2,DC=contoso,DC=com"
 
    Disable all users present in OU1 and OU2
 
    .EXAMPLE
    Disable-CompromisedUser -OU "OU=OU1,DC=contoso,DC=com","OU=OU2,DC=contoso,DC=com" -check
 
    Check if all users present in OU1 and OU2 are disable
 
    .NOTES
    General notes
#>

    [CmdletBinding(DefaultParameterSetName = "ByUser")]
    param (
        [Parameter(
            ParameterSetName = "ByUser",
            HelpMessage = 'One or more user(s) to disable'
        )]
        [System.String[]]$Identity,
        [Parameter(
            ParameterSetName = "ByFileName",
            HelpMessage = 'File with a list of users to disable. txt with one name by line'
        )]
        [System.String]$FileName,
        [Parameter(
            ParameterSetName = "ByOu",
            HelpMessage = 'One or more OU(s) in which we want to disable all users'
        )]
        [System.String[]]$OU,
        [Parameter(
            HelpMessage = 'Only check if the users passed in parameter, whatever the way (Identity, Filename or OU), are disable'
        )]
        [Switch]$Check,

        [Parameter(
            HelpMessage = "Specifies the user account credentials to use when performing this task."
        )]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty,

        [Parameter(
            HelpMessage = 'Log information in a file'
        )]
        [switch]$log,

        [Parameter(
            HelpMessage = 'Show information in console'
        )]
        [switch]$Console
    )


    begin
    {
        if ($log)
        {
            $LogPath = $env:Temp + '\Disable-CompromisedUser.csv'
            Write-Log -LogPath $LogPath -Message 'Starting Disable-CompromisedUser' -Severity Information -Console:$Console
        }
        $Users = @()

        switch ($PSCmdlet.ParameterSetName)
        {
            ByUser
            {
                if ($log) { write-log -LogPath $LogPath -Message "Retrieve AD User Account by user list" -Severity Information -Console:$Console}
                foreach ($User in $Identity)
                {
                    try
                    {
                        $Users += Get-ADUser -Identity $User -Properties SamAccountName,DisplayName,Enabled -ErrorAction Continue | Select-Object SamAccountName,DisplayName,Enabled
                        if ($log) { write-log -LogPath $LogPath -Message "User $($User) found" -Severity Information -Console:$Console}
                    }
                    catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
                    {
                        if ($log) { write-log -LogPath $LogPath -Message "User $($User) not found" -Severity Error -Console:$Console}
                    }
                }
            }
            ByFileName
            {
                if ($log) { write-log -LogPath $LogPath -Message "Retrieve AD User Account by file list" -Severity Information -Console:$Console}
                foreach ($User in (Get-Content -Path $FileName))
                {
                    try
                    {
                        $Users += Get-ADUser -Identity $User -Properties SamAccountName,DisplayName,Enabled -ErrorAction Continue | Select-Object SamAccountName,DisplayName,Enabled
                        if ($log) { write-log -LogPath $LogPath -Message "User $($User) found" -Severity Information -Console:$Console}
                    }
                    catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
                    {
                        if ($log) { write-log -LogPath $LogPath -Message "User $($User) not found" -Severity Error -Console:$Console}
                    }
                }
            }
            ByOu
            {
                if ($log) { write-log -LogPath $LogPath -Message "Retrieve AD User Account by OU list" -Severity Information -Console:$Console}
                foreach ($Organ in $OU)
                {
                    if ($log) { write-log -LogPath $LogPath -Message "Retrieve AD User Account in $($Organ)" -Severity Information -Console:$Console}
                    $Users += Get-ADUser -Filter * -SearchBase $Organ -Properties SamAccountName,DisplayName,Enabled | Select-Object SamAccountName,DisplayName,Enabled

                }
            }
        }
    }

    process
    {

        $Arguments = @{}
        if ($PSBoundParameters.ContainsKey('Credential'))
        {
            $Arguments['Credential'] = $Credential
        }

        foreach ($user in $Users)
        {
            if ($Check)
            {
                if ($log) { write-log -LogPath $LogPath -Message "Check state for user $( $User.SamAccountName)" -Severity Information -Console:$Console}
                if ($user.Enabled -eq "True")
                {
                    if ($log) { write-log -LogPath $LogPath -Message "user $($User.SamAccountName) is enabled" -Severity Information -Console:$Console}
                } else
                {
                    if ($log) { write-log -LogPath $LogPath -Message "user $($User.SamAccountName) is disabled" -Severity Information -Console:$Console}
                }
            } else
            {
                $Arguments['Identity'] = $Users.SamAccountName

                Disable-ADAccount @Arguments -Confirm:$false
                if ($log) { write-log -LogPath $LogPath -Message "Disabeling user $($User.SamAccountName)" -Severity Information -Console:$Console}
            }
        }
    }

    end
    {
        if ($log)
        {
            write-log -LogPath $LogPath -Message "Ending Disable-CompromisedUser" -Severity Information -Console:$Console
        }
    }
}
#EndRegion '.\Public\Disable-CompromisedUser.ps1' 247
#Region '.\Public\Find-UserLockoutsInformation.ps1' 0
Function Find-UserLockoutsInformation
{
<#
    .SYNOPSIS
    Find information about locked user account
 
    .DESCRIPTION
    This fonction search for locked user on PDC Emulator and return the lock source
    return :
    User : User1
    DomainController : PDCEmulator
    EventId : 4740
    LockoutTimeStamp : 8/3/2023 6:18:12 AM
    Message : A user account was locked out.
    LockoutSource : SourceComputer
    To find the reason use : Get-UserLockoutReason -Computer SourceComputer -Identity User1
 
    .PARAMETER Identity
    User to check (by default all)
 
    .PARAMETER DC
    Domain controller on which you want to look up information (by default PDC Emulator)
 
    .PARAMETER Credential
    Administrator credential to connect to the DC
 
    .EXAMPLE
    Find-UserLockoutsInformation -Credential (Get-Credential MyAdminAccount)
    Search information for all locked users in PDC Emulator
 
    .EXAMPLE
    Find-UserLockoutsInformation -Identity User1 -Credential (Get-Credential MyAdminAccount)
    Search information for user User1 in PDC Emulator
 
    .EXAMPLE
    Find-UserLockoutsInformation -Identity User1 -DC MyDC1 -Credential (Get-Credential MyAdminAccount)
    Search information for user User1 in specific domain controler MyDC1
 
    .NOTES
    General notes
#>

    [CmdletBinding(
        DefaultParameterSetName = 'All'
    )]
    param (
        [Parameter(
            ValueFromPipeline = $true,
            ParameterSetName = 'ByUser'
        )]
        [System.String]$Identity,
        [System.String]$DC = (Get-ADDomain).PDCEmulator,
        # Specifies the user account credentials to use when performing this task.
        [Parameter()]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )
    Begin
    {
        Write-Verbose ('[{0:O}] Searching EventID : 4740 on Server : {1} ' -f (get-date), $DC)
        $WinEventArguments = @{
            ComputerName    = $DC
            FilterHashtable = @{LogName = 'Security'; Id = 4740 }
        }

        if ($PSBoundParameters.ContainsKey('Credential'))
        {
            $WinEventArguments['Credential'] = $Credential
        }
        try {
            $LockedOutEvents = Get-WinEvent @WinEventArguments -ErrorAction Stop | Sort-Object -Property TimeCreated -Descending
        }
        catch {
            if ($Error[-1].Exception.Message -like "*elevated user rights*") {
                throw ('[{0:O}] You need an admin account. Please provide with the -Credential parameter' -f (get-date))
            }
        }

        if ($LockedOutEvents) {
            Write-Verbose ('[{0:O}] {1} event found' -f (get-date), $LockedOutEvents.Count)
        } else {
            throw ('[{0:O}] No event found' -f (get-date))
        }
    }

    Process
    {
        switch ($PSCmdlet.ParameterSetName)
        {
            ByUser
            {
                Write-Verbose ('[{0:O}] Searching information for user : {1}' -f (get-date), $Identity)
                $UserInfo = Get-ADUser -Identity $Identity
                Foreach ($Event in $LockedOutEvents)
                {
                    If ($Event | Where-Object { $_.Properties[2].value -match $UserInfo.SID.Value })
                    {

                        $Event | Select-Object -Property @(
                            @{Label = 'User'; Expression = { $_.Properties[0].Value } }
                            @{Label = 'DomainController'; Expression = { $_.MachineName } }
                            @{Label = 'EventId'; Expression = { $_.Id } }
                            @{Label = 'LockoutTimeStamp'; Expression = { $_.TimeCreated } }
                            @{Label = 'Message'; Expression = { $_.Message -split "`r" | Select-Object -First 1 } }
                            @{Label = 'LockoutSource'; Expression = { $_.Properties[1].Value } }
                        )
                    }
                }
            }
            All
            {
                Write-Verbose ('[{0:O}] Searching information for all user(s) ' -f (get-date))
                Foreach ($Event in $LockedOutEvents)
                {

                    $Event | Select-Object -Property @(
                        @{Label = 'User'; Expression = { $_.Properties[0].Value } }
                        @{Label = 'DomainController'; Expression = { $_.MachineName } }
                        @{Label = 'EventId'; Expression = { $_.Id } }
                        @{Label = 'LockoutTimeStamp'; Expression = { $_.TimeCreated } }
                        @{Label = 'Message'; Expression = { $_.Message -split "`r" | Select-Object -First 1 } }
                        @{Label = 'LockoutSource'; Expression = { $_.Properties[1].Value } }
                    )
                }
            }
        }
    }
    End
    {
    }

}
#EndRegion '.\Public\Find-UserLockoutsInformation.ps1' 134
#Region '.\Public\Get-BitLockerInformation.ps1' 0

function Get-BitLockerInformation {
<#
.SYNOPSIS
Retreive BitLocker information from Active Directory
 
.DESCRIPTION
Retreive BitLocker information for computer pass as parameter from Active Directory
 
.PARAMETER Computer
Computer name
 
.PARAMETER Credential
Credential with permission to read bitlocker information in Active Directory
 
.EXAMPLE
Get-BitlockerInformation -Computer "ComputerName" -Credential $MyCredential
 
Find bitlocker information for computer "ComputerName" with credential
 
.NOTES
General notes
#>

    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true)]
        [System.String[]]$Computer,
        [Parameter(Mandatory)]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

    begin {
        $Result = @()
        $Argument = @{
            Filter     = { ObjectClass -eq 'msFVE-RecoveryInformation' }
            Properties = 'msFVE-RecoveryPassword'
        }

        If ($PSBoundParameters.ContainsKey("Credential")) {

            $Argument.Add("Credential", $Credential)
        }
    }

    process {
        foreach ($Comp in $Computer) {
            Write-Verbose "Check computer : $($Comp)"
            $objComputer = Get-ADComputer -Identity $Comp
            $BitLockerObject = Get-ADObject @Argument -SearchBase $objComputer.DistinguishedName
            if ($BitLockerObject) {
                $Bitlock = $BitLockerObject | Sort-Object Name | Select-Object -last 1
                $object = [PSCustomObject]@{
                    "Computer"     = $Comp
                    "Password ID"  = $Bitlock.Name.split("{")[1].split("}")[0]
                    "Date"         = $Bitlock.Name.split("{")[0]
                    "Recovery Key" = $Bitlock.'msFVE-RecoveryPassword'
                }
                $Result += $object
            }
            else {
                $object = [PSCustomObject]@{
                    "Computer"     = $Comp
                    "Password ID"  = "null"
                    "Date"         = "null"
                    "Recovery Key" = "null"
                }
                $Result += $object
            }

        }
    }

    end {
        return $Result
    }
}
#EndRegion '.\Public\Get-BitLockerInformation.ps1' 80
#Region '.\Public\Get-LastUpdateInformation.ps1' 0
function Get-LastUpdateInformation
{
    <#
    .SYNOPSIS
    Retrieve update information
 
    .DESCRIPTION
    Retrieve update information for a server
    the data is :
    Name
    CheckTime
    Status
    SamAccountName
    CN
    Operatingsystem
    Description
    IPv4Address
    Created
    LastLogontimestamp
    CanonicalName
    MemberOF
    HotFixDescription
    HotfixID
    HotFixInstalledBy
    HotFixInstalledOn
    LastBootUptime
    RebootNeeded
 
    .PARAMETER ComputerName
    One or more computer(s) to check
 
    .PARAMETER Credential
    Administrator credential to connect to the computer
 
    .EXAMPLE
    Get-LastUpdateInformation -ComputerName MyServer -Credential (Get-Credential MyAdminAccount) -Verbose
    Search last update information foe server MyServer using credential to connect
 
    .NOTES
    General notes
#>

    [CmdletBinding()]
    [OutputType([System.Object[]])]
    param (
        [Parameter(Mandatory = $true)]
        [System.String[]]$ComputerName,
        # Specifies the user account credentials to use when performing this task.
        [Parameter()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]$Credential
    )

    begin
    {
        $result = @()
    }

    process
    {
        if ($null -ne $Credential)
        {
            foreach ($computer in $ComputerName)
            {
                Write-Verbose ('[{0:O}] Computer {1}' -f (get-date),$computer)
                $Infos = [COMPUTER]::new($computer, $Credential)
                $Infos.GetALlInformation()
                $result += $Infos
            }
        }
        else
        {
            foreach ($computer in $ComputerName)
            {
                Write-Verbose ('[{0:O}] Computer {1}' -f (get-date),$computer)
                $Infos = [COMPUTER]::new($computer)
                $Infos.GetALlInformation()
                $result += $Infos
            }
        }
    }

    end
    {
        return $result
    }
}
#EndRegion '.\Public\Get-LastUpdateInformation.ps1' 87
#Region '.\Public\Get-UserLockoutReason.ps1' 0
function Get-UserLockoutReason
{
    <#
    .SYNOPSIS
    Search user lockout reason
 
    .DESCRIPTION
    You can search the reason of locked user on a specific computer
    To find the source you can use : Find-UserLockoutsInformation -Identity User1 -DC MyDC1 -Credential (Get-Credential MyAdminAccount)
 
    .PARAMETER Computer
    User lockout source computer
 
    .PARAMETER Identity
    Name of the user for whom we are looking for the source of the lock
 
    .PARAMETER Credential
    Administrator credential to connect to the computer
 
    .EXAMPLE
    Get-UserLockoutReason -Computer ComputerSource -Identity User1 -Credential (Get-Credential MyAdminAccount)
 
    .NOTES
    General notes
#>

    [CmdletBinding(
        DefaultParameterSetName = 'All'
    )]
    [OutputType([System.Object[]])]
    param (
        [System.String]$Computer,
        [Parameter(
            ValueFromPipeline = $true,
            ParameterSetName = 'ByUser'
        )]
        [System.String]$Identity,
        # Specifies the user account credentials to use when performing this task.
        [Parameter()]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

    begin
    {
        $LogonInfo = Import-PSFPowerShellDataFile -Path $PSScriptRoot/PSPowerAdminTasks.psd1
        Write-Verbose ('[{0:O}] Searching EventID : 4625 on Computer : {1} ' -f (get-date), $Computer)

        $WinEventArguments = @{
            ComputerName    = $Computer
            FilterHashtable = @{LogName = 'Security'; Id = 4625 }
        }

        if ($PSBoundParameters.ContainsKey('Credential'))
        {
            $WinEventArguments['Credential'] = $Credential
        }

        $lockoutEvents = $null
        Write-Verbose ('[{0:O}] Test if computer : {1} is alive ' -f (get-date), $Computer)
        if (Test-Connection -ComputerName $Computer -Quiet -Count 2)
        {
            try
            {
                $lockoutEvents = Get-WinEvent @WinEventArguments -ErrorAction Stop
            }
            catch
            {
                if ($_.Exception.Message -match "No events were found that match the specified selection criteria")
                {
                    Write-Verbose ('[{0:O}] No logs found' -f (get-date))
                }
                if ($Error[-1].Exception.Message -like "*elevated user rights*")
                {
                    throw ('[{0:O}] You need an admin account. Please provide with the -Credential parameter' -f (get-date))
                }
            }
        }
        else
        {
            throw ('[{0:O}] computer {1} is not alive' -f (get-date), $Computer)
        }

        if ($lockoutEvents)
        {
            Write-Verbose ('[{0:O}] {1} event found' -f (get-date), $lockoutEvents.Count)
        }
        else
        {
            throw ('[{0:O}] No event found' -f (get-date))
        }
    }

    process
    {
        switch ($PSCmdlet.ParameterSetName)
        {
            All
            {
                Write-Verbose ('[{0:O}] Searching information for all user(s) ' -f (get-date))
                Foreach ($Event in $lockoutEvents)
                {
                    $eventXML = [xml]$event.ToXml()
                    $Event | Select-Object -Property @(
                        @{label = 'LockedUserName' ; Expression = {$eventXML.Event.EventData.Data[5].'#text'}}
                        @{label = 'LogonType' ; Expression = {$LogonInfo.PrivateData.LogonType."$($eventXML.Event.EventData.Data[10].'#text')"}}
                        @{label = 'LogonProcessName' ; Expression = {$eventXML.Event.EventData.Data[11].'#text'}}
                        @{label = 'ProcessName' ; Expression = {$eventXML.Event.EventData.Data[18].'#text'}}
                        @{label = 'FailureReason' ; Expression = {$LogonInfo.PrivateData.FailureReason."$($eventXML.Event.EventData.Data[8].'#text')"}}
                        @{label = 'FailureStatus' ; Expression = {$LogonInfo.PrivateData.FailureType."$($eventXML.Event.EventData.Data[7].'#text')"}}
                        @{label = 'FailureSubStatus' ; Expression = {$LogonInfo.PrivateData.FailureType."$($eventXML.Event.EventData.Data[9].'#text')"}}
                    )
                }
            }
            ByUser
            {
                Write-Verbose ('[{0:O}] Searching information for user : {1}' -f (get-date), $Identity)
                Foreach ($Event in $lockoutEvents)
                {
                    $eventXML = [xml]$event.ToXml()
                    If ($Event | Where-Object { $eventXML.Event.EventData.Data[5].'#text' -match $Identity })
                    {
                        $Event | Select-Object -Property @(
                            @{label = 'LockedUserName' ; Expression = {$eventXML.Event.EventData.Data[5].'#text'}}
                            @{label = 'LogonType' ; Expression = {$LogonInfo.PrivateData.LogonType."$($eventXML.Event.EventData.Data[10].'#text')"}}
                            @{label = 'LogonProcessName' ; Expression = {$eventXML.Event.EventData.Data[11].'#text'}}
                            @{label = 'ProcessName' ; Expression = {$eventXML.Event.EventData.Data[18].'#text'}}
                            @{label = 'FailureReason' ; Expression = {$LogonInfo.PrivateData.FailureReason."$($eventXML.Event.EventData.Data[8].'#text')"}}
                            @{label = 'FailureStatus' ; Expression = {$LogonInfo.PrivateData.FailureType."$($eventXML.Event.EventData.Data[7].'#text')"}}
                            @{label = 'FailureSubStatus' ; Expression = {$LogonInfo.PrivateData.FailureType."$($eventXML.Event.EventData.Data[9].'#text')"}}
                        )
                    }

                }

            }
        }


    }

    end
    {
    }
}
#EndRegion '.\Public\Get-UserLockoutReason.ps1' 147
#Region '.\Public\Remove-UserFromGroup.ps1' 0
#take a list of users and for each users, check if the user is in a list of groups. If user is found in a group then remove the user from the group.
function Remove-UserFromGroup
{
    <#
.SYNOPSIS
Remove a user from a group
 
.DESCRIPTION
Remove one or more users from one or more groups
 
.PARAMETER Users
One user or more users to remove from one or more groups
 
.PARAMETER Groups
One or more groups to remove one or more users from
 
.PARAMETER FilePathUser
Path to a file containing one user per line
 
.PARAMETER FilePathGroup
Path to a file containing one group per line
 
.PARAMETER Credential
Credentials to use when performing this task
 
.PARAMETER Log
Log the operation into a file (in $env:temp by default)
 
.PARAMETER Console
Show the message in the console
 
.EXAMPLE
Remove-UserFromGroup -Users 'User1' -Groups 'Group1'
 
Remove USer1 from Group1
 
.EXAMPLE
Remove-UserFromGroup -Users 'User1','User2" -Groups 'Group1'
 
Remove User1 and User2 from Group1
 
.EXAMPLE
Remove-UserFromGroup -Users 'User1','User2" -Groups 'Group1','Group2'
 
Remove User1 and User2 from Group1 and Group2
 
.EXAMPLE
Remove-UserFromGroup -FilePathUser 'C:\Users.txt' -FilePathGroup 'C:\Groups.txt'
 
Users.txt contains one user per line
Groups.txt contains one group per line
Remove users from groups based on a file containing users and a file containing groups
 
.NOTES
General notes
#>

    [CmdletBinding(DefaultParameterSetName = 'ByUser')]
    param (
        [Parameter(ParameterSetName = 'ByUser')]
        [string[]]$Users,
        [Parameter(ParameterSetName = 'ByUser')]
        [string[]]$Groups,
        [Parameter(ParameterSetName = 'ByFile')]
        [System.String]$FilePathUser,
        [Parameter(ParameterSetName = 'ByFile')]
        [System.String]$FilePathGroup,       # Specifies the user account credentials to use when performing this task.
        [Parameter()]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty,
        [Parameter()]
        [switch]$log,
        [Parameter()]
        [switch]$Console
    )

    begin
    {
        if ($log)
        {
            $LogPath = $env:Temp + '\Remove-UserFromGroup.csv'
            Write-Log -LogPath $LogPath -Message 'Starting Remove-UserFromGroup' -Severity Information -Console:$Console
        }
    }
    process
    {
        if ($PSCmdlet.ParameterSetName -eq 'ByFile')
        {
            $Users = Get-Content -Path $FilePathUser
            $Groups = Get-Content -Path $FilePathGroup
        }

        try
        {
            # Loop through each user
            foreach ($user in $users)
            {
                # Loop through each group
                foreach ($group in $groups)
                {
                    if ($log) { write-log -LogPath $LogPath -Message "Searching user $($user) in group $($group)" -Severity Information -Console:$Console}
                    # Check if the user is a member of the group
                    $isMember = (Get-ADGroupMember -Identity $group -ErrorAction Stop | Where-Object { $_.SamAccountName -eq $user })

                    # If the user is a member of the group, remove them
                    if ($isMember)
                    {
                        if ($log) { write-log -LogPath $LogPath -Message "User $($user) found in group $($group) => remove it" -Severity Information -Console:$Console}
                        $Arguments = @{
                            Identity = $group
                            Members  = $user
                            Confirm  = $false
                            ErrorAction = "Stop"
                        }
                        if ($PSBoundParameters.ContainsKey('Credential'))
                        {
                            $Arguments['Credential'] = $Credential
                        }

                        Remove-ADGroupMember @Arguments
                    }
                }
            }
        }
        catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
        {
            if ($log) { write-log -LogPath $LogPath -Message "group $($group) not found...." -Severity Error -Console:$Console}
            Write-Error ('[{0:O}] group {1} not found....' -f (Get-Date),$group)
        }
        catch [Microsoft.ActiveDirectory.Management.ADException]
        {
            if ($log) { write-log -LogPath $LogPath -Message "Insufficient access rights to perform the operation" -Severity Error -Console:$Console}
            Write-Error ('[{0:O}] Insufficient access rights to perform the operation' -f (Get-Date))
        }
        catch
        {
            Write-Output ('[{0:O}] ErrorID: {1}' -f (Get-Date), $_.Exception.Message)
            Write-Output ('[{0:O}] Exception: {1}' -f (Get-Date), $_.FullyQualifiedErrorId)
            Write-Output ('[{0:O}] Category: {1}' -f (Get-Date), (($_.Exception.GetType() | Select-Object -ExpandProperty UnderlyingSystemType).FullName))
        }

    }

    end
    {
        if ($log)
        {
            Write-Log -LogPath $LogPath -Message 'Ending Remove-UserFromGroup' -Severity Information -Console:$Console
        }
    }
}
#EndRegion '.\Public\Remove-UserFromGroup.ps1' 153
#Region '.\Public\Set-ChangePasswordAtNextLogon.ps1' 0
function Set-ChangePasswordAtNextLogon
{
    <#
    .SYNOPSIS
    Force user to change password at next logon
 
    .DESCRIPTION
    Force user(s) passed as parameter to change password at next logon
 
    .PARAMETER Identity
    Name of user(s) to force to change password at next logon
 
    .PARAMETER DomainController
    Domain controler on which to perform the operation
 
    .PARAMETER Credential
    Credentials to use when performing the operation
 
    .PARAMETER Log
    Log the operation into a file
 
    .PARAMETER Console
    Show the message in the console
 
 
    .EXAMPLE
    Set-ChangePasswordAtNextLogon -Identity user1,user2,user3
 
    .EXAMPLE
    Set-ChangePasswordAtNextLogon -Identity user1,user2,user3 -DomainController dc1
 
    .EXAMPLE
    Set-ChangePasswordAtNextLogon -Identity user1,user2,user3 -Credential (Get-Credential)
 
    .EXAMPLE
    Set-ChangePasswordAtNextLogon -Identity user1,user2,user3 -Log
 
    .EXAMPLE
    Set-ChangePasswordAtNextLogon -Identity user1,user2,user3 -Console -Log
 
    .NOTES
    General notes
#>

    [CmdletBinding(SupportsShouldProcess)]
    param (
        # UserName
        [Parameter()]
        [System.String[]]$Identity,
        # Parameter help description
        [Parameter()]
        [System.String]$DomainController = (Get-ADDomainController -Discover -Service PrimaryDC).HostName[0],
        # Specifies the user account credentials to use when performing this task.
        [Parameter()]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty,
        [Parameter()]
        [switch]$log,
        [Parameter()]
        [switch]$Console
    )

    begin
    {
        if ($log)
        {
            $LogPath = $env:Temp + '\Set-ChangePasswordAtNextLogon.csv'
            Write-Log -LogPath $LogPath -Message 'Starting Set-ChangePasswordAtNextLogon' -Severity Information -Console:$Console
        }
    }

    process
    {
        $count = 1
        $Arguments = @{
            ChangePasswordAtLogon = $True
            ErrorAction           = "Stop"
            Server                = $DomainController
        }

        if ($PSBoundParameters.ContainsKey('Credential'))
        {
            $Arguments['Credential'] = $Credential
        }

        foreach ($user in $Identity)
        {
            if ($log) { write-log -LogPath $LogPath -Message "Processing user $($count) of $($Identity.Count)" -Severity Information -Console:$Console}
            if ($log) { write-log -LogPath $LogPath -Message "Processing user $($user)" -Severity Information -Console:$Console}
            $count++
            $Arguments['Identity'] = $user
            try
            {
                if ($PSCmdlet.ShouldProcess($user, 'Set-ADUser'))
                {
                    if ($log) { write-log -LogPath $LogPath -Message "Processing user $($user)" -Severity Information -Console:$Console}
                    Set-ADUser @Arguments
                }
            }
            catch [Microsoft.ActiveDirectory.Management.ADException]
            {
                if ($log) { write-log -LogPath $LogPath -Message "Insufficient access rights to perform the operation" -Severity Error -Console:$Console}
                Write-Error ('[{0:O}] Insufficient access rights to perform the operation' -f (Get-Date))
            }
            catch
            {
                if ($log)
                {
                    write-log -LogPath $LogPath -Message "$($_.Exception.Message)" -Severity Error -Console:$Console
                    write-log -LogPath $LogPath -Message "$($_.FullyQualifiedErrorId)" -Severity Error -Console:$Console
                    write-log -LogPath $LogPath -Message "$($_.Exception.GetType() | Select-Object -ExpandProperty UnderlyingSystemType).FullName)" -Severity Error
                }
                Write-Output ('[{0:O}] ErrorID: {1}' -f (Get-Date), $_.Exception.Message)
                Write-Output ('[{0:O}] Exception: {1}' -f (Get-Date), $_.FullyQualifiedErrorId)
                Write-Output ('[{0:O}] Category: {1}' -f (Get-Date), (($_.Exception.GetType() | Select-Object -ExpandProperty UnderlyingSystemType).FullName))
            }
        }
    }

    end
    {
        if ($log)
        {
            Write-Log -LogPath $LogPath -Message 'Ending Set-ChangePasswordAtNextLogon' -Severity Information -Console:$Console
        }
    }
}
#EndRegion '.\Public\Set-ChangePasswordAtNextLogon.ps1' 129
#Region '.\Public\Set-LocalUserPassword.ps1' 0

function Set-LocalUserPassword
{
<#
.SYNOPSIS
Set the password of a local user account
 
.DESCRIPTION
Set the password of a local user account. Password pass as a plain text string will be converted to a secure string.
 
.PARAMETER Username
UserName of the local user account to set the password
 
.PARAMETER Password
Password of the local user account to set. Pass as a plain text string will be converted to a secure string.
 
.PARAMETER ComputerName
ComputerName where the local user account is located. Default is the local computer.
 
.PARAMETER Credential
Specifies the user account credentials to use when performing this task.
 
.EXAMPLE
Set-LocalUserPassword -Username "MyUser" -Password "P@sswOrd" -Credential ($MyAdminAccount) -ComputerName Myserver
 
Set password of the local user account "MyUser" on the computer "Myserver" with the credential stored in the variable $MyAdminAccount
 
.NOTES
General notes
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [System.String]$Username,
        [Parameter(Mandatory = $true)]
        [System.String]$Password,
        [Parameter()]
        [System.String]$ComputerName = $env:COMPUTERNAME,
        # Specifies the user account credentials to use when performing this task.
        [Parameter()]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

    begin {
        $ErrorActionPreference = 'Stop'
    }

    process {
        $NewSecurePwd = $Password | ConvertTo-SecureString -AsPlainText -Force

        try
        {
            if ($ComputerName -ne $env:COMPUTERNAME)
            {
                $Session = New-PSSession -ComputerName $ComputerName -Credential $Credential
                Invoke-Command -Session $Session -ScriptBlock {
                    Get-LocalUser -Name $Using:Username | Set-LocalUser -Password $Using:NewSecurePwd
                }
                Remove-PSSession -Session $Session
                return
            }
            else
            {
                Get-LocalUser -Name $Username | Set-LocalUser -Password $NewSecurePwd
                return
            }

        }
        catch [Microsoft.PowerShell.Commands.UserNotFoundException]
        {
            Write-Error ('[{0:O}] User {1} not found' -f (get-date),$Username)
        }
        catch [Microsoft.PowerShell.Commands.AccessDeniedException]
        {
            Write-Error ('[{0:O}] Access denied, use account with suffisant privilege' -f (get-date))
        }
        catch
        {
            Write-Output ('[{0:O}] ErrorID: {1}' -f (get-date),$_.Exception.Message)
            Write-Output ('[{0:O}] Exception: {1}' -f (get-date),$_.FullyQualifiedErrorId)
            Write-Output ('[{0:O}] Category: {1}' -f (get-date),(($_.Exception.GetType() | Select-Object -ExpandProperty UnderlyingSystemType).FullName))
        }

    }

    end {
        $ErrorActionPreference = 'Continue'
    }
}
#EndRegion '.\Public\Set-LocalUserPassword.ps1' 93