Friday, 1 October 2021

Remove Box tools-per user install


$exitCode = 0
if (![System.Environment]::Is64BitProcess)
{
# start new PowerShell as x64 bit process, wait for it and gather exit code and standard error output
$sysNativePowerShell = "$($PSHOME.ToLower().Replace("syswow64", "sysnative"))\powershell.exe"
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = $sysNativePowerShell
$pinfo.Arguments = "-ex bypass -file `"$PSCommandPath`""
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.CreateNoWindow = $true
$pinfo.UseShellExecute = $false
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$exitCode = $p.ExitCode
$stderr = $p.StandardError.ReadToEnd()
if ($stderr) { Write-Error -Message $stderr }
}
else
{
# start logging to TEMP in file "scriptname".log
Start-Transcript -Path "$env:TEMP\$($(Split-Path $PSCommandPath -Leaf).ToLower().Replace(".ps1", ".log"))" | Out-Null
function Execute-AsLoggedOnUser($Command,$Hidden=$true) {
$csharpCode = @"
using System;
using System.Runtime.InteropServices;
namespace murrayju.ProcessExtensions
{
public static class ProcessExtensions
{
#region Win32 Constants
private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
private const int CREATE_NO_WINDOW = 0x08000000;
private const int CREATE_NEW_CONSOLE = 0x00000010;
private const uint INVALID_SESSION_ID = 0xFFFFFFFF;
private static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
#endregion
#region DllImports
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private static extern bool CreateProcessAsUser(
IntPtr hToken,
String lpApplicationName,
String lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandle,
uint dwCreationFlags,
IntPtr lpEnvironment,
String lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
private static extern bool DuplicateTokenEx(
IntPtr ExistingTokenHandle,
uint dwDesiredAccess,
IntPtr lpThreadAttributes,
int TokenType,
int ImpersonationLevel,
ref IntPtr DuplicateTokenHandle);
[DllImport("userenv.dll", SetLastError = true)]
private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
[DllImport("userenv.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hSnapshot);
[DllImport("kernel32.dll")]
private static extern uint WTSGetActiveConsoleSessionId();
[DllImport("Wtsapi32.dll")]
private static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);
[DllImport("wtsapi32.dll", SetLastError = true)]
private static extern int WTSEnumerateSessions(
IntPtr hServer,
int Reserved,
int Version,
ref IntPtr ppSessionInfo,
ref int pCount);
#endregion
#region Win32 Structs
private enum SW
{
SW_HIDE = 0,
SW_SHOWNORMAL = 1,
SW_NORMAL = 1,
SW_SHOWMINIMIZED = 2,
SW_SHOWMAXIMIZED = 3,
SW_MAXIMIZE = 3,
SW_SHOWNOACTIVATE = 4,
SW_SHOW = 5,
SW_MINIMIZE = 6,
SW_SHOWMINNOACTIVE = 7,
SW_SHOWNA = 8,
SW_RESTORE = 9,
SW_SHOWDEFAULT = 10,
SW_MAX = 10
}
private enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}
[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
private enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3,
}
[StructLayout(LayoutKind.Sequential)]
private struct STARTUPINFO
{
public int cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
private enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation = 2
}
[StructLayout(LayoutKind.Sequential)]
private struct WTS_SESSION_INFO
{
public readonly UInt32 SessionID;
[MarshalAs(UnmanagedType.LPStr)]
public readonly String pWinStationName;
public readonly WTS_CONNECTSTATE_CLASS State;
}
#endregion
// Gets the user token from the currently active session
private static bool GetSessionUserToken(ref IntPtr phUserToken)
{
var bResult = false;
var hImpersonationToken = IntPtr.Zero;
var activeSessionId = INVALID_SESSION_ID;
var pSessionInfo = IntPtr.Zero;
var sessionCount = 0;
// Get a handle to the user access token for the current active session.
if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref pSessionInfo, ref sessionCount) != 0)
{
var arrayElementSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
var current = pSessionInfo;
for (var i = 0; i < sessionCount; i++)
{
var si = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
current += arrayElementSize;
if (si.State == WTS_CONNECTSTATE_CLASS.WTSActive)
{
activeSessionId = si.SessionID;
}
}
}
// If enumerating did not work, fall back to the old method
if (activeSessionId == INVALID_SESSION_ID)
{
activeSessionId = WTSGetActiveConsoleSessionId();
}
if (WTSQueryUserToken(activeSessionId, ref hImpersonationToken) != 0)
{
// Convert the impersonation token to a primary token
bResult = DuplicateTokenEx(hImpersonationToken, 0, IntPtr.Zero,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, (int)TOKEN_TYPE.TokenPrimary,
ref phUserToken);
CloseHandle(hImpersonationToken);
}
return bResult;
}
public static bool StartProcessAsCurrentUser(string cmdLine, bool visible, string appPath = null, string workDir = null)
{
var hUserToken = IntPtr.Zero;
var startInfo = new STARTUPINFO();
var procInfo = new PROCESS_INFORMATION();
var pEnv = IntPtr.Zero;
int iResultOfCreateProcessAsUser;
startInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
try
{
if (!GetSessionUserToken(ref hUserToken))
{
throw new Exception("StartProcessAsCurrentUser: GetSessionUserToken failed.");
}
uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);
startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);
startInfo.lpDesktop = "winsta0\\default";
if (!CreateEnvironmentBlock(ref pEnv, hUserToken, false))
{
throw new Exception("StartProcessAsCurrentUser: CreateEnvironmentBlock failed.");
}
if (!CreateProcessAsUser(hUserToken,
appPath, // Application Name
cmdLine, // Command Line
IntPtr.Zero,
IntPtr.Zero,
false,
dwCreationFlags,
pEnv,
workDir, // Working directory
ref startInfo,
out procInfo))
{
throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed.\n");
}
iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
}
finally
{
CloseHandle(hUserToken);
if (pEnv != IntPtr.Zero)
{
DestroyEnvironmentBlock(pEnv);
}
CloseHandle(procInfo.hThread);
CloseHandle(procInfo.hProcess);
}
return true;
}
}
}
"@
# Compiling the source code as csharp
$compilerParams = [System.CodeDom.Compiler.CompilerParameters]::new()
$compilerParams.ReferencedAssemblies.AddRange(('System.Runtime.InteropServices.dll', 'System.dll'))
$compilerParams.CompilerOptions = '/unsafe'
$compilerParams.GenerateInMemory = $True
Add-Type -TypeDefinition $csharpCode -Language CSharp -CompilerParameters $compilerParams
# Adding powershell executeable to the command
$Command = '{0}\System32\WindowsPowerShell\v1.0\powershell.exe -executionPolicy bypass {1}' -f $($env:windir),$Command
# Adding double slashes to the command paths, as this is required.
$Command = $Command.Replace("\","\\")
# Execute a process as the currently logged on user.
# Absolute paths required if running as SYSTEM!
if($Hidden) { #running the command hidden
$runCommand = [murrayju.ProcessExtensions.ProcessExtensions]::StartProcessAsCurrentUser($Command,$false)
}else{ #running the command visible
$runCommand = [murrayju.ProcessExtensions.ProcessExtensions]::StartProcessAsCurrentUser($Command,$true)
}
if ($runCommand) {
return "Executed `"$Command`" as loggedon user"
} else {
throw "Something went wrong when executing process as currently logged-on user"
}
}
Function Get-InstalledSoftware {
Param(
[Alias('Computer','ComputerName','HostName')]
[Parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$true,Mandatory=$false,Position=1)]
[string[]]$Name = $env:COMPUTERNAME
)
Begin{
$lmKeys = "Software\Microsoft\Windows\CurrentVersion\Uninstall","SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
$lmReg = [Microsoft.Win32.RegistryHive]::LocalMachine
$cuKeys = "Software\Microsoft\Windows\CurrentVersion\Uninstall"
$cuReg = [Microsoft.Win32.RegistryHive]::CurrentUser
}
Process{
if (!(Test-Connection -ComputerName $Name -count 1 -quiet)) {
Write-Error -Message "Unable to contact $Name. Please verify its network connectivity and try again." -Category ObjectNotFound -TargetObject $Computer
Break
}
$masterKeys = @()
$remoteCURegKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($cuReg,$Name)
$remoteLMRegKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($lmReg,$Name)
foreach ($key in $lmKeys) {
$regKey = $remoteLMRegKey.OpenSubkey($key)
foreach ($subName in $regKey.GetSubkeyNames()) {
foreach($sub in $regKey.OpenSubkey($subName)) {
$masterKeys += (New-Object PSObject -Property @{
"ComputerName" = $Name
"Name" = $sub.GetValue("displayname")
"SystemComponent" = $sub.GetValue("systemcomponent")
"ParentKeyName" = $sub.GetValue("parentkeyname")
"Version" = $sub.GetValue("DisplayVersion")
"UninstallCommand" = $sub.GetValue("UninstallString")
"InstallDate" = $sub.GetValue("InstallDate")
"RegPath" = $sub.ToString()
})
}
}
}
foreach ($key in $cuKeys) {
$regKey = $remoteCURegKey.OpenSubkey($key)
if ($regKey -ne $null) {
foreach ($subName in $regKey.getsubkeynames()) {
foreach ($sub in $regKey.opensubkey($subName)) {
$masterKeys += (New-Object PSObject -Property @{
"ComputerName" = $Computer
"Name" = $sub.GetValue("displayname")
"SystemComponent" = $sub.GetValue("systemcomponent")
"ParentKeyName" = $sub.GetValue("parentkeyname")
"Version" = $sub.GetValue("DisplayVersion")
"UninstallCommand" = $sub.GetValue("UninstallString")
"InstallDate" = $sub.GetValue("InstallDate")
"RegPath" = $sub.ToString()
})
}
}
}
}
$woFilter = {$null -ne $_.name -AND $_.SystemComponent -ne "1" -AND $null -eq $_.ParentKeyName}
$props = 'Name','Version','ComputerName','Installdate','UninstallCommand','RegPath'
$masterKeys = ($masterKeys | Where-Object $woFilter | Select-Object $props | Sort-Object Name)
$masterKeys
}
End{}
}
$boxtoolsuninstallcommand = (Get-InstalledSoftware | where { $_.Name -match "Box Tools"}).UninstallCommand
If ($boxtoolsuninstallcommand -ne $null)
{
$boxtoolsuninstallcommand = $boxtoolsuninstallcommand.Trim()
$boxtoolsuninstallcommand = $boxtoolsuninstallcommand -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
$boxtoolsuninstallcommand = $boxtoolsuninstallcommand.Trim()
$boxtoolsuninstallcommand = "/X " + $boxtoolsuninstallcommand + " /quiet"
Write-Host $boxtoolsuninstallcommand
$uninstall = "-command & {Start-Process 'C:\Windows\system32\msiexec.exe' -ArgumentList '$boxtoolsuninstallcommand' -Wait}"
Execute-AsLoggedOnUser -Command $uninstall
Write-Host "Removed old box tools"
}
else {
Write-Host "Box tools was not previously installed"
}
$boxmsi = "https://e3.boxcdn.net/box-installers/boxedit/win/currentrelease/BoxToolsInstaller-AdminInstall.msi"
$outFile = "$env:TEMP\BoxToolsInstaller-AdminInstall.msi"
$msilog = "$env:TEMP\BoxToolsInstaller-AdminInstall.log"
(New-Object System.Net.WebClient).DownloadFile($boxmsi, $outFile)
Start-Sleep -Seconds 20
if (Test-Path $outFile)
{
Write-Host "Box tools installer Downloaded"
$arguments = @(
"/i"
"`"$outFile`""
"/qn"
"/l*v"
"`"$msilog`""
)
$boxinstall = Start-Process msiexec -ArgumentList $arguments -wait -PassThru
Write-Host "Installed box tools with exitcode $($boxinstall.Exitcode)"
Start-Sleep -Seconds 20
Remove-Item $outFile
Write-Host "Removed box installer."
}
else
{
Write-Host "box msi installer failed to download"
}
Stop-Transcript | Out-Null
}
exit $exitCode
view raw boxtools hosted with ❤ by GitHub

No comments:

Post a Comment

Detect autopilot session

  Ensuring that some apps only install during autopilot is not easily accomplished, you can use the below powershell script as a requiremen...