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 .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 = "" ) $ErrorActionPreference = 'Stop' $LogParam = Confirm-LogFileParameters -LogFileName $LogFileName -LogFileFolderPath $LogFileFolderPath 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-ToLogOrConsole @LogParam -Severity Info -Message "starting installation of $($Name)" Start-Process -FilePath $SetupFilePath -ArgumentList $SetupParameter -Wait if ($CleanUpInstallFiles) { Write-ToLogOrConsole @LogParam -Severity Info -Message "removing folder $($OutPath)" Start-FolderCleanUp -FolderToRemove $OutPath } Write-ToLogOrConsole @LogParam -Severity Info -Message "finished installing $($Name)" } catch { throw "error while installing - $($PSItem.Exception.Message)" } } catch { Write-ToLogOrConsole @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)" } } |