CISPowerShell.psm1

<#
.SYNOPSIS
    Save Putty
 
.DESCRIPTION
    Save the x64 or x86 version of the latest version of Putty to a
    specified file path location
 
.EXAMPLE
    Save-Putty -FilePath C:\
     
    This example will determine if you need the x86 or x64 version of Putty
    and save the executable file to c:\putty.exe
 
.EXAMPLE
    Save-Putty -FilePath C:\users\Me\NewFolder
 
    This example will determine if you need the x86 or x64 version of Putty
    and save the executable file to c:\users\Me\NewFolder. If NewFolder doesn't
    exist, the cmdlet will create the folder for you
#>

function Save-Putty
{ 
    [cmdletbinding()]
    param
    (
        [parameter(Mandatory = $true)]
        [string]$FilePath
    )

    begin
    {
        $timer = New-Object -TypeName System.Diagnostics.StopWatch
        $cmdletName = $PSCmdlet.MyInvocation.MyCommand.Name
        Write-Verbose -Message ('{0} : Begin execution : {1}' -f $cmdletName, (Get-Date))
        $timer.Start()
    }

    process
    {
        try
        {
            if (Test-Connection google.com -Count 1)
            {
                Write-Verbose -Message ('{0} : Creating destination filepath : {1}' -f $cmdletName, $FilePath)
                If (!(Test-Path -Path $FilePath))
                {
                    New-Item -Path $FilePath -ItemType Directory -Force | Out-Null
                    Write-Verbose -Message ('{0} : Created destination filepath complete' -f $cmdletName)
                }
                Write-Verbose -Message ('{0} : Detecting operating system architecture' -f $cmdletName)
                $uri = switch ((Get-WmiObject -Class Win32_OperatingSystem -Property OSArchitecture).OSArchitecture)
                {
                    '32-bit'
                    {
                        Write-Verbose -Message ('{0} : Detected x86 operating system' -f $cmdletName)
                        'https://the.earth.li/~sgtatham/putty/latest/w32/putty.exe'
                    }

                    '64-bit'
                    {
                        Write-Verbose -Message ('{0} : Detected x64 operating system' -f $cmdletName)
                        'https://the.earth.li/~sgtatham/putty/latest/w64/putty.exe'
                    }
                }
                Write-Verbose -Message ('{0} : Download URL : {1}' -f $cmdletName, $uri)
                Invoke-WebRequest -Uri $uri -OutFile (Join-Path -Path $FilePath -ChildPath 'putty.exe')
                Write-Verbose -Message ('{0} : Download complete' -f $cmdletName)
                '{0} : Download complete. FilePath : {1}\putty.exe' -f $cmdletName, $FilePath | Write-Output
            }
            else
            {
                'No access to internet! Unable to download Putty!' | Write-Warning
            }
        }
        catch
        {
            throw
        }
    }

    end
    {
        $timer.Stop()
        Write-Verbose -Message ('{0} : End execution' -f $cmdletName)
        Write-Verbose -Message ('Total execution time: {0} ms' -f $timer.Elapsed.TotalMilliseconds)
    }
}


<#
.SYNOPSIS
    Get a computer's public IP address
 
.DESCRIPTION
    Retrieve a computer's public IP address by using Amazon's CheckIP REST service
 
.EXAMPLE
    Get-PublicIP
     
    This example will retrieve the local machine's public IP address
 
.EXAMPLE
    Get-PublicIP -ComputerName Computer1, Computer2, Computer3
 
    This example will retrieve the specified computers public IP addresses using
    default credentials
 
.EXAMPLE
    Get-PublicIP -ComputerName (Get-Content c:\list.txt) -Credential (Get-Credential)
 
    This example will retrieve public IP addresses for the list of computer names
    in the file c:\list.txt (one computername per line) using the specified credentials
#>

function Get-PublicIP
{
    [cmdletbinding()]
    param
    (
        [parameter(ValueFromPipeline = $true,
                   ValueFromPipelineByPropertyName = $true)]
        [string[]]$ComputerName = $env:COMPUTERNAME,
        
        [parameter()]
        [pscredential]$Credential   
    )

    begin
    {
        $timer = New-Object -TypeName System.Diagnostics.StopWatch
        $cmdletName = $PSCmdlet.MyInvocation.MyCommand.Name
        Write-Verbose -Message ('{0} : Begin execution : {1}' -f $cmdletName, (Get-Date))
        $timer.Start()
    }

    process
    {
        foreach ($computer in $ComputerName)
        {
            try
            {
                Write-Verbose -Message ('{0} : {1} : Begin execution' -f $cmdletName, $computer)
                $sessionParams = @{ComputerName = $computer
                                   ErrorAction  = 'Stop'}
                if ($Credential -ne $null)
                {
                    $sessionParams.Add('Credential', $Credential)
                    Write-Verbose -Message ('{0} : {1} : Using supplied credentials' -f $cmdletName, $computer)
                }
                else
                {
                    Write-Verbose -Message ('{0} : {1} : Using default credentials' -f $cmdletName, $computer)
                }
                $session = $null
                $session = New-PSSession @sessionParams
                if ($session)
                {
                    $ip = $null
                    $ip = Invoke-Command -Session $session -ScriptBlock {
                        Invoke-RestMethod -Uri http://checkip.amazonaws.com
                    }
                    $props = @{ComputerName = [string]$computer
                               PublicIP     = [ipaddress]$ip.Trim()}
                    New-Object -TypeName System.Management.Automation.PSObject -Property $props | Write-Output
                }
                else
                {
                    '{0} : {1} : Unable to create PSSession. If not supplied, try including the -Credential parameter' -f $cmdletName, $computer | Write-Warning
                }
            }
            catch
            {
                throw
            }
        }
    }

    end
    {
        $timer.Stop()
        Write-Verbose -Message ('{0} : End execution' -f $cmdletName)
        Write-Verbose -Message ('Total execution time: {0} ms' -f $timer.Elapsed.TotalMilliseconds)
    }
}


<#
.SYNOPSIS
    Change a Server Core instance's default shell from CMD.exe to PowerShell.exe
 
.DESCRIPTION
    Set registry key to specify PowerShell as default shell
    HKLM:\Software\Microsoft\Windows NT\CurrentVersion\WinLogon\Shell = "PowerShell.exe -NoExit"
 
    * ONLY APPLICABLE TO SERVER CORE INSTALLATIONS *
 
.EXAMPLE
    Set-PowerShellDefaultShell
 
    This example sets PowerShell as the default shell on the local machine using default
    credentials and then warns the user that the local machine must still be rebooted for
    the changes to take effect
 
.EXAMPLE
    Set-PowerShellDefaultShell -ComputerName Server1, Server2 -Restart
 
    This example sets PowerShell as the default shell on the specified computer names (Server1
    and Server2) using default credentials and then reboots the computers automatically when
    complete.
 
.EXAMPLE
    Set-PowerShellDefaultshell -ComputerName (Get-Content c:\list.txt) -Credential (Get-Credential) -Restart
 
    This example sets Powershell as the default shell on the specified computer names read
    from the file specified (1 computername per line) using the supplied credentials of
    Get-Credential and then reboots the computers automatically when complete
#>

function Set-PowerShellDefaultShell
{
    [cmdletbinding()]
    param
    (
        [parameter(ValueFromPipeline = $true,
                   ValueFromPipelineByPropertyName = $true)]
        [string[]]$ComputerName = $env:COMPUTERNAME,
        
        [parameter()]
        [pscredential]$Credential,

        [parameter()]
        [alias('Reboot')]
        [switch]$Restart
    )

    begin
    {
        $timer = New-Object -TypeName System.Diagnostics.StopWatch
        $cmdletName = $PSCmdlet.MyInvocation.MyCommand.Name
        Write-Verbose -Message ('{0} : Begin execution : {1}' -f $cmdletName, (Get-Date))
        $timer.Start()

        $keyPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\winlogon'
        Write-Verbose -Message ('{0} : KeyPath : {1}' -f $cmdletName, $keyPath)
    }

    process
    {
        foreach ($computer in $ComputerName)
        {
            Write-Verbose -Message ('{0} : {1} : Begin execution' -f $cmdletName, $computer)
            $sessionParams = @{ComputerName = $computer
                               ErrorAction  = 'Stop'}
            if ($Credential -ne $null)
            {
                $sessionParams.Add('Credential', $Credential)
                Write-Verbose -Message ('{0} : {1} : Using supplied credentials' -f $cmdletName, $computer)
            }
            else
            {
                Write-Verbose -Message ('{0} : {1} : Using default credentials' -f $cmdletName, $computer)
            }
            $session = $null
            $session = New-PSSession @sessionParams
            if ($session)
            {
                try
                {
                    $result = Invoke-Command -Session $sessionParams -ArgumentList $keyPath, $Restart -ScriptBlock {
                        try
                        {
                            Set-ItemProperty -Path $args[0] -Name 'Shell' -Value 'PowerShell.exe -NoExit' -Force
                            $true | Write-Output
                            if ($args[1])
                            {
                                Restart-Computer -Force
                            }
                        }
                        catch
                        {
                            throw
                        }
                    }
                    New-Object -TypeName System.Management.Automation.PSCustomObject -Property @{ComputerName = $computer
                                                                                                 Result       = $result} |
                        Write-Output
                    if (!$Restart)
                    {
                        '{0} : {1} : Successfully set PowerShell as default shell - reboot is required to make setting active' -f $cmdletName, $computer | Write-Warning
                    }
                }
                catch
                {
                    throw
                }
            }
            else
            {
                '{0} : {1} : Unable to create PSSession' -f $cmdletName, $computer | Write-Warning
                if (!$Credential)
                {
                    'Try including the -Credential parameter!' | Write-Warning
                }
            }
        }
    }

    end
    {
        $timer.Stop()
        Write-Verbose -Message ('{0} : End execution' -f $cmdletName)
        Write-Verbose -Message ('Total execution time: {0} ms' -f $timer.Elapsed.TotalMilliseconds)
    }
}


<#
.SYNOPSIS
    Get a computers uptime
 
.DESCRIPTION
    Calculate a computer's uptime by retrieving the LastBootUpTime property from the Win32
    OperatingSystem WMI class and subtracting that from the current date and time.
 
.EXAMPLE
    Get-UpTime
 
    This example retrieves the local machine's uptime using default credentials
 
.EXAMPLE
    Get-UpTime -ComputerName Server1, Server2
 
    This example retrieves the specified computer's uptime using default credentials
 
.EXAMPLE
    Get-UpTime -ComputerName (Get-Content c:\list.txt) -Credential (Get-Credential)
 
    This example retrieves the computer names found in the file (one computer name per line)
    uptime using the specified credentials
#>

function Get-Uptime
{
    [cmdletbinding()]
    param
    (
        [parameter(ValueFromPipeline = $true,
                   ValueFromPipelineByPropertyName = $true)]
        [string[]]$ComputerName = $env:COMPUTERNAME,
        
        [parameter()]
        [pscredential]$Credential   
    )

    begin
    {
        $timer = New-Object -TypeName System.Diagnostics.StopWatch
        $cmdletName = $PSCmdlet.MyInvocation.MyCommand.Name
        Write-Verbose -Message ('{0} : Begin execution : {1}' -f $cmdletName, (Get-Date))
        $timer.Start()
    }

    process
    {
        foreach ($computer in $ComputerName)
        {
            try
            {
                Write-Verbose -Message ('{0} : {1} : Begin execution' -f $cmdletName, $computer)
                $sessionParams = @{ComputerName = $computer
                                   ErrorAction  = 'Stop'}
                if ($Credential -ne $null)
                {
                    $sessionParams.Add('Credential', $Credential)
                    Write-Verbose -Message ('{0} : {1} : Using supplied credentials' -f $cmdletName, $computer)
                }
                else
                {
                    Write-Verbose -Message ('{0} : {1} : Using default credentials' -f $cmdletName, $computer)
                }
                $session = $null
                $session = New-PSSession @sessionParams
                if ($session)
                {
                    $result = $null
                    $result = Invoke-Command -Session $session -ScriptBlock {
                        [DateTime]::Now - [Management.ManagementDateTimeConverter]::ToDateTime((Get-WmiObject Win32_OperatingSystem).LastBootUpTime)
                    }
                    if ($result)
                    {
                        $props = @{
                            ComputerName = $computer
                            UpTime       = ('{0}:{1}:{2}:{3}:{4}' -f $result.Days, $result.Hours, $result.Minutes, $result.Seconds, $result.Milliseconds)
                            TotalDays    = $result.TotalDays
                            TotalHours   = $result.TotalHours
                            TotalMinutes = $result.TotalMinutes
                            TotalSeconds = $result.TotalSeconds
                        }
                        New-Object -TypeName System.Management.Automation.PSObject -Property $props | Write-Output
                    }
                    else
                    {
                        '{0} : {1} : Unable to retrieve Win32_Operatingsystem.LastBootupTime informantion!' -f $cmdletName, $computer | Write-Warning
                    }
                }
                else
                {
                    $message = '{0} : {1} : Unable to create PSSession. Ensure PSremoting to {1} is enabled.' -f $cmdletName, $computer
                    if ($Credential -eq $null)
                    {
                        $message += ' Try including the -Credential parameter.'
                    }
                    $message | Write-Warning
                }
            }
            catch
            {
                throw
            }
        }
    }

    end
    {
        $timer.Stop()
        Write-Verbose -Message ('{0} : End execution' -f $cmdletName)
        Write-Verbose -Message ('Total execution time: {0} ms' -f $timer.Elapsed.TotalMilliseconds)
    }
}


# Kaseya credentials helper function
function Save-KCredentials
{
    param
    (
        [parameter(mandatory = $true)]
        [string]$UserName,

        [parameter(mandatory = $true)]
        [securestring]$Password
    )
    try
    {
        $filePath = (Join-Path $env:LOCALAPPDATA -ChildPath ('{0}_{1}_kcredentials.xml' -f $env:USERNAME, $env:COMPUTERNAME))
        Remove-Item -Path $filePath -Force -ErrorAction SilentlyContinue
        Get-Credential -Credential ([PScredential]::new($UserName, $Password)) -ErrorAction Stop |
            Export-Clixml -Path $filePath -Force -ErrorAction Stop
        Test-Path -Path $filePath | Write-Output
    }
    catch
    {
        $false | Write-Output
    }
}


# Kaseya Connect PowerShell Script generator
function Save-KConnect {
try
{
$FilePath = (Join-Path -Path $env:LOCALAPPDATA -ChildPath 'kconnect.ps1')
Remove-Item -Path $FilePath -ErrorAction SilentlyContinue
$contents = @'
$creds = (Import-Clixml -Path (Join-Path -Path $env:LOCALAPPDATA -ChildPath ('{0}_{1}_kcredentials.xml' -f $env:USERNAME, $env:COMPUTERNAME))).GetNetworkCredential()
$ie = New-Object -ComObject InternetExplorer.Application
$ie.Visible = $true
$ie.Navigate2('https://assist.customis.com/vsapres/web20/core/login.aspx')
$sw = '
[DllImport("user32.dll")]
public static extern int ShowWindow(int hwnd, int nCmdShow);
'
$type = Add-Type -Name ShowWindow2 -MemberDefinition $sw -Language CSharpVersion3 -Namespace Utils -PassThru
$type::ShowWindow($ie.hwnd, 3)
while ($ie.Busy) { Start-Sleep -Seconds 1 }
$user = $ie.Document.IHTMLDocument3_getElementById('UsernameTextbox')
if ($user) { $user.Value = $creds.UserName }
$pass = $ie.Document.IHTMLDocument3_getElementById('PasswordTextbox')
if ($pass) { $pass.Value = $creds.Password }
$button = $ie.Document.IHTMLDocument3_getElementById('SubmitButton')
if ($button) { $button.click() }
'@

New-Item -Path $FilePath -Value $contents -Force | Out-Null
$true | Write-Output
}
catch
{
    $false | Write-Output
}
}


<#
.SYNOPSIS
    Create a new Kaseya enhanced desktop shortcut
 
.DESCRIPTION
    Create a new desktop shortcut that launches Internet Explorer, navigates to CIS's Kaseya
    VSA, programmatically inputs the login credentials, logs in, and maximizes the Internet
    Explorer window
 
.EXAMPLE
    New-KaseyaShortcut (First Time)
 
    IF THIS IS THE FIRST TIME EVER this script is running, you will be prompted to enter in
    your Kaseya username and password. This information is securely encrypted and saved in your
    LocalAppData directory. A PowerShell script to control the interactions with Internet
    Explorer will also be saved to this directory. A desktop shortcut called "Connect Kaseya"
    will be created on your desktop. This desktop shortcut file may be moved to any other
    file system location.
     
    NOTE! Moving credential.xml and KConnect.ps1 files will result in this function asking for
    your credentials and saving these 2 files in the LocalAppData directory again.
 
.EXAMPLE
    New-KaseyaShortcut (Subsequent Times)
 
    If this is NOT the first time ever this function is running, a new Kaseya shortcut will be
    saved to your desktop. You may move this file after the function has completed.
 
.EXAMPLE
    New-KaseyaShortcut -Force (Any time)
 
    When you supply the -Force parameter, this function will go through it's execution as
    though as it were the first time it has ever executed. This is useful if you wish to
    change your current Kaseya credentials.
#>

function New-KaseyaShortcut
{
    [cmdletbinding()]
    param
    (
        [string]$FilePath = (Join-Path -Path ([Environment]::GetFolderPath('Desktop')) -ChildPath 'Connect Kaseya.lnk'),
        [switch]$Force
    )
    
    begin
    {
        $cmdletName = $PSCmdlet.MyInvocation.MyCommand.Name
        $timer      = New-Object -TypeName System.Diagnostics.StopWatch
        Write-Verbose -Message ('{0} : {1} : Begin execution' -f $cmdletName, (Get-Date))
        $timer.Start()

        $CredPath = Join-Path -Path $env:LOCALAPPDATA -ChildPath ('{0}_{1}_kcredentials.xml' -f $env:USERNAME, $env:COMPUTERNAME)
        $connPath = Join-Path -Path $env:LOCALAPPDATA -ChildPath 'kconnect.ps1'
        if (!$Force)
        {
            Write-Verbose -Message ('{0} : Force not detected' -f $cmdletName)
            Write-Verbose -Message ('{0} : Checking for encrypted Kaseya credential file' -f $cmdletName)
            if (!(Test-Path $CredPath))
            {
                Write-Verbose -Message ('{0} : Could not find encrypted Kaseya credential file. FilePath = {1}' -f $cmdletName, $CredPath)
                ('Could not find encrypted credential file for {0}\{1}!' -f $env:COMPUTERNAME, $env:USERNAME) | Write-Warning
                $u = Read-Host -Prompt 'Kaseya user name'
                $p = Read-Host -Prompt 'Kaseya password' -AsSecureString
                if (Save-KCredentials -UserName $u -Password $p)
                {
                    Write-Verbose -Message ('{0} : Successfully saved encrypted Kaseya credential file. FilePath ={0}' -f $cmdletName, $CredPath)
                    ('{0} : Successfully saved encrypted Kaseya credential file.' -f $cmdletName)
                }
                else
                {
                    'ERROR! Unable to save credential file to {0}' -f $CredPath | Write-Error
                }
            }
            else
            {
                Write-Verbose -Message ('{0} : Detected encrypted Kaseya credential file.' -f $cmdletName)
            }
            Write-Verbose -Message ('{0} : Checking for KConnect PowerShell script' -f $cmdletName)
            if (!(Test-Path $connPath))
            {
                Write-Verbose -Message ('{0} : Could not find Kaseya Connect PowerShell script. ConnPath = {0}' -f $cmdletName, $connPath)
                if (Save-KConnect)
                {
                    Write-Verbose -Message ('{0} : Successfully saved Kaseya Connect PowerShell script. ConnPath = {0}' -f $cmdletName, $connPath)
                    ('{0} : Successfully saved Kaseya Connect PowerShell script.' -f $cmdletName)
                }
                else
                {
                    'ERROR! Unable to save Kaseya Connect PowerShell script to {0}' -f $connPath | Write-Error
                }
            }
            else
            {
                Write-Verbose -Message ('{0} : Kaseya Connect PowerShell script already exists.' -f $cmdletName)
            }
        }
        else
        {
            Write-Verbose -Message ('{0} : Force detected. Generating new credentials file and Kaseya Connect PowerShell script' -f $cmdletName)
            Remove-Item -Path $CredPath -Force -ErrorAction SilentlyContinue
            Remove-Item -Path $connPath -Force -ErrorAction SilentlyContinue
            Remove-Item -Path $FilePath -Force -ErrorAction SilentlyContinue
            $u = Read-Host -Prompt 'Kaseya user name'
            $p = Read-Host -Prompt 'Kaseya password' -AsSecureString
            if (Save-KCredentials -UserName $u -Password $p)
            {
                Write-Verbose -Message ('{0} : Successfully saved encrypted Kaseya credential file. FilePath ={0}' -f $cmdletName, $CredPath)
                ('{0} : Successfully saved encrypted Kaseya credential file.' -f $cmdletName)
            }
            else
            {
                'ERROR! Unable to save credential file to {0}' -f $CredPath | Write-Error
            }
            if (Save-KConnect)
            {
                Write-Verbose -Message ('{0} : Successfully saved Kaseya Connect PowerShell script. ConnPath = {0}' -f $cmdletName, $connPath)
                ('{0} : Successfully saved Kaseya Connect PowerShell script.' -f $cmdletName)
            }
            else
            {
                'ERROR! Unable to save Kaseya Connect PowerShell script to {0}' -f $connPath | Write-Error
            }
        }
    }

    process
    {
        try
        {
            $shell = New-Object -ComObject Wscript.Shell
            $shortcut = $shell.CreateShortcut($FilePath)
            $shortcut.TargetPath = $('C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe')
            $shortcut.Arguments = (' -noprofile -command "& {0}"' -f (Join-Path -Path $env:LOCALAPPDATA -ChildPath 'kconnect.ps1'))
            $shortcut.WindowStyle = 7
            $shortcut.Save()
        }
        catch
        {
            throw
        }
    }

    end
    {
        $timer.Stop()
        Write-Verbose -Message ('{0} : {1} : End execution' -f $cmdletName, (Get-Date))
        'Total execution time: {0} ms' -f $timer.ElapsedMilliseconds
    }
}


# Portal credentials helper function
function Save-PortalCredentials
{
    param
    (
        [parameter(mandatory)]
        [string]$UserName,

        [parameter(mandatory)]
        [securestring]$Password
    )
    try
    {
        $filePath = (Join-Path $env:LOCALAPPDATA -ChildPath ('{0}_{1}_portalcredentials.xml' -f $env:USERNAME, $env:COMPUTERNAME))
        Remove-Item -Path $filePath -Force -ErrorAction SilentlyContinue
        Get-Credential -Credential ([PSCredential]::new($UserName, $Password)) -ErrorAction Stop |
            Export-Clixml -Path $filePath -Force -ErrorAction Stop
        Test-Path -Path $filePath | Write-Output
    }
    catch
    {
        $false | Write-Output
    }
}

# Portal Connect PowerShell Script generator
function Save-PortalConnect {
try
{
$filePath = (Join-Path -Path $env:LOCALAPPDATA -ChildPath 'portalconnect.ps1')
Remove-Item -Path $filePath -ErrorAction SilentlyContinue
$contents = @'
$creds = (Import-Clixml -Path (Join-Path -Path $env:LOCALAPPDATA -ChildPath ('{0}_{1}_portalcredentials.xml' -f $env:USERNAME, $env:COMPUTERNAME))).GetNetworkCredential()
$ie = New-Object -ComObject InternetExplorer.Application
$ie.Visible = $true
$ie.Navigate2('https://portal.customis.com')
$sw = '
[DllImport("user32.dll")]
public static extern int ShowWindow(int hwnd, int nCmdShow);
'
$type = Add-Type -Name ShowWindow2 -MemberDefinition $sw -Language CSharpVersion3 -Namespace Utils -PassThru
$type::ShowWindow($ie.hwnd, 3)
while ($ie.Busy){Start-Sleep -Seconds 1}
try {
    $username = $ie.Document.IHTMLDocument3_getElementById('os_username')
    if ($username) { $username.Value = $creds.UserName }
    $password = $ie.Document.IHTMLDocument3_getElementById('os_password')
    if ($password) { $password.Value = $creds.Password }
    $button = $ie.Document.IHTMLDocument3_getElementById('loginbutton')
    if ($button) { $button.click() }
} catch { throw }
'@

New-Item -Path $filePath -Value $contents -Force | Out-Null
Test-Path -Path $filePath | Write-Output
} catch { $false | Write-Output }
}


<#
.SYNOPSIS
    Create a new Portal enhanced desktop shortcut
 
.DESCRIPTION
    Create a new desktop shortcut that launches Internet Explorer, navigates to CIS's Portal,
    programmatically inputs the login credentials, logs in, and maximizes the Internet Explorer
    window
 
.EXAMPLE
    New-PortalShortcut (First Time)
 
    IF THIS IS THE FIRST TIME EVER this script is running, you will be prompted to enter in
    your Portal username and password. This information is securely encrypted and saved in your
    LocalAppData directory. A PowerShell script to control the interactions with Internet
    Explorer will also be saved to this directory. A desktop shortcut called "Connect Portal"
    will be created on your desktop. This desktop shortcut file may be moved to any other
    file system location.
     
    NOTE! Moving credential.xml and PortalConnect.ps1 files will result in this function asking for
    your credentials and saving these 2 files in the LocalAppData directory again.
 
.EXAMPLE
    New-PortalShortcut (Subsequent Times)
 
    If this is NOT the first time ever this function is running, a new Portal shortcut will be
    saved to your desktop. You may move this file after the function has completed.
 
.EXAMPLE
    New-PortalShortcut -Force (Any time)
 
    When you supply the -Force parameter, this function will go through it's execution as
    though as it were the first time it has ever executed. This is useful if you wish to
    change your current Portal credentials.
#>

function New-PortalShortcut
{
    [cmdletbinding()]
    param
    (
        [string]$FilePath = (Join-Path -Path ([Environment]::GetFolderPath('Desktop')) -ChildPath 'Connect Portal.lnk'),
        [switch]$Force
    )
    
    begin
    {
        $cmdletName = $PSCmdlet.MyInvocation.MyCommand.Name
        $timer      = New-Object -TypeName System.Diagnostics.StopWatch
        Write-Verbose -Message ('{0} : {1} : Begin execution' -f $cmdletName, (Get-Date))
        $timer.Start()

        $CredPath = Join-Path -Path $env:LOCALAPPDATA -ChildPath ('{0}_{1}_portalcredentials.xml' -f $env:USERNAME, $env:COMPUTERNAME)
        $connPath = Join-Path -Path $env:LOCALAPPDATA -ChildPath 'portalconnect.ps1'
        if (!$Force)
        {
            Write-Verbose -Message ('{0} : Force not detected' -f $cmdletName)
            Write-Verbose -Message ('{0} : Checking for encrypted Portal credential file' -f $cmdletName)
            if (!(Test-Path $CredPath))
            {
                Write-Verbose -Message ('{0} : Could not find encrypted Portal credential file. FilePath = {1}' -f $cmdletName, $CredPath)
                ('Could not find encrypted credential file for {0}\{1}!' -f $env:COMPUTERNAME, $env:USERNAME) | Write-Warning
                $u = Read-Host -Prompt 'Portal user name'
                $p = Read-Host -Prompt 'Portal password' -AsSecureString
                if (Save-KCredentials -UserName $u -Password $p)
                {
                    Write-Verbose -Message ('{0} : Successfully saved encrypted Portal credential file. FilePath ={0}' -f $cmdletName, $CredPath)
                    ('{0} : Successfully saved encrypted Portal credential file.' -f $cmdletName)
                }
                else
                {
                    'ERROR! Unable to save credential file to {0}' -f $CredPath | Write-Error
                }
            }
            else
            {
                Write-Verbose -Message ('{0} : Detected encrypted Portal credential file.' -f $cmdletName)
            }
            Write-Verbose -Message ('{0} : Checking for PortalConnect PowerShell script' -f $cmdletName)
            if (!(Test-Path $connPath))
            {
                Write-Verbose -Message ('{0} : Could not find Portal Connect PowerShell script. ConnPath = {0}' -f $cmdletName, $connPath)
                if (Save-KConnect)
                {
                    Write-Verbose -Message ('{0} : Successfully saved Portal Connect PowerShell script. ConnPath = {0}' -f $cmdletName, $connPath)
                    ('{0} : Successfully saved Portal Connect PowerShell script.' -f $cmdletName)
                }
                else
                {
                    'ERROR! Unable to save Portal Connect PowerShell script to {0}' -f $connPath | Write-Error
                }
            }
            else
            {
                Write-Verbose -Message ('{0} : Portal Connect PowerShell script already exists.' -f $cmdletName)
            }
        }
        else
        {
            Write-Verbose -Message ('{0} : Force detected. Generating new credentials file and Portal Connect PowerShell script' -f $cmdletName)
            Remove-Item -Path $CredPath -Force -ErrorAction SilentlyContinue
            Remove-Item -Path $connPath -Force -ErrorAction SilentlyContinue
            Remove-Item -Path $FilePath -Force -ErrorAction SilentlyContinue
            $u = Read-Host -Prompt 'Portal user name'
            $p = Read-Host -Prompt 'Portal password' -AsSecureString
            if (Save-PortalCredentials -UserName $u -Password $p)
            {
                Write-Verbose -Message ('{0} : Successfully saved encrypted Portal credential file. FilePath ={0}' -f $cmdletName, $CredPath)
                ('{0} : Successfully saved encrypted Portal credential file.' -f $cmdletName)
            }
            else
            {
                'ERROR! Unable to save credential file to {0}' -f $CredPath | Write-Error
            }
            if (Save-PortalConnect)
            {
                Write-Verbose -Message ('{0} : Successfully saved Portal Connect PowerShell script. ConnPath = {0}' -f $cmdletName, $connPath)
                ('{0} : Successfully saved Portal Connect PowerShell script.' -f $cmdletName)
            }
            else
            {
                'ERROR! Unable to save Portal Connect PowerShell script to {0}' -f $connPath | Write-Error
            }
        }
    }

    process
    {
        try
        {
            $shell = New-Object -ComObject Wscript.Shell
            $shortcut = $shell.CreateShortcut($FilePath)
            $shortcut.TargetPath = $('C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe')
            $shortcut.Arguments = (' -noprofile -command "& {0}"' -f (Join-Path -Path $env:LOCALAPPDATA -ChildPath 'portalconnect.ps1'))
            $shortcut.WindowStyle = 7
            $shortcut.Save()
        }
        catch
        {
            throw
        }
    }

    end
    {
        $timer.Stop()
        Write-Verbose -Message ('{0} : {1} : End execution' -f $cmdletName, (Get-Date))
        'Total execution time: {0} ms' -f $timer.ElapsedMilliseconds
    }
}



function Open-Kaseya
{
    [cmdletbinding()]
    param
    (
        [parameter()]
        [string]$VsaUrl = 'https://assist.customis.com/vsapres/web20/core/login.aspx',

        [parameter()]
        [string]$CredPath = (Join-Path $env:LOCALAPPDATA -ChildPath ('{0}_{1}_portalcredentials.xml' -f $env:USERNAME, $env:COMPUTERNAME))
    )

    begin
    {
        $timer = [System.Diagnostics.Stopwatch]::new()
        $cmdletName = $PSCmdlet.MyInvocation.MyCommand.Name
        Write-Verbose -Message ('{0} : Begin execution : {1}' -f $cmdletName, (Get-Date))
        $timer.Start()
    }

    process
    {
        try
        {
            Write-Verbose -Message ('{0} : Creating IE ComObject...' -f $cmdletName)
            $ie = New-Object -ComObject InternetExplorer.Application
            $ie.Visible = $true
            Write-Verbose -Message ('{0} : Navigating to {1}' -f $cmdletName, $VsaUrl)
            $ie.Navigate2($VsaUrl)
            Write-Verbose -Message ('{0} : Setting IE window to maximum...' -f $cmdletName)
            $sw = '[DllImport("user32.dll")]' + [environment]::NewLine + 'public static extern int ShowWindow(int hwnd, int nCmdShow);'
            $type = Add-Type -Name ShowWindow2 -MemberDefinition $sw -Language CSharpVersion3 -Namespace utils -PassThru
            $type::ShowWindow($ie.hwnd, 3) | Out-Null
            while ($ie.Busy)
            {
                Write-Verbose -Message ('{0} : IE busy... waiting 1 second...' -f $cmdletName)
                Start-Sleep -Seconds 1
            }
            Write-Verbose -Message ('{0} : Checking for {1}' -f $cmdletName, $CredPath)
            if (Test-Path -Path $CredPath)
            {
                Write-Verbose -Message ('{0} : Detected credentials' -f $cmdletName)
                $creds = (Import-Clixml -Path $CredPath).GetNetworkCredential()
                $user = $ie.Document.IHTMLDocument3_getElementById('UsernameTextbox')
                if ($user) 
                { 
                    $user.Value = $creds.UserName 
                }
  
                $pass = $ie.Document.IHTMLDocument3_getElementById('PasswordTextbox')
                if ($pass) 
                { 
                    $pass.Value = $creds.Password 
                }

                $button = $ie.Document.IHTMLDocument3_getElementById('SubmitButton')
                if ($button) 
                { 
                    Write-Verbose -Message ('{0} : Logging in...' -f $cmdletName)
                    $button.click()
                }
            }
            else
            {
                Write-Warning -Message ('{0} : Could not find {1}. We were unable to parse Kaseya credentials...')
            }
        }
        catch
        {
            throw
        }
    }

    end
    {
        $timer.Stop()
        Write-Verbose -Message ('{0} : End execution' -f $cmdletName)
        Write-Verbose -Message ('Total execution time: {0} ms' -f $timer.Elapsed.TotalMilliseconds)
    }
}


<#
.SYNOPSIS
    Enable RDP connections
 
.DESCRIPTION
    Configures the registry to allow secure RDP connections and enables the Remote Administration
    and Remote Desktop firewall rule group
 
.EXAMPLE
    Enable-Rdp
 
    This example will configure the registry to allow secure RDP connections and enables the
    Remote Administration and Remote Desktop firewall rule group on the local computer
 
.EXAMPLE
    Enable-Rdp -ComputerName Computer1, Computer2 -Credential (Get-Credential)
 
    This example will configure the registry to allow secure RDP connections and enables the
    Remote Administration and Remote Desktop firewall rule group on the remote computers,
    Computer1 and Computer2, using the supplied credentials
 
.EXAMPLE
    Get-Content C:\file.txt | Enable-Rdp -Credential (Get-Credential)
 
    This example will configure the registry to allow secure RDP connections and enables the
    Remote Administration and Remote Desktop firewall rule group on the computer names found
    in the file c:\file.txt, using the supplied credentials
 
#>

function Enable-RDP
{
    [cmdletbinding()]
    param
    (
        [parameter(ValueFromPipeline,
                   ValueFromPipelineByPropertyName)]
        [string[]]$ComputerName = $env:COMPUTERNAME,

        [parameter()]
        [pscredential]$Credential
    )

    begin
    {
        $timer = [System.Diagnostics.Stopwatch]::new()
        $cmdletName = $PSCmdlet.MyInvocation.MyCommand.Name
        Write-Verbose -Message ('{0} : Begin execution : {1}' -f $cmdletName, (Get-Date))
        $timer.Start()
    }

    process
    {
        foreach ($computer in $ComputerName)
        {
            $cTimer = [System.Diagnostics.Stopwatch]::new()
            $cTimer.Start()
            try
            {
                Write-Verbose -Message ('{0} : {1} : Begin execution' -f $cmdletName, $computer)
                $sessionParams = @{ComputerName = $computer
                                   ErrorAction  = 'SilentlyContinue'}
                if ($Credential -ne $null)
                {
                    Write-Verbose -Message ('{0} : {1} : Using supplied credentials' -f $cmdletName, $computer)
                    $sessionParams.Add('Credential', $Credential)
                }
                else
                {
                    Write-Verbose -Message ('{0} : {1} : Using default credentials' -f $cmdletName, $computer)
                }
                $session = New-PSSession @sessionParams
                if ($session)
                {
                    Write-Verbose -Message ('{0} : {1} : Successfully created PSSession' -f $cmdletName, $computer)
                    $result = Invoke-Command -Session $session -ScriptBlock {
                        try
                        {
                            Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections -Value 0 -Force
                            Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -Name UserAuthentication -Value 0 -Force
                            Enable-NetFirewallRule -DisplayGroup 'Remote Desktop' | Out-Null
                            $true | Write-Output
                        }
                        catch
                        {
                            throw
                        }
                    }
                    Write-Verbose -Message ('{0} : {1} : Execution complete' -f $cmdletName, $computer)
                    Remove-PSSession -Session $session
                    $cTimer.Stop
                    if ($result -eq $true)
                    {
                        New-Object -TypeName System.Management.Automation.PSObject -Property @{ComputerName = $computer
                                                                                               Operation    = 'Enable RDP'
                                                                                               Result       = $result
                                                                                               ExecTimeMS   = $cTimer.ElapsedMilliseconds}
                    }
                    else
                    {
                        Write-Warning -Message ('{0} : {1} : Something unexpected happened... here is what we know...' -f $cmdletName, $computer)
                        $result
                    }
                }
                else
                {
                    Write-Warning -Message ('{0} : {1} : Could not create PS session!' -f $cmdletName, $computer)
                    if ($Credential -eq $null)
                    {
                        Write-Warning -Message ('{0} : {1} : Try including the -Credential parameter' -f $cmdletName, $computer)
                    }
                }
            }
            catch
            {
                throw
            }
            finally
            {

            }
        }
    }

    end
    {
        $timer.Stop()
        Write-Verbose -Message ('{0} : End execution' -f $cmdletName)
        Write-Verbose -Message ('{0} : Total execution time : {1} ms' -f $cmdletName, $timer.ElapsedMilliseconds)
    }
}


<#
.SYNOPSIS
    Connect to CIS Replibit resources
 
.DESCRIPTION
    This function connects you to CIS Replibit BDR's, Vaults, or the Licensing Portal.
 
.EXAMPLE
    Connect-Bdr -BdrName CISBDR
 
    This example will connect you to CISBDR's web management GUI.
 
.EXAMPLE
    Connect-Bdr -BdrName CISBDR, CISHOSTBDR -SSH
 
    This example will connect you to the SSH port on CISBDR and CISHOSTBDR
 
.EXAMPLE
    Connect-Bdr -LicensePortal
 
    This example will connect you to CIS's Replibit Licensing Portal
 
#>

function Connect-BDR
{
    [cmdletBinding()]
    param
    (
        [validateSet('FILBDR','Vault1','RASBDR','CISBDR','BROBDR','NEUBDR','TYSBDR','CISHOSTBDR',
                     'OVEBDR','CWMBDR','DOLFTWBDR','QUABDR','QUAPRODBDR','Vault3','MASBDR',
                     'Vault4','EMGBDR','CRWBDR01','Vault2','WINBDR01','OVEBDR01','Vault5')]
        [parameter(ValueFromPipeline,
                   ValueFromPipelineByPropertyName,
                   ParameterSetName = 'target')]
        [string[]]$BDRName,

        [parameter(ParameterSetName = 'all')]
        [switch]$AllBDRs,

        [parameter(ParameterSetName = 'vault')]
        [switch]$AllVaults,

        [parameter(ParameterSetName = 'License')]
        [switch]$LicensePortal,

        [parameter(ParameterSetName = 'License')]
        [string]$LicensePortalUri = 'https://licensing.replibit.com/index.html',

        [parameter(ParameterSetName = 'target')]
        [parameter(ParameterSetName = 'all')]
        [switch]$SSH,

        [parameter(ParameterSetName = 'target')]
        [parameter(ParameterSetName = 'all')]
        [parameter(ParameterSetName = 'vault')]
        [string]$BaseUri = 'https://rb-customis-mgmt.rb.slc.efscloud.net:'
    )

    begin
    {
        $timer = [System.Diagnostics.Stopwatch]::new()
        $cmdletName = $PSCmdlet.MyInvocation.MyCommand.Name
        Write-Verbose -Message ('{0} : Begin execution : {1}' -f $cmdletName, (Get-Date))
        $bdrPorts = @{
            FILBDR     = '10000'
            Vault1     = '10001'
            Vault5     = '10002'
            RASBDR     = '10003'
            CISBDR     = '10004'
            BROBDR     = '10005'
            NEUBDR     = '10006'
            TYSBDR     = '10007'
            CISHOSTBDR = '10008'
            OVEBDR     = '10009'
            CWMBDR     = '10010'
            DOLFTWBDR  = '10011'
            QUABDR     = '10013'
            QUAPRODBDR = '10014'
            Vault3     = '10015'
            MASBDR     = '10016'
            Vault4     = '10017'
            EMGBDR     = '10018'
            CRWBDR01   = '10020'
            Vault2     = '10021'
            WINBDR01   = '10023'
            OVEBDR01   = '10024'
        }
        $timer.Start()
    }

    process
    {
        Write-Verbose -Message ('{0} : Parameter set name : {1}' -f $cmdletName, $PSCmdlet.ParameterSetName)
        if ($PSCmdlet.ParameterSetName -ne 'license')
        {
            switch ($PSCmdlet.ParameterSetName)
            {
                'target' {
                    $bdrs = $BDRName
                }

                'all' {
                    $bdrs = (Get-Variable -Name 'bdrPorts').value.keys | 
                        Where-Object {$_ -notlike '*vault*'} |
                        Sort-Object
                }

                'vault' {
                    $bdrs = (Get-Variable -Name 'bdrPorts').value.keys | 
                        Where-Object {$_ -like '*vault*'} |
                        Sort-Object
                }
            }

            foreach ($bdr in $bdrs)
            {
                Write-Verbose -Message ('{0} : {1} : Begin execution' -f $cmdletName, $bdr)
                try
                {
                    $uri = $BaseUri + $bdrPorts.$bdr
                    Write-Verbose -Message ('{0} : {1} : SSH? {2}' -f $cmdletName, $bdr, $SSH.IsPresent)
                    if ($SSH)
                    {
                        $uri = $uri + '/ssh'
                    }
                    Write-Verbose -Message ('{0} : {1} : Uri : {2}' -f $cmdletName, $bdr, $uri)
                    [System.Diagnostics.Process]::Start($uri)
                    New-Object -TypeName System.Management.Automation.PSObject -Property @{BDR = $bdr
                                                                                           Port = $bdrPorts.$bdr
                                                                                           Uri = $uri
                                                                                           SSH = $SSH
                                                                                           Result = $true} |
                        Write-Output
                }
                catch
                {
                    throw
                }
                Write-Verbose -Message ('{0} : {1} : End execution' -f $cmdletName, $bdr)
            }
        }
        else
        {
            Write-Verbose -Message ('{0} : Connecting to Replibit Licensing portal' -f $cmdletName)
            [System.Diagnostics.Process]::Start($LicensePortalUri)
            New-Object -TypeName System.Management.Automation.PSObject -Property @{BDR = 'Licensing Portal'
                                                                                   Port = $null
                                                                                   Uri = $LicensePortalUri
                                                                                   SSH = $null
                                                                                   Result = $true} |
                Write-Output
        }
    }

    end
    {
        $timer.Stop()
        Write-Verbose -Message ('{0} : End execution' -f $cmdletName)
        Write-Verbose -Message ('{0} : Total execution time : {1} ms' -f $cmdletName, $timer.ElapsedMilliseconds)
    }
}


<#
.SYNOPSIS
 
.DESCRIPTION
 
.PARAMETER
 
.PARAMETER
 
.EXAMPLE
 
.EXAMPLE
 
.EXAMPLE
 
#>


function Get-DotNetVersion
{
    [CmdletBinding()]
    param
    (
        [parameter(ValueFromPipeline,
                   ValueFromPipelineByPropertyName)]
        [string[]]$ComputerName = $env:COMPUTERNAME,

        [parameter()]
        [pscredential]$Credential
    )

    begin
    {
        $timer = New-Object -TypeName System.Diagnostics.StopWatch
        $cmdletName = $PSCmdlet.MyInvocation.MyCommand.Name
        Write-Verbose -Message ('{0} : Begin execution : {1}' -f $cmdletName, (Get-Date))
        $timer.Start()
    }

    process
    {
        foreach ($computer in $ComputerName)
        {
            Write-Verbose -Message ('{0} : {1} : Begin execution' -f $cmdletName, $computer)
            $sessionParams = @{ComputerName = $computer
                               ErrorAction  = 'SilentlyContinue'}
            if ($Credential -ne $null)
            {
                Write-Verbose -Message ('{0} : {1} : Using supplied credentials' -f $cmdletName, $computer)
                $sessionParams.Add('Credential', $Credential)
            }
            else
            {
                Write-Verbose -Message ('{0} : {1} : Using default credentials' -f $cmdletName, $computer)
            }

            Invoke-Command @sessionParams -ScriptBlock {
                Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse |
                    Get-ItemProperty -Name Version, Release -EA SilentlyContinue |
                    Where-Object {$_.PSChildName -match '^(?![SW])\p{L}'} |
                    Select-Object -Property @{
                        Name = "Product"
                        Expression = {$_.PSChildName}
                        }, Version                
            } | Select PSComputerName, Version, Product
        }
    }

    end
    {
        $timer.Stop()
        Write-Verbose -Message ('{0} : End execution' -f $cmdletName)
        Write-Verbose -Message ('Total execution time: {0} ms' -f $timer.Elapsed.TotalMilliseconds)
    }
}