Private/BitTitanTools/BitTitanTools.psm1

<#
.NOTES
    Company: BitTitan, Inc.
    Title: BitTitanUtilities.PS1
    Author: SUPPORT@BITTITAN.COM
    Requirements:
     
    Version: 1.5
    Date: December 6, 2016
 
    PowerShell Version: 3,4,5
 
    Disclaimer: This script is provided ‘AS IS’. No warrantee is provided either expresses or implied.
 
    Copyright: Copyright© 2016 BitTitan. All rights reserved.
     
.Synopsis
   This Module provides Tools for use internally and externally. The Tools provided are:
 
    1. Logging - Set-LoggingConfiguration, Get-LoggingConfiguration, Add LogEntry, Suspend-Logging, and Resume-Logging
    2. Disable and Enable Console Select Mode - Use these Cmdlets to make sure that the script is not paused by the use clicking in the Console window.
 
.REMARKS
    Each tool is documented separately.
    To learn more about each cmdlet, call Get-Help <Cmdlet>.
    To enumerate the Cmdlets, use Get-Command -Module BitTitanUtilities.
#>


#region =============== LOGGING =============================


<#
.Synopsis
   Set-LoggingConfiguration - Use to set the global setting for the Log function.
 
.DESCRIPTION
   Set-LoggingConfiguration - Use to set the global setting for the Log function. These global settings apply only to the current Session and you can override any of these settings for a specific call to 'Log'.
    
   Sets the following global settings:
 
       ScriptName - the name of the script you are running, without the extension. For example, 'ExportExchangeOnlinePermissions.ps1' would be 'ExportExchangeOnlinePermissions'.
     
       RunType - The type run of that your script is. Here are the possible values and their meanings:
            
           Development - you are developing the script.
           Debug - you are running the script in the debug mode, for debugging purposes.
           Test - You are running the script in a Test Environment.
           Internal - the script is running inside the BitTitan environemnt for internal purposes.
           Customer - You are running the script in a real-world, customer environment.
            
        LogToConsole - output the Log Entries to the PowerShell Console Window.
        LogToText - saves the Log Entries to a flat text file on disk.
 
        LogFolder - the folder where the text file is being written to. The name is derived as : <scriptName>
         
        TextFilename - the name of the text file is derived as <ScriptName>.<RunType>.<Date>.txt
 
        TotalLogEntries - the total number of Log Entries during the current Session. This can be viewed by running Get-LoggingConfiguration.
 
.EXAMPLE
   Set-LoggingConfiguration -Runtype "Debug" -ScriptName "ExportExchangeUsersToCSV" -LogToConsole -LogToText
   Configures all logging in the script to send log messages to the Console and a text file.
 
.OUTPUTS
   NONE. Only sets global variable values.
 
.ERRORS
    NONE
#>

function Set-LoggingConfiguration
{
    # Create global variables
    [CmdletBinding(ConfirmImpact='Low')]
    [Alias("ConfigLog")]

    Param(
        
        [Parameter (Mandatory=$true,
            ParameterSetName="Default",
            HelpMessage="Specify where the type of script run that logs the messages. Values are: 'Developement', 'Debug', 'Test', 'Internal', 'Customer'.")]
        [ValidateSet("Development","Debug","Test","Internal", "Customer")]
        [String]$RunType,


        [Parameter (Mandatory=$true,
            ParameterSetName="Default",
            HelpMessage="Specify the name of the script you are runnng, without the file extension. For example, for LoadAdUsers.ps1 specify 'LoadAdUsers'.")]
        [ValidateNotNullOrempty()]
        [String]$ScriptName,


        [Parameter (Mandatory=$true,
            ParameterSetName="Default",
            HelpMessage="Specify the version of the script you are runnng. For example, '1.5'")]
        [ValidateNotNullOrempty()]
        [String]$ScriptVersion,


        [Parameter (Mandatory=$false,
            ParameterSetName="Default",
            HelpMessage="Specifies that Log Entries are not saved to a flat text file on disk. By default log entries are logged to a text file.")]
        [switch]$NoTextLogging,


        [Parameter (Mandatory=$false,
            ParameterSetName="Default",
            HelpMessage="Specifies that Log Entries are displayed to the Console Window. You can specify as many outputs as you want. The switches are additive.")]
        [switch]$LogToConsole,


        [Parameter (Mandatory=$false,
            ParameterSetName="Default",
            HelpMessage="Specify the path to a folder that your logon can write to.")]
        [ValidateNotNullOrempty()]
        [String]$LogFolder
    )

    Process
    {
        $global:SuspendLogging = $false
        $global:TotalLogEntries = 0
        $global:ScriptName = $ScriptName
        $global:ScriptVersion = $ScriptVersion
        $global:RunType = $RunType
        $global:LogToConsole = $LogToConsole
        $global:ScriptStartTime = Get-date

        if($NoTextLogging)
        {
            $global:LogToText = $false
        }
        else
        {
            $global:LogToText = $true
        }

        $TimeStamp = Get-Date -format "yyyy-MM-dd HH:mm:ss"
 

        if ($LogFolder)
        {
            $global:LogFolder = $LogFolder
        }
        else 
        {
            $global:LogFolder = $env:PUBLIC
        }


        if (Test-Path -Path $global:LogFolder)
        {
            $global:LogFolder = Join-Path -Path $global:LogFolder -ChildPath "BitTitanLogging"
            if(-not (Test-Path -Path $global:LogFolder))
            {
                New-Item -Path $global:LogFolder -ItemType Directory | Out-Null
            }

            $global:LogFolder = Join-Path -Path $global:LogFolder -ChildPath "$global:ScriptName.$ScriptVersion"
            if(-not (Test-Path -Path $global:LogFolder))
            {
                New-Item -Path $global:LogFolder -ItemType Directory | Out-Null
            }
        }
        else
        {
            Write-Error "Specified log folder does not exist."
        }


        $Date = (Get-Date -format "yyyy-MM-dd")
        $global:LogFileName = "$ScriptName-$ScriptVersion-$RunType-$Date"


        $global:TextFilename = "$global:LogFileName.txt"

        $global:AllSet = $true

    }
}


<#
.Synopsis
   Get-LoggingConfiguration - Use to get the global setting for the Log function.
 
.DESCRIPTION
   Get-LoggingConfiguration - Use to get the global setting for the Log function. These global settings apply only to the current Session and you can override any of these settings for a specific call to 'Log'. Sets the following global settings:
     
       ScriptName - the name of the script you are running, without the extension. For example, 'ExportExchangeOnlinePermissions.ps1' would be 'ExportExchangeOnlinePermissions'.
     
       RunType - The type run of that your script is. Here are the possible values and their meanings:
            
           Development - you are developing the script.
           Debug - you are running the script in the debug mode, for debugging purposes.
           Test - You are running the script in a Test Environment.
           Customer - You are running the script in a real-world, customer environment.
            
        LogToConsole - output the Log Entries to the PowerShell Console Window.
        LogToText - saves the Log Entries to a flat text file on disk.
 
        LogFolder - the folder where the text file is being written to. The name is derived as : <scriptName>
         
        TextFilename - the name of the text file is derived as <ScriptName>.<RunType>.<Date>.txt
 
        TotalLogEntries - the total number of Log Entries during the current Session. This can be viewed by running Get-LoggingConfiguration.
 
.EXAMPLE
   Get-LoggingConfiguration
 
.OUTPUTS
   System.Collections.Hashtable - Key-Value pairs of the Global Logging Settings
 
.ERRORS
   If the Logging Settings have not been configured by using Set-LoggingConfiguration -- "You must use Set-LoggingConfiguration before using New-LogEntry ('Log') or Get-LoggingConfiguration ('GetConfig')."
#>

function Get-LoggingConfiguration
{
    [CmdletBinding(ConfirmImpact='Low')]
    [Alias("gconfig")]
    [OutputType([System.Collections.Hashtable])]
    Param()


    Process
    {
        if($global:AllSet -ne $true)
        {
            Write-Error "You must use Set-LoggingConfiguration before using Get-LoggingConfiguration ('gconfig')."
        }


        $out = @{}

        $out.Add("Script Name: ",$global:ScriptName)
        $out.Add("Script Version: ",$global:ScriptVersion)
        $out.Add("RunType: ",$global:RunType)
        $out.Add("LogFolder: ",$global:LogFolder)
        $out.Add("LogFile: ",$global:LogFileName)
        $out.Add("LogToText: ",$global:LogToText)
        $out.Add("LogToConsole: ",$global:LogToConsole)
        $out.Add("Total Log Entries: ",$global:TotalLogEntries)

        return $out
    }
}


<#
.Synopsis
   Add-LogEntry - Add a log entry to the log.
 
.DESCRIPTION
   Add-LogEntry - Add a log entry to the log.
   The log entry will be added to the currently specified log file with the metadata specified by Set-LoggingConfiguration.
   The only required parameter is -Message. However, you can temporarily override the global values for this entry only by specifying one or more of the values.
 
.EXAMPLE
   Add-LogEntry -Message "The Exchange cmdlet Get-Mailbox returned no results."
    
.EXAMPLE
   Add-LogEntry -Message "The Exchange cmdlet Get-Mailbox returned no results." -Color Red
   This example writes to the Console in Green. The Color setting only works in Verbose mode. The default color for Verbose is Cyan.
 
 
.EXAMPLE
   Add-LogEntry -Message "The Exchange cmdlet Get-Mailbox returned no results." -LogLevel Error
   This example temporarily override the global LogLevel setting and uses Write-Error to the Console. The text entry is written normally.
 
.OUTPUTS
   If -LogToConsole is selected, or the global values are set to these, the function will output the text to the Console window.
   If -LogToTextFile is selected, or the global values are set to these, the function will output to a text file.
 
   *Note - these selections are additive, that is you can log to multiple outputs by using the switch parameter for each.
   For example to log to both a text file and the Console, use:
    Add-LogEntry -Message "The Exchange cmdlet Get-Mailbox returned no results."-LogToConsole -LogToText
 
.NOTES
   The settings in this Cmdlet are only valid for this specific Log Entry. The settings for the next Log Entry will be determined by the Global values set by using v
 
.ERRORS
   If the Logging Settings have not been configured by using Set-LoggingConfiguration -- "You must use Set-LoggingConfiguration before using New-LogEntry ('Log') or Get-LoggingConfiguration ('GetConfig')."
#>

function Add-LogEntry
{
    [CmdletBinding(DefaultParameterSetName='Default', ConfirmImpact='Low')]
    [Alias("Log")]
    Param(

        # Log Output Type + TextFile
        [Parameter (Mandatory=$false,
            ParameterSetName="Default",
            HelpMessage="Specifies that Log Entries are saved to a flat text file on disk. Use this if you have set the global -NoTextLogging switch using Set-LoggingConfiguration, but want to log this specific entry to the text file.")]
        [switch]$LogtoText,


        # Log Output Type + TextFile
        [Parameter (Mandatory=$false,
            ParameterSetName="Default",
            HelpMessage="Specifies that Log Entries are displayed to the Console Window. You can specify as many outputs as you want. The switches are additive.")]
        [switch]$LogToConsole,



        [Parameter (Mandatory=$false,
            ParameterSetName="Default",
            HelpMessage="Specify the log level. Values are: 'Error', 'Warning', 'Verbose'. The default is 'Verbose'.")]
        [ValidateSet("Error","Warning","Verbose")]
        [String]$LogLevel = "Verbose",


        [Parameter (Mandatory=$true,
            ParameterSetName="Default",
            HelpMessage="Specify the Message text for the log entry.")]
        [ValidateNotNullOrempty()]
        [String]$Message, 


        [Parameter (Mandatory=$false,
            ParameterSetName="Default",
            HelpMessage="Specify the System.Console.ForegroundColor (System.ConsoleColor) for the Message text. The setting only affects the LogToConsole option and is for this entry only and will revert to the default setting for subsequent entries.")]
        [ValidateSet("Black","Blue","Cyan","DarkBlue","DarkCyan","DarkGray","DarkGreen","DarkMagenta","DarkRed","DarkYellow","Gray","Green","Magenta","Red","White","Yellow")]
        [string]$Color,


        # Log Output Type + TextFile
        [Parameter (Mandatory=$false,
            ParameterSetName="Default",
            HelpMessage="Specifies that Script Running Time will be logged to all specified outputs. The RunningTime is the total time that the script has been riunning up to the point that -RunningTime is called. You can use this at any point in the script execution.")]
        [switch]$RunningTime
    )

    Process
    {
        if($global:AllSet -ne $true)
        {
            Write-Error "You must use Set-LoggingConfiguration before using Add-LogEntry ('Log')."
        }

        if(-not $global:SuspendLogging)
        {
            $global:TotalLogEntries ++

            $TimeStamp = Get-Date -format "yyyy-MM-dd HH:mm:ss.fff"

            if($RunningTime)
            {
                $ScriptEndTime = Get-Date
                $TotalRunningtime = ($ScriptEndTime - $global:ScriptStartTime)
                $Message += "Script: $global:ScriptName Running Time: $TotalRunningtime"
            }

    
            #region LOG To TextFile
            if ($LogtoText -or $global:LogToText)
            {
                if($LogLevel -eq "Error")
                {
                    $TextLogEntryString = "$global:ScriptName.$global:ScriptVersion.$global:RunType.$TimeStamp -- $LogLevel -- $Message"
                }
                else
                {
                    $TextLogEntryString = "$global:ScriptName.$global:ScriptVersion.$global:RunType.$TimeStamp -- $LogLevel -- $Message"
                }


                $thisFileName = Join-Path -Path $global:LogFolder -ChildPath $global:TextFilename
                $TextLogEntryString | Out-File -FilePath $thisFileName -Append -Force
            }
            #endregion



            #region LOG To Console
            if ($LogToConsole -or $global:LogToConsole)
            {
                $LogEntryString = "$global:ScriptName.$global:ScriptVersion.$global:RunType.$TimeStamp"

                switch ($LogLevel)
                {
                    "Error"
                    {
                        Write-Error "$LogEntryString.$LogLevel -- $Message" 
                    }

                    "Warning"
                    {
                        Write-Warning "$LogEntryString.$LogLevel -- $Message"
                    }


                    "Verbose"
                    {
                        if ($Color)
                        {
                            Write-Host "$LogEntryString.$LogLevel -- $Message" -ForegroundColor $Color
                        }
                        else
                        {
                            Write-Host "$LogEntryString.$LogLevel -- $Message" -ForegroundColor Cyan
                        }
                    }

                    Default 
                    {
                        if ($Color)
                        {
                            Write-Host "$LogEntryString.$LogLevel -- $Message" -ForegroundColor $Color
                        }
                        else
                        {
                            Write-Host "$LogEntryString.$LogLevel -- $Message" -ForegroundColor Cyan
                        }
                    }
                }
            }

            #endregion


        }
    }
}    


<#
.Synopsis
   Suspend-Logging - Pauses Logging until Resume-Logging is called.
 
.DESCRIPTION
   Suspend-Logging - Pauses Logging until Resume-Logging is called or until you call Set-LoggingConfiguration, which sets $global:SuspendLogging = $false.
   No further Log Entries will be added to any Destination until Resume-Logging is called.
   You would use this if you are iterating through many steps that you do not need logging for.
 
.ERRORS
   NONE
#>

function Suspend-Logging
{
    [CmdletBinding(DefaultParameterSetName='Default', ConfirmImpact='Low')]
    [Alias("stop")]
    Param()
    
    Process
    {
        $global:SuspendLogging = $true
    }
}


<#
.Synopsis
   Resume-Logging - Resumes paused logging.
 
.DESCRIPTION
   Resume-Logging - Resumes paused logging.
   Log Entries will resume be added to any Destination until Suspend-Logging is called.
   You would use Suspend-Logging this if you are iterating through many steps that you do not need logging for.
 
.ERRORS
   NONE
#>

function Resume-Logging
{
    [CmdletBinding(DefaultParameterSetName='Default', ConfirmImpact='Low')]
    [Alias("go")]
    Param()
    
    Process
    {
        $global:SuspendLogging = $false
    }
}


<#
.Synopsis
   Export-LogFile - Creates a zip file from the Log File and saves it in the current LogFolder.
 
.DESCRIPTION
   Export-LogFile - Creates a zip file from the Log File and saves it in the current LogFolder.
   The zip file name is <ScriptName>-<Runtype>-<Date YYYY-MM-DD>.zip and is created in the current LogFolder.
   By default the LogFolder is 'C:\Users\Public\BitTitanLogging\<ScriptName>'.
   If you specify a LogFolder when calling Set-LoggingConfiguration -LogFolder, you will have to look in that folder.
 
   IMPORTANT - The Cmdlet will overwrite any previously-created archive of the script being run.
 
.ERRORS
   NONE
#>

function Export-LogFileArchive
{
    [CmdletBinding(DefaultParameterSetName='Default', ConfirmImpact='Low')]
    [Alias("zip")]
    Param() 

    Process
    {
        # Create paths and filenames
        $ZipFilename = "$global:LogFileName.zip"
        $ZipFullPath = Join-Path -Path $global:LogFolder -ChildPath $ZipFilename

        if(Test-Path -Path $ZipFullPath)
        {
            Remove-Item -Path $ZipFullPath -Force
        }

        Add-Type -Assembly System.IO.Compression.FileSystem 
        $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
        try
        {
            [System.IO.Compression.ZipFile]::CreateFromDirectory($global:LogFolder, 
                                                           $ZipFullPath,
                                                           $compressionLevel, 
                                                          $false) 
        }
        # Adding empty catch block because API always throws error even when successfully creating zip file -- known issue
        catch {}
             
        Log -Message "Zip file created in current LogFolder."

    }
}
#endregion




#region =============== SELECT MODE =============================

<#
.Synopsis
   Disable-SelectMode - Prevents the Console Window from entering select mode. While this is True, users will not be able to click in the Console Window and select text.
 
.DESCRIPTION
   Disable-SelectMode - Prevents the Console Window from entering select mode.
   Select Mode is where the user can interact with the Console and select text to Copy or Paste. this is only in effect until the current Session ends, the current Console is closed, or Enable-SelectMode is called.
 
.EXAMPLES
    Disable-SelectMode
    this disabled Select Mode for the current Console Window for as long as the current script runs, or until Enable-SelectMode is called.
#>

function Disable-SelectMode
{
    [CmdletBinding(DefaultParameterSetName='Default', ConfirmImpact='Medium')]
    [Alias("nosel")]
    Param()

    Process
    {
        $ReturnSuccess = $false

        # Imports some system primitives.
        Add-Type -MemberDefinition @"
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern bool SetConsoleMode(IntPtr hConsoleHandle, int mode);
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern IntPtr GetStdHandle(int handle);
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern bool GetConsoleMode(IntPtr handle, out int mode);
        [DllImport("Kernel32.dll")]
        public static extern IntPtr GetConsoleWindow();
"@
 -Namespace Win32 -Name NativeMethods
        
        # SET Selct Mode OFF for Input Console
        try 
        {
            $HandleInput = [Win32.NativeMethods]::GetStdHandle(-10)

            Log -Message "Input Handle: $HandleInput"

            $ModeInput = 0

            try
            {
                $ResultInput = [Win32.NativeMethods]::GetConsoleMode($HandleInput, [ref]$ModeInput)
                $ModeInput = $ModeInput -band (-bnot 0x040)
                Log -Message "Input Console Mode: $ModeInput"

                try
                {
                    $ResultInput = [Win32.NativeMethods]::SetConsoleMode($HandleInput, $ModeInput)

                    $ReturnSuccess = $true
                }
                catch
                {
                    Log -Message "SetConsoleMode call failed. Select Mode cannot be DISABLED."
                    throw
                }

            }
            catch
            {
                Log -Message "GetConsoleMode call failed. Select Mode cannot be DISABLED."
                throw
            }

        }
        catch
        {
            Log -Message "GetStdHandle for HandleInput failed. Select Mode cannot be DISABLED." -LogLevel Error
            throw
        }



        # SET Selct Mode OFF for Output Console
        try 
        {
            $HandleOutput = [Win32.NativeMethods]::GetStdHandle(-11)

            Log -Message "Input Handle: $HandleOutput"

            $ModeOutput = 0

            try
            {
                $ResultOutput = [Win32.NativeMethods]::GetConsoleMode($HandleOutput, [ref]$ModeOutput)
                $ModeOutput = $ModeOutput -band (-bnot 0x040)

                Log -Message "Output Console Mode: $ModeOutput"

                try
                {
                    $ResultOutput = [Win32.NativeMethods]::SetConsoleMode($HandleOutput, $ModeOutput)

                    if ($ReturnSuccess)
                    {
                        Log -Message "Select Mode is DISABLED." -Color Green

                        return $true
                    }
                    else
                    {
                        Log -Message "Select Mode could not be diabled." -LogLevel Error
                        return $false
                    }
                }
                catch
                {
                    Log -Message "SetConsoleMode call failed. Select Mode cannot be DISABLED." -LogLevel Error
                    throw
                }

            }
            catch
            {
                Log -Message "GetConsoleMode call failed. Select Mode cannot be DISABLED." -LogLevel Error
                throw
            }

        }
        catch
        {
            Log -Message "GetStdHandle for HandleOutput failed. Select Mode cannot be DISABLED." -LogLevel Error
            throw
        }

    }
}


<#
.Synopsis
   Enable-SelectMode - Allows the Console Window to enter select mode. While this is True, users will be able to click in the Console Window and select text. If they do the script running will hault until select mode is stopped manually. Calling Disable-SelectMode will not have any effect.
 
.DESCRIPTION
   Disable-SelectMode - Prevents the Console Window from entering select mode.
   Select Mode is where the user can interact with the Console and select text to Copy or Paste. this is only in effect until the current Session ends, the current Console is closed, or Enable-SelectMode is called.
 
.EXAMPLES
    Enable-SelectMode
    This enables Select Mode for the current Console Window for as long as the current script runs, or until Disable-SelectMode is called.
#>

function Enable-SelectMode
{
    [CmdletBinding(DefaultParameterSetName='Default', ConfirmImpact='Medium')]
    [Alias("sel")]
    Param()


    Process
    {
        $ReturnSuccess = $false

        # Imports some system primitives.
        Add-Type -MemberDefinition @"
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern bool SetConsoleMode(IntPtr hConsoleHandle, int mode);
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern IntPtr GetStdHandle(int handle);
        [DllImport("kernel32.dll", SetLastError=true)]
        public static extern bool GetConsoleMode(IntPtr handle, out int mode);
        [DllImport("Kernel32.dll")]
        public static extern IntPtr GetConsoleWindow();
"@
 -Namespace Win32 -Name NativeMethods
        
        # SET Selct Mode ON for Input Console
        try 
        {
            $HandleInput = [Win32.NativeMethods]::GetStdHandle(-10)

            Log -Message "Input Handle: $HandleInput"

            $ModeInput = 0

            try
            {
                $ResultInput = [Win32.NativeMethods]::GetConsoleMode($HandleInput, [ref]$ModeInput)
                $ModeInput = $ModeOutput -band $ModeOutput -bor ( 0x040)
                Log -Message "Input Console Mode: $ModeInput"

                try
                {
                    $ResultInput = [Win32.NativeMethods]::SetConsoleMode($HandleInput, $ModeInput)

                    $ReturnSuccess = $true
                }
                catch
                {
                    Log -Message "SetConsoleMode call failed. Select Mode cannot be ENABLED."
                    throw
                }

            }
            catch
            {
                Log -Message "GetConsoleMode call failed. Select Mode cannot be ENABLED."
                throw
            }

        }
        catch
        {
            Log -Message "GetStdHandle for HandleInput failed. Select Mode cannot be ENABLED." -LogLevel Error
            throw
        }



        # SET Selct Mode ON for Output Console
        try 
        {
            $HandleOutput = [Win32.NativeMethods]::GetStdHandle(-11)

            Log -Message "Input Handle: $HandleOutput"

            $ModeOutput = 0

            try
            {
                $ResultOutput = [Win32.NativeMethods]::GetConsoleMode($HandleOutput, [ref]$ModeOutput)
                $ModeOutput = $ModeOutput -bor ( 0x040)

                Log -Message "Output Console Mode: $ModeOutput"

                try
                {
                    $ResultOutput = [Win32.NativeMethods]::SetConsoleMode($HandleOutput, $ModeOutput)

                    if ($ReturnSuccess)
                    {
                        Log -Message "Select Mode is ENABLED." -Color Green

                        return $true
                    }
                    else
                    {
                        Log -Message "Select Mode could not be ENABLED." -LogLevel Error
                        return $false
                    }
                }
                catch
                {
                    Log -Message "SetConsoleMode call failed. Select Mode cannot be ENABLED." -LogLevel Error
                    throw
                }

            }
            catch
            {
                Log -Message "GetConsoleMode call failed. Select Mode cannot be ENABLED." -LogLevel Error
                throw
            }

        }
        catch
        {
            Log -Message "GetStdHandle for HandleOutput failed. Select Mode cannot be ENABLED." -LogLevel Error
            throw
        }

    }
}

#endregion



#region ================= FILE TOOLS ================================


<#
.Synopsis
   New-BtZipFile - Use to create a compressed-file (zip).
 
.DESCRIPTION
   New-BtZipFile - Use to create a compressed-file (zip).
    
    The compression level (defaults to Optimal):
        Optimal - The compression operation should be optimally compressed, even if the operation takes a longer time to complete.
        Fastest - The compression operation should complete as quickly as possible, even if the resulting file is not optimally compressed.
        NoCompression - No compression should be performed on the file.
 
 
.EXAMPLE
   New-BtZipFile -ZipFilePath $CsvZipPath -SourcePath $CsvPath
   Archives all the files in $CsvPath to the zip file $CsvZipPath using the default compression.
 
.OUTPUTS
   NONE. Only sets global variable values.
 
.ERRORS
    NONE
#>

function New-BtZipFile
{
    [CmdletBinding()]
    [Alias ("zip")]
    [OutputType([bool])]
    Param(

        [Parameter(Mandatory=$true,
            ValueFromPipelineByPropertyName=$true,
            HelpMessage="[Required] (String) -- Specify the folder containing the files to be archived as a zip file.")]
        [Alias("spath","item")]
        [ValidateNotNullOrEmpty()]
        [string]$SourcePath,
 

        [Parameter(Mandatory=$true,
                HelpMessage="[Required] (String) -- Enter the full path to where you want the zip file to be written.")]
        [Alias("zpath")]
        [ValidateNotNullOrEmpty()]
        [string] $ZipFilePath,
 


        [Parameter(Mandatory=$false,
                HelpMessage="[Optional] (String) -- Specify the compresssion level the zip file. If you do not specify, the level is 'Optimal'.")]
        [ValidateSet("Fastest", "NoCompression", "Optimal")]
        [System.IO.Compression.CompressionLevel]$Compression = "Optimal"
    )

    Begin
    {
        Log -Message "================= BEGIN New-BtZipFile ======================" 
        Add-Type -As System.IO.Compression.FileSystem


        if(Test-Path $ZipFilePath)
        { 
            Remove-Item $ZipFilePath -Force
        }

        if ($Compression)
        {
            $compressionLevel = $Compression
        }
        else
        {
            $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
        }

        Log -Message "Compression level set to : $compressionLevel"
    }

    # Process each of the input Paths
    Process 
    {
        try
        {
            [System.IO.Compression.ZipFile]::CreateFromDirectory($SourcePath, $ZipFilePath, $compressionLevel, $false) 
        }
        # Adding empty catch block because API always throws error even when successfully creating zip file -- known issue
        catch { throw }

        if (Test-Path -Path $ZipFilePath)
        {
            Log -Message "Zip file $ZipFilePath created."
            Write-Output $true
        }
        else
        {
            Log -Message "Zip file $ZipFilePath could not be created."
            Write-Output $false
        }
    }
}



#endregion



#region =============== Bittitan PowerShell ==========================

function Import-BTPowerShell
{
    [CmdletBinding(ConfirmImpact='Low')]
    [Alias("imp")]

    Param()

    Process
    {
            Import-Module “C:\Program Files (x86)\BitTitan\BitTitan PowerShell\BitTitanPowerShell.dll”
    }

}





#endregion