NTS.Tools.Application.psm1

function Start-C2RSetup {
    <#
        .Description
        this function can be used to install Microsoft 365 Apps
 
        .Parameter ConfigXMLPath
        defines the path to xml config file, cannot be used with UseDefaultConfigXML or UseSilentDefaultConfigXML
 
        .Parameter WorkingDir
        defines to folder where installation files should be saved
 
        .Parameter CleanUpInstallFiles
        if specified, the folder used in the parameter workdir will be deleted afterwards
 
        .Parameter UseDefaultConfigXML
        if specified, it will create config with "Outlook", "Word", "Excel", "Teams" and install those apps
 
        .Parameter UseSilentDefaultConfigXML
        same as parameter UseDefaultConfigXML, but silent
 
        .Parameter OfficeEdition
        define the office edition which should be installed with the default config
 
        .Example
        Install-M365Apps -UseDefaultConfigXML -OfficeEdition O365BusinessRetail -CleanUpInstallFiles
 
        .NOTES
        https://github.com/mallockey/Install-Office365Suite/blob/master/Install-Office365Suite.ps1
    #>


    [CmdletBinding(DefaultParameterSetName = 'XMLFile')]
    [Alias("Install-M365Apps", "Install-OfficeLTSC")]
    param(
        [Parameter(Mandatory = $true, ParameterSetName = "XMLFile")]
        [string]
        $ConfigXMLPath,

        [Parameter(Mandatory = $false)]
        [string]
        $WorkingDir = "$($env:ProgramData)\NTS\Office",

        [Parameter(Mandatory = $false)]
        [switch]
        $CleanUpInstallFiles,

        [Parameter(Mandatory = $false, ParameterSetName = "DefaultXML")]
        [switch]
        $UseDefaultConfigXML,

        [Parameter(Mandatory = $false, ParameterSetName = "SilentDefaultXML")]
        [switch]
        $UseSilentDefaultConfigXML,

        [Parameter(Mandatory = $false, ParameterSetName = "DefaultXML")]
        [Parameter(Mandatory = $false, ParameterSetName = "SilentDefaultXML")]
        [ValidateSet(
            "O365ProPlusRetail",
            "O365BusinessRetail",
            "ProPlus2021Volume",
            "ProPlus2019Volume"
        )]
        [string]
        $OfficeEdition
    )
    
    $ErrorActionPreference = "Stop"

    # check admin access
    $CurrentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
    if (!($CurrentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))) {
        Write-Warning "Script is not running as Administrator"
        Write-Warning "Please rerun this script as Administrator"
        exit
    }

    New-ItemIfNotExists -Path $WorkingDir -ItemType Directory
    if ($UseDefaultConfigXML) {
        Write-Output "creating xml config file for $($OfficeEdition)"
        New-C2RConfigXML -ConfigXMLPath $WorkingDir -ConfigXMLFileName "config.xml" -OfficeEdition $OfficeEdition -IncludeApps ("Outlook", "Word", "Excel", "Teams")
        $ConfigXMLPath = "$($WorkingDir)\config.xml"
    }
    elseif ($UseSilentDefaultConfigXML) {
        Write-Output "creating xml config file for $($OfficeEdition)"
        New-C2RConfigXML -ConfigXMLPath $WorkingDir -ConfigXMLFileName "config.xml" -OfficeEdition $OfficeEdition -IncludeApps ("Outlook", "Word", "Excel", "Teams") -DisplayLevel None
        $ConfigXMLPath = "$($WorkingDir)\config.xml"
    }

    # verify config xml
    Test-OfficeConfiguration -ConfigurationXMLFilePath $ConfigXMLPath

    # Get Setup.exe
    Get-C2RSetup -OutPath $WorkingDir -FileName "Setup.exe"

    # Run the setup
    [xml]$OfficeConfig = Get-Content -Path $ConfigXMLPath
    Write-Output "start installation of $($OfficeConfig.Configuration.Add.Product.ID)"
    $Process = Start-Process "$($WorkingDir)\Setup.exe" -ArgumentList "/configure `"$ConfigXMLPath`"" -Wait -PassThru -WindowStyle Hidden
    if ($Process.ExitCode -ne 0) {
        throw "there was an error installing office - $($PSItem.Exception.Message)"
    }

    #Check if suite was installed correctly

    $RegLocations = @(
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
        "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
    )
    $ItemsFound = ((Get-ChildItem -Path $RegLocations).Name -match "$($OfficeConfig.Configuration.Add.Product.ID)")[0].ToString().Replace("HKEY_LOCAL_MACHINE\", "")
    if ($null -ne $ItemsFound) {
        $OfficeVersionInstalled = (Get-ItemProperty -Path "HKLM:\$($ItemsFound)").Displayname
        Write-Output "$($OfficeVersionInstalled) was successfully installed"
    }
    else {
        Write-Warning "$($OfficeConfig.Configuration.Add.Product.ID) was not detected after the install ran"
    }

    if ($CleanUpInstallFiles) {
        Start-FolderCleanUp -FolderToRemove $WorkingDir
    }
}

function New-C2RConfigXML {
    <#
        .Description
        this function can be used generate a microsoft 365 apps config file
 
        .Parameter ConfigXMLPath
        defines the folder where the config file will be saved
 
        .Parameter ConfigXMLFileName
        name of the config file
 
        .Parameter OfficeEdition
        define the office edtion proplus or business for example
 
        .Parameter ExcludeApps
        apps that should not be installed
 
        .Parameter IncludeApps
        apps that should be installed
 
        .Parameter LanguageIDs
        languages that should be installed, defaults to matchos
 
        .Parameter DisplayLevel
        installation display level
 
        .Parameter OfficeArch
        architecture of the microsoft 365 suite
 
        .Parameter AcceptEULA
        should the eula be accepted or not
 
        .Parameter EnableUpdates
        enabled updates for the suite
 
        .Parameter Channel
        update channel
 
        .Parameter IncludeProject
        include project in the installation
 
        .Parameter IncludeVisio
        include visio in the installation
 
        .Parameter SharedComputerLicensing
        activate shared computer licensing
 
        .Parameter RemoveMSI
        unininstall msi version of office before starting the installation
 
        .Parameter SetFileFormat
        sets the default file format for word, excel, powerpoint
         
 
        .Example
        New-C2RConfigXML -ConfigXMLPath $WorkingDir -ConfigXMLFileName "config.xml" -IncludeApps "Outlook", "Word", "Excel", "Teams"
 
        .NOTES
        https://github.com/mallockey/Install-Office365Suite/blob/master/Install-Office365Suite.ps1
    #>


    [CmdletBinding(DefaultParameterSetName = 'ExcludeApps')]
    param(
        [Parameter(Mandatory = $false)]
        [string]
        $ConfigXMLPath = "$($env:ProgramData)\NTS\Office\",

        [Parameter(Mandatory = $false)]
        [string]
        $ConfigXMLFileName = "config.xml",

        [Parameter(Mandatory = $false)]
        [ValidateSet(
            "O365ProPlusRetail",
            "O365BusinessRetail",
            "ProPlus2021Volume",
            "ProPlus2019Volume"
        )]
        [string]
        $OfficeEdition = 'O365ProPlusRetail',

        [Parameter(Mandatory = $false, ParameterSetName = "ExcludeApps")]
        [ValidateSet(
            'Groove', 
            'Outlook', 
            'OneNote', 
            'Access', 
            'OneDrive', 
            'Publisher', 
            'Word', 
            'Excel', 
            'PowerPoint', 
            'Teams', 
            'Lync'
        )]
        [Array]
        $ExcludeApps,

        [Parameter(Mandatory = $false, ParameterSetName = "IncludeApps")]
        [ValidateSet(
            'Groove', 
            'Outlook', 
            'OneNote', 
            'Access', 
            'OneDrive', 
            'Publisher', 
            'Word', 
            'Excel', 
            'PowerPoint', 
            'Teams', 
            'Lync'
        )]
        [Array]
        $IncludeApps,

        [Parameter(Mandatory = $false)]
        [Array]
        $LanguageIDs,

        [Parameter(Mandatory = $false)]
        [ValidateSet("None", "Full")]
        [string]
        $DisplayLevel = "Full",

        [Parameter(Mandatory = $false)]
        [ValidateSet('64', '32')]
        [string]
        $OfficeArch = '64',

        [Parameter(Mandatory = $false)]
        [ValidateSet("TRUE", "FALSE")]
        [string]
        $AcceptEULA = "TRUE",

        [Parameter(Mandatory = $false)]
        [ValidateSet("TRUE", "FALSE")]
        [string]
        $EnableUpdates = "TRUE",

        [Parameter(Mandatory = $false)]
        [ValidateSet('SemiAnnualPreview', 'SemiAnnual', 'MonthlyEnterprise', 'CurrentPreview', 'Current')]
        [string]
        $Channel = 'Current',

        [Parameter(Mandatory = $false)]
        [Switch]
        $IncludeProject,

        [Parameter(Mandatory = $false)]
        [Switch]
        $IncludeVisio,

        [Parameter(Mandatory = $false)]
        [ValidateSet(0, 1)]
        [string]
        $SharedComputerLicensing = '0',

        [Parameter(Mandatory = $false)]
        [bool]
        $RemoveMSI = $true,

        [Parameter(Mandatory = $false)]
        [bool]
        $SetFileFormat = $true
    )

    $ErrorActionPreference = 'Stop'
    $ValidApps = (
        'Groove', 
        'Outlook', 
        'OneNote', 
        'Access', 
        'OneDrive', 
        'Publisher', 
        'Word', 
        'Excel', 
        'PowerPoint', 
        'Teams', 
        'Lync'
    )
  
    if ($ExcludeApps -and $IncludeApps) {
        throw "you can use 'ExcludeApps' or 'IncludeApps' not both"
    }
    elseif ($ExcludeApps) {
        $ExcludeApps | ForEach-Object {
            $ExcludeAppsString += "<ExcludeApp ID =`"$_`" />"
        }
    }
    elseif ($IncludeApps) {
        $ValidApps | Where-Object { $PSItem -notin $IncludeApps } | ForEach-Object {
            $ExcludeAppsString += "<ExcludeApp ID =`"$_`" />"
        }
    }
  
    if ($LanguageIDs) {
        $LanguageIDs | ForEach-Object {
            $LanguageString += "<Language ID =`"$_`" />"
        }
    }
    else {
        $LanguageString = "<Language ID=`"MatchOS`" />"
    }
  
    if ($OfficeArch) {
        $OfficeArchString = "`"$OfficeArch`""
    }
  
    if ($RemoveMSI) {
        $RemoveMSIString = '<RemoveMSI />'
    }
    else {
        $RemoveMSIString = $Null
    }
  
    if ($SetFileFormat) {
        $AppSettingsString = '<AppSettings>
        <User Key="software\microsoft\office\16.0\excel\options" Name="defaultformat" Value="51" Type="REG_DWORD" App="excel16" Id="L_SaveExcelfilesas" />
        <User Key="software\microsoft\office\16.0\powerpoint\options" Name="defaultformat" Value="27" Type="REG_DWORD" App="ppt16" Id="L_SavePowerPointfilesas" />
        <User Key="software\microsoft\office\16.0\word\options" Name="defaultformat" Value="" Type="REG_SZ" App="word16" Id="L_SaveWordfilesas" />
      </AppSettings>'

    }
    else {
        $AppSettingsString = $Null
    }
  
    if ($OfficeEdition -eq "ProPlus2021Volume") {
        $ChannelString = "Channel=`"PerpetualVL2021`""
    }
    elseif ($OfficeEdition -eq "ProPlus2019Volume") {
        $ChannelString = "Channel=`"PerpetualVL2019`""
    }
    elseif ($Channel) {
        $ChannelString = "Channel=`"$Channel`""
    }
    else {
        $ChannelString = $Null
    }
  
    if ($IncludeProject) {
        $ProjectString = "<Product ID=`"ProjectProRetail`"`>$ExcludeAppsString $LanguageString</Product>"
    }
    else {
        $ProjectString = $Null
    }
  
    if ($IncludeVisio) {
        $VisioString = "<Product ID=`"VisioProRetail`"`>$ExcludeAppsString $LanguageString</Product>"
    }
    else {
        $VisioString = $Null
    }
  
    $OfficeXML = [XML]@"
<Configuration>
    <Add OfficeClientEdition=$($OfficeArchString) $($ChannelString) $($SourcePathString) >
    <Product ID="$($OfficeEdition)">
        $($LanguageString)
        $($ExcludeAppsString)
    </Product>
    $($ProjectString)
    $($VisioString)
    </Add>
    <Property Name="SharedComputerLicensing" Value="$($SharedComputerlicensing)" />
    <Display Level="$($DisplayLevel)" AcceptEULA="$($AcceptEULA)" />
    <Updates Enabled="$($EnableUpdates)" />
    $($AppSettingsString)
    $($RemoveMSIString)
</Configuration>
"@

  
    try {
        New-ItemIfNotExists -Path $ConfigXMLPath -ItemType Directory
        Write-Output "XML Config file will be saved to $($ConfigXMLPath)\$($ConfigXMLFileName)"
        $OfficeXML.Save("$($ConfigXMLPath)\$($ConfigXMLFileName)")
    }
    catch {
        throw "could not create config xml at $($ConfigXMLPath) - $($PSItem.Exception.Message)"
    }
}

function Get-C2RSetup {
    <#
        .Description
        this function downloads office deployment tool kit and extract it, the setup.exe file be keept
 
        .Parameter OutPath
        folder pat where the setup file should be placed
 
        .Parameter FileName
        name of the setup.exe file
 
        .Parameter KeepODTFiles
        if specified, the folder containing the office deployment tool kit files will not be removed
 
        .Example
        Get-C2RSetup -OutPath $WorkingDir -FileName "Setup.exe"
 
        .NOTES
        https://github.com/mallockey/Install-Office365Suite/blob/master/Install-Office365Suite.ps1
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [string]
        $OutPath = "$($env:ProgramData)\NTS\Office\Setup",

        [Parameter(Mandatory = $false)]
        [string]
        $FileName = "setup.exe",

        [Parameter(Mandatory = $false)]
        [switch]
        $KeepODTFiles
    )

    $ODTFolder = "$($OutPath)\ODT"
    $ODTSetupFilePath = "$($ODTFolder)\ODTSetup.exe"

    # get odt
    try {
        New-ItemIfNotExists -Path $OutPath -ItemType Directory
        New-ItemIfNotExists -Path $ODTFolder -ItemType Directory
        if (Test-Path -Path $ODTSetupFilePath) {
            throw "$($ODTSetupFilePath) already exits"
        }
        else {
            try {                
                [String]$MSWebPage = Invoke-RestMethod "https://www.microsoft.com/en-us/download/confirmation.aspx?id=49117"
                $ODTDownloadURL = $MSWebPage | ForEach-Object {
                    if ($PSItem -match 'url=(https://.*officedeploymenttool.*\.exe)') {
                        $matches[1]
                    }
                }
            }
            catch {
                throw "could not find odt download url - $($PSItem.Exception.Message)"
            }

            Invoke-WebRequest -Uri $ODTDownloadURL -OutFile $ODTSetupFilePath
        }
    }
    catch {
        throw "could not download ODTSetup - $($PSItem.Exception.Message)"
    }

    # get setup
    try {
        Write-Output "extracting office deployment tool kit"
        Start-Process -FilePath $ODTSetupFilePath -ArgumentList "/quiet /extract:`"$($ODTFolder)`"" -Wait

        Write-Output "Copy Setup.exe to $($OutPath)"
        Copy-Item -Path "$($ODTFolder)\setup.exe" -Destination "$($OutPath)\$($FileName)" -Force

        if (!($KeepODTFiles)) {
            Start-FolderCleanUp -FolderToRemove $ODTFolder
        }
    }
    catch {
        Write-Warning "Error running the Office Deployment Tool - $($PSItem.Exception.Message)"
    }
}

function Test-OfficeConfiguration {
    <#
        .Description
        this function verifies a office config xml file against microsofts service
 
        .Parameter ConfigurationXMLFilePath
        path to the xml file
 
        .Example
        Test-OfficeConfiguration -ConfigurationXMLFilePath $ConfigXMLPath
 
        .NOTES
        https://github.com/mallockey/Install-Office365Suite/blob/master/Install-Office365Suite.ps1
    #>


    param(
        [Parameter(Mandatory = $true)]
        [String]
        $ConfigurationXMLFilePath
    )

    $ErrorActionPreference = 'Stop'
      
    try {
        $OfficeXML = Get-Content -Path $ConfigurationXMLFilePath
    }
    catch {
        throw "There was an error generating the XML config file"
    }

    try {
        Write-Output "Uploading XML config file to clients.config.office.net to verify syntax"
      
        Invoke-RestMethod -Uri 'https://clients.config.office.net/intents/v1.0/DeploymentSettings/ImportConfiguration' `
            -Method Post  `
            -Body $OfficeXML `
            -ContentType 'text/xml' | Out-Null
      
        Write-Output "XML config file was successfully verified"
    }
    catch {
        throw "The XML is not formatted correctly"
    }
}

function Get-Mimikatz {
    <#
        .Description
        this function downloads and expands the latest mimikart trunk from github
 
        .Parameter OutPath
        path where the files will be saved
 
        .Parameter DisableMSDefender
        sets exclusions for the path in $OutPath
 
        .Example
        Get-Mimikatz -DisableMSDefender
 
        .NOTES
        https://github.com/gentilkiwi/mimikatz/releases
    #>


    param (
        [Parameter(Mandatory = $false)]
        [string]
        $OutPath = "$($env:SystemDrive)\Temp\MimiKatz",

        [Parameter(Mandatory = $false)]
        [switch]
        $DisableMSDefender
    )

    $ErrorActionPreference = 'Stop'

    if ($DisableMSDefender) {
        Confirm-RunningAsAdministrator
        Write-Output "adding $($OutPath) to ms defender exclusions"
        Set-MpPreference -ExclusionPath $OutPath
    }

    $DownloadURL = "https://github.com/gentilkiwi/mimikatz/releases/latest/download/mimikatz_trunk.zip"
    $FileName = "mimikatz_trunk.zip"
    $FilePath = "$($OutPath)\$($FileName)"
    $ExpandFolderPath = "$($OutPath)\mimikatz_trunk"

    New-ItemIfNotExists -Path $OutPath -ItemType Directory
    Start-FileDownload -DownloadURL $DownloadURL -FileOutPath $FilePath
    Expand-Archive -Path $FilePath -DestinationPath $ExpandFolderPath

    Write-Output "Mimikatz was saved to $($ExpandFolderPath)"
}

function Install-GenericApplication {
    <#
        .Description
        this will download the install and runs it with the specified parameters
 
        .Parameter InstallType
        install for current user or all users
 
        .Parameter OutPath
        path where the files will be saved
 
        .Parameter FileName
        setup file name
 
        .Parameter CleanUpInstallFiles
        if specified, the folder used in the parameter workdir will be deleted afterwards
 
        .PARAMETER LogFileName
        name of the log file
 
        .PARAMETER LogFileFolderPath
        path of the folder where to put the log file
 
        .PARAMETER Terminal
        writes to Terminal instead of log file
 
        .Example
        $params = @{
            Name = "Bitwarden"
            InstallerURL = $InstallerURL
            OutPath = $OutPath
            FileName = $FileName
            CleanUpInstallFiles = $CleanUpInstallFiles
        }
        Install-GenericApplication @params -SetupParameter "/allusers /S"
 
        .NOTES
        https://silentinstallhq.com/bitwarden-silent-install-how-to-guide/
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]
        $Name,

        [Parameter(Mandatory = $true)]
        [string]
        $InstallerURL,

        [Parameter(Mandatory = $true)]
        [string]
        $SetupParameter,

        [Parameter(Mandatory = $false)]
        [string]
        $OutPath = "$($env:ProgramData)\NTS\Generic\Setup",

        [Parameter(Mandatory = $false)]
        [string]
        $FileName = "",

        [Parameter(Mandatory = $false)]
        [switch]
        $CleanUpInstallFiles,

        [Parameter(Mandatory = $false)]
        [string]
        $LogFileName,

        [Parameter(Mandatory = $false)]
        [string]
        $LogFileFolderPath,

        [Parameter(Mandatory = $false)]
        [bool]
        $Terminal
    )

    $ErrorActionPreference = 'Stop'
    $LogParam = Confirm-LogFileParameters -LogFileName $LogFileName -LogFileFolderPath $LogFileFolderPath -Terminal $Terminal

    if ($FileName -eq "") {
        $FileName = "$($Name).exe"
    }
    $SetupFilePath = "$($OutPath)\$($FileName)"
    
    try {
        # download
        try {
            Start-FileDownload -DownloadURL $InstallerURL -FileOutPath $SetupFilePath -MaxAgeOfFile (Get-Date).AddHours(-1)
        }
        catch {
            throw "error downloading - $($PSItem.Exception.Message)"
        }

        # install
        try {
            Write-ToLogOrTerminal @LogParam -Severity Info -Message "starting installation of $($Name)"
            Start-Process -FilePath $SetupFilePath -ArgumentList $SetupParameter -Wait
            if ($CleanUpInstallFiles) {
                Write-ToLogOrTerminal @LogParam -Severity Info -Message "removing folder $($OutPath)"
                Start-FolderCleanUp -FolderToRemove $OutPath
            }
            Write-ToLogOrTerminal @LogParam -Severity Info -Message "finished installing $($Name)"
        }
        catch {
            throw "error while installing - $($PSItem.Exception.Message)"
        }
    }
    catch {
        Write-ToLogOrTerminal @LogParam -Severity Error -Message $PSItem.Exception.Message
        throw $PSItem.Exception.Message
    }
}

function Install-BitwardenClient {
    <#
        .Description
        this function installs the bitwarden client
 
        .Parameter InstallType
        install for current user or all users
 
        .Parameter OutPath
        path where the files will be saved
 
        .Parameter FileName
        setup file name
 
        .Parameter CleanUpInstallFiles
        if specified, the folder used in the parameter workdir will be deleted afterwards
 
        .Example
        Install-BitwardenClient -InstallType AllUsers
 
        .NOTES
         
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [ValidateSet("AllUsers", "CurrentUser")]
        [string]
        $InstallType = "CurrentUser",

        [Parameter(Mandatory = $false)]
        [string]
        $OutPath = "$($env:ProgramData)\NTS\Bitwarden\Setup",

        [Parameter(Mandatory = $false)]
        [string]
        $FileName = "bitwarden-installer.exe",

        [Parameter(Mandatory = $false)]
        [switch]
        $CleanUpInstallFiles
    )
    
    # static vars
    $ErrorActionPreference = 'Stop'
    $InstallerURL = "https://vault.bitwarden.com/download/?app=desktop&platform=windows"

    # install
    try {
        $params = @{
            Name                = "Bitwarden"
            InstallerURL        = $InstallerURL
            OutPath             = $OutPath 
            FileName            = $FileName 
            CleanUpInstallFiles = $CleanUpInstallFiles
        }

        if ($InstallType -eq "AllUsers") {
            Confirm-RunningAsAdministrator
            Install-GenericApplication @params -SetupParameter "/allusers /S"
        }
        elseif ($InstallType -eq "CurrentUser") {
            Install-GenericApplication @params -SetupParameter "/S"
        }
    }
    catch {
        throw "error installing - $($PSItem.Exception.Message)"
    }
}

function Install-VSCode {
    <#
        .Description
        this function install vs code
 
        .Parameter InstallType
        install for current user or all users
 
        .Parameter OutPath
        path where the files will be saved
 
        .Parameter FileName
        setup file name
 
        .Parameter CleanUpInstallFiles
        if specified, the folder used in the parameter workdir will be deleted afterwards
 
        .Example
        Install-VSCode -InstallType AllUsers
 
        .NOTES
         
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [ValidateSet("AllUsers", "CurrentUser")]
        [string]
        $InstallType = "CurrentUser",

        [Parameter(Mandatory = $false)]
        [string]
        $OutPath = "$($env:ProgramData)\NTS\VSCode\Setup",

        [Parameter(Mandatory = $false)]
        [string]
        $FileName = "vscode-$($InstallType).exe",

        [Parameter(Mandatory = $false)]
        [switch]
        $CleanUpInstallFiles
    )
    
    # static vars
    $ErrorActionPreference = 'Stop'

    # install
    try {
        $params = @{
            Name                = "VSCode"
            SetupParameter      = "/VERYSILENT /NORESTART /MERGETASKS=!runcode"
            OutPath             = $OutPath 
            FileName            = $FileName
            CleanUpInstallFiles = $CleanUpInstallFiles
        }

        if ($InstallType -eq "AllUsers") {
            Confirm-RunningAsAdministrator
            Install-GenericApplication @params -InstallerURL "https://code.visualstudio.com/sha/download?build=stable&os=win32-x64"
        }
        elseif ($InstallType -eq "CurrentUser") {
            Install-GenericApplication @params -InstallerURL "https://code.visualstudio.com/sha/download?build=stable&os=win32-x64-user"
        }
    }
    catch {
        throw "error installing - $($PSItem.Exception.Message)"
    }
}