diff --git a/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitBanner.png b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitBanner.png
new file mode 100644
index 0000000..60c2ed1
Binary files /dev/null and b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitBanner.png differ
diff --git a/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitConfig.xml b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitConfig.xml
new file mode 100644
index 0000000..67fe1f1
Binary files /dev/null and b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitConfig.xml differ
diff --git a/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitExtensions.ps1 b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitExtensions.ps1
new file mode 100644
index 0000000..08fd4ed
--- /dev/null
+++ b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitExtensions.ps1
@@ -0,0 +1,57 @@
+<#
+.SYNOPSIS
+ This script is a template that allows you to extend the toolkit with your own custom functions.
+ # LICENSE #
+ PowerShell App Deployment Toolkit - Provides a set of functions to perform common application deployment tasks on Windows.
+ Copyright (C) 2017 - Sean Lillis, Dan Cunningham, Muhammad Mashwani, Aman Motazedian.
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see .
+.DESCRIPTION
+ The script is automatically dot-sourced by the AppDeployToolkitMain.ps1 script.
+.NOTES
+ Toolkit Exit Code Ranges:
+ 60000 - 68999: Reserved for built-in exit codes in Deploy-Application.ps1, Deploy-Application.exe, and AppDeployToolkitMain.ps1
+ 69000 - 69999: Recommended for user customized exit codes in Deploy-Application.ps1
+ 70000 - 79999: Recommended for user customized exit codes in AppDeployToolkitExtensions.ps1
+.LINK
+ http://psappdeploytoolkit.com
+#>
+[CmdletBinding()]
+Param (
+)
+
+##*===============================================
+##* VARIABLE DECLARATION
+##*===============================================
+
+# Variables: Script
+[string]$appDeployToolkitExtName = 'PSAppDeployToolkitExt'
+[string]$appDeployExtScriptFriendlyName = 'App Deploy Toolkit Extensions'
+[version]$appDeployExtScriptVersion = [version]'1.5.0'
+[string]$appDeployExtScriptDate = '02/12/2017'
+[hashtable]$appDeployExtScriptParameters = $PSBoundParameters
+
+##*===============================================
+##* FUNCTION LISTINGS
+##*===============================================
+
+#
+
+##*===============================================
+##* END FUNCTION LISTINGS
+##*===============================================
+
+##*===============================================
+##* SCRIPT BODY
+##*===============================================
+
+If ($scriptParentPath) {
+ Write-Log -Message "Script [$($MyInvocation.MyCommand.Definition)] dot-source invoked by [$(((Get-Variable -Name MyInvocation).Value).ScriptName)]" -Source $appDeployToolkitExtName
+}
+Else {
+ Write-Log -Message "Script [$($MyInvocation.MyCommand.Definition)] invoked directly" -Source $appDeployToolkitExtName
+}
+
+##*===============================================
+##* END SCRIPT BODY
+##*===============================================
\ No newline at end of file
diff --git a/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitHelp.ps1 b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitHelp.ps1
new file mode 100644
index 0000000..83c6e4a
--- /dev/null
+++ b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitHelp.ps1
@@ -0,0 +1,132 @@
+<#
+.SYNOPSIS
+ Displays a graphical console to browse the help for the App Deployment Toolkit functions
+ # LICENSE #
+ PowerShell App Deployment Toolkit - Provides a set of functions to perform common application deployment tasks on Windows.
+ Copyright (C) 2017 - Sean Lillis, Dan Cunningham, Muhammad Mashwani, Aman Motazedian.
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see .
+.DESCRIPTION
+ Displays a graphical console to browse the help for the App Deployment Toolkit functions
+.EXAMPLE
+ AppDeployToolkitHelp.ps1
+.NOTES
+.LINK
+ http://psappdeploytoolkit.com
+#>
+
+##*===============================================
+##* VARIABLE DECLARATION
+##*===============================================
+
+## Variables: Script
+[string]$appDeployToolkitHelpName = 'PSAppDeployToolkitHelp'
+[string]$appDeployHelpScriptFriendlyName = 'App Deploy Toolkit Help'
+[version]$appDeployHelpScriptVersion = [version]'3.6.5'
+[string]$appDeployHelpScriptDate = '02/12/2017'
+
+## Variables: Environment
+[string]$scriptDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
+# Dot source the App Deploy Toolkit Functions
+. "$scriptDirectory\AppDeployToolkitMain.ps1" -DisableLogging
+
+##*===============================================
+##* END VARIABLE DECLARATION
+##*===============================================
+
+##*===============================================
+##* FUNCTION LISTINGS
+##*===============================================
+
+Function Show-HelpConsole {
+ ## Import the Assemblies
+ Add-Type -AssemblyName 'System.Windows.Forms' -ErrorAction 'Stop'
+ Add-Type -AssemblyName System.Drawing -ErrorAction 'Stop'
+
+ ## Form Objects
+ $HelpForm = New-Object -TypeName 'System.Windows.Forms.Form'
+ $HelpListBox = New-Object -TypeName 'System.Windows.Forms.ListBox'
+ $HelpTextBox = New-Object -TypeName 'System.Windows.Forms.RichTextBox'
+ $InitialFormWindowState = New-Object -TypeName 'System.Windows.Forms.FormWindowState'
+
+ ## Form Code
+ $System_Drawing_Size = New-Object -TypeName 'System.Drawing.Size'
+ $System_Drawing_Size.Height = 665
+ $System_Drawing_Size.Width = 957
+ $HelpForm.ClientSize = $System_Drawing_Size
+ $HelpForm.DataBindings.DefaultDataSourceUpdateMode = 0
+ $HelpForm.Name = 'HelpForm'
+ $HelpForm.Text = 'PowerShell App Deployment Toolkit Help Console'
+ $HelpForm.WindowState = 'Normal'
+ $HelpForm.ShowInTaskbar = $true
+ $HelpForm.FormBorderStyle = 'Fixed3D'
+ $HelpForm.MaximizeBox = $false
+ $HelpForm.Icon = New-Object -TypeName 'System.Drawing.Icon' -ArgumentList $AppDeployLogoIcon
+ $HelpListBox.Anchor = 7
+ $HelpListBox.BorderStyle = 1
+ $HelpListBox.DataBindings.DefaultDataSourceUpdateMode = 0
+ $HelpListBox.Font = New-Object -TypeName 'System.Drawing.Font' -ArgumentList ('Microsoft Sans Serif', 9.75, 1, 3, 1)
+ $HelpListBox.FormattingEnabled = $true
+ $HelpListBox.ItemHeight = 16
+ $System_Drawing_Point = New-Object -TypeName 'System.Drawing.Point'
+ $System_Drawing_Point.X = 0
+ $System_Drawing_Point.Y = 0
+ $HelpListBox.Location = $System_Drawing_Point
+ $HelpListBox.Name = 'HelpListBox'
+ $System_Drawing_Size = New-Object -TypeName 'System.Drawing.Size'
+ $System_Drawing_Size.Height = 658
+ $System_Drawing_Size.Width = 271
+ $HelpListBox.Size = $System_Drawing_Size
+ $HelpListBox.Sorted = $true
+ $HelpListBox.TabIndex = 2
+ $HelpListBox.add_SelectedIndexChanged({ $HelpTextBox.Text = Get-Help -Name $HelpListBox.SelectedItem -Full | Out-String })
+ $helpFunctions = Get-Command -CommandType 'Function' | Where-Object { ($_.HelpUri -match 'psappdeploytoolkit') -and ($_.Definition -notmatch 'internal script function') } | Select-Object -ExpandProperty Name
+ ForEach ($helpFunction in $helpFunctions) {
+ $null = $HelpListBox.Items.Add($helpFunction)
+ }
+ $HelpForm.Controls.Add($HelpListBox)
+ $HelpTextBox.Anchor = 11
+ $HelpTextBox.BorderStyle = 1
+ $HelpTextBox.DataBindings.DefaultDataSourceUpdateMode = 0
+ $HelpTextBox.Font = New-Object -TypeName 'System.Drawing.Font' -ArgumentList ('Microsoft Sans Serif', 8.5, 0, 3, 1)
+ $HelpTextBox.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0)
+ $System_Drawing_Point = New-Object -TypeName System.Drawing.Point
+ $System_Drawing_Point.X = 277
+ $System_Drawing_Point.Y = 0
+ $HelpTextBox.Location = $System_Drawing_Point
+ $HelpTextBox.Name = 'HelpTextBox'
+ $HelpTextBox.ReadOnly = $True
+ $System_Drawing_Size = New-Object -TypeName 'System.Drawing.Size'
+ $System_Drawing_Size.Height = 658
+ $System_Drawing_Size.Width = 680
+ $HelpTextBox.Size = $System_Drawing_Size
+ $HelpTextBox.TabIndex = 1
+ $HelpTextBox.Text = ''
+ $HelpForm.Controls.Add($HelpTextBox)
+
+ ## Save the initial state of the form
+ $InitialFormWindowState = $HelpForm.WindowState
+ ## Init the OnLoad event to correct the initial state of the form
+ $HelpForm.add_Load($OnLoadForm_StateCorrection)
+ ## Show the Form
+ $null = $HelpForm.ShowDialog()
+}
+
+##*===============================================
+##* END FUNCTION LISTINGS
+##*===============================================
+
+##*===============================================
+##* SCRIPT BODY
+##*===============================================
+
+Write-Log -Message "Load [$appDeployHelpScriptFriendlyName] console..." -Source $appDeployToolkitHelpName
+
+## Show the help console
+Show-HelpConsole
+
+Write-Log -Message "[$appDeployHelpScriptFriendlyName] console closed." -Source $appDeployToolkitHelpName
+
+##*===============================================
+##* END SCRIPT BODY
+##*===============================================
\ No newline at end of file
diff --git a/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitLogo.ico b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitLogo.ico
new file mode 100644
index 0000000..411f4ab
Binary files /dev/null and b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitLogo.ico differ
diff --git a/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitMain.cs b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitMain.cs
new file mode 100644
index 0000000..b1653b0
--- /dev/null
+++ b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitMain.cs
@@ -0,0 +1,775 @@
+// Date Modified: 01-08-2016
+// Version Number: 3.6.8
+
+using System;
+using System.Text;
+using System.Collections;
+using System.ComponentModel;
+using System.DirectoryServices;
+using System.Security.Principal;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
+using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
+
+namespace PSADT
+{
+ public class Msi
+ {
+ enum LoadLibraryFlags : int
+ {
+ DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
+ LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
+ LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
+ LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
+ LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
+ LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
+ }
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, LoadLibraryFlags dwFlags);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ static extern int LoadString(IntPtr hInstance, int uID, StringBuilder lpBuffer, int nBufferMax);
+
+ // Get MSI exit code message from msimsg.dll resource dll
+ public static string GetMessageFromMsiExitCode(int errCode)
+ {
+ IntPtr hModuleInstance = LoadLibraryEx("msimsg.dll", IntPtr.Zero, LoadLibraryFlags.LOAD_LIBRARY_AS_DATAFILE);
+
+ StringBuilder sb = new StringBuilder(255);
+ LoadString(hModuleInstance, errCode, sb, sb.Capacity + 1);
+
+ return sb.ToString();
+ }
+ }
+
+ public class Explorer
+ {
+ private static readonly IntPtr HWND_BROADCAST = new IntPtr(0xffff);
+ private const int WM_SETTINGCHANGE = 0x1a;
+ private const int SMTO_ABORTIFHUNG = 0x0002;
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ static extern bool SendNotifyMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ private static extern IntPtr SendMessageTimeout(IntPtr hWnd, int Msg, IntPtr wParam, string lParam, int fuFlags, int uTimeout, IntPtr lpdwResult);
+
+ [DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
+
+ public static void RefreshDesktopAndEnvironmentVariables()
+ {
+ // Update desktop icons
+ SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);
+ SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero, null, SMTO_ABORTIFHUNG, 100, IntPtr.Zero);
+ // Update environment variables
+ SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero, "Environment", SMTO_ABORTIFHUNG, 100, IntPtr.Zero);
+ }
+ }
+
+ public sealed class FileVerb
+ {
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern int LoadString(IntPtr h, int id, StringBuilder sb, int maxBuffer);
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern IntPtr LoadLibrary(string s);
+
+ public static string GetPinVerb(int VerbId)
+ {
+ IntPtr hShell32 = LoadLibrary("shell32.dll");
+ const int nChars = 255;
+ StringBuilder Buff = new StringBuilder("", nChars);
+
+ LoadString(hShell32, VerbId, Buff, Buff.Capacity);
+ return Buff.ToString();
+ }
+ }
+
+ public sealed class IniFile
+ {
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern int GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, int nSize, string lpFileName);
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool WritePrivateProfileString(string lpAppName, string lpKeyName, StringBuilder lpString, string lpFileName);
+
+ public static string GetIniValue(string section, string key, string filepath)
+ {
+ string sDefault = "";
+ const int nChars = 1024;
+ StringBuilder Buff = new StringBuilder(nChars);
+
+ GetPrivateProfileString(section, key, sDefault, Buff, Buff.Capacity, filepath);
+ return Buff.ToString();
+ }
+
+ public static void SetIniValue(string section, string key, StringBuilder value, string filepath)
+ {
+ WritePrivateProfileString(section, key, value, filepath);
+ }
+ }
+
+ public class UiAutomation
+ {
+ public enum GetWindow_Cmd : int
+ {
+ GW_HWNDFIRST = 0,
+ GW_HWNDLAST = 1,
+ GW_HWNDNEXT = 2,
+ GW_HWNDPREV = 3,
+ GW_OWNER = 4,
+ GW_CHILD = 5,
+ GW_ENABLEDPOPUP = 6
+ }
+
+ public enum ShowWindowEnum
+ {
+ Hide = 0,
+ ShowNormal = 1,
+ ShowMinimized = 2,
+ ShowMaximized = 3,
+ Maximize = 3,
+ ShowNormalNoActivate = 4,
+ Show = 5,
+ Minimize = 6,
+ ShowMinNoActivate = 7,
+ ShowNoActivate = 8,
+ Restore = 9,
+ ShowDefault = 10,
+ ForceMinimized = 11
+ }
+
+ public enum UserNotificationState
+ {
+ // http://msdn.microsoft.com/en-us/library/bb762533(v=vs.85).aspx
+ ScreenSaverOrLockedOrFastUserSwitching =1, // A screen saver is displayed, the machine is locked, or a nonactive Fast User Switching session is in progress.
+ FullScreenOrPresentationModeOrLoginScreen =2, // A full-screen application is running or Presentation Settings are applied. Presentation Settings allow a user to put their machine into a state fit for an uninterrupted presentation, such as a set of PowerPoint slides, with a single click. Also returns this state if machine is at the login screen.
+ RunningDirect3DFullScreen =3, // A full-screen, exclusive mode, Direct3D application is running.
+ PresentationMode =4, // The user has activated Windows presentation settings to block notifications and pop-up messages.
+ AcceptsNotifications =5, // None of the other states are found, notifications can be freely sent.
+ QuietTime =6, // Introduced in Windows 7. The current user is in "quiet time", which is the first hour after a new user logs into his or her account for the first time.
+ WindowsStoreAppRunning =7 // Introduced in Windows 8. A Windows Store app is running.
+ }
+
+ // Only for Vista or above
+ [DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ static extern int SHQueryUserNotificationState(out UserNotificationState pquns);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool EnumWindows(EnumWindowsProcD lpEnumFunc, ref IntPtr lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ private static extern IntPtr GetDesktopWindow();
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ private static extern IntPtr GetShellWindow();
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsWindowEnabled(IntPtr hWnd);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool IsIconic(IntPtr hWnd);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool ShowWindow(IntPtr hWnd, ShowWindowEnum flags);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern IntPtr SetActiveWindow(IntPtr hwnd);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetForegroundWindow(IntPtr hWnd);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern IntPtr GetForegroundWindow();
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern IntPtr SetFocus(IntPtr hWnd);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern bool BringWindowToTop(IntPtr hWnd);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern int GetCurrentThreadId();
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern bool AttachThreadInput(int idAttach, int idAttachTo, bool fAttach);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLong", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
+
+ [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
+
+ public delegate bool EnumWindowsProcD(IntPtr hWnd, ref IntPtr lItems);
+
+ public static bool EnumWindowsProc(IntPtr hWnd, ref IntPtr lItems)
+ {
+ if (hWnd != IntPtr.Zero)
+ {
+ GCHandle hItems = GCHandle.FromIntPtr(lItems);
+ List items = hItems.Target as List;
+ items.Add(hWnd);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public static List EnumWindows()
+ {
+ try
+ {
+ List items = new List();
+ EnumWindowsProcD CallBackPtr = new EnumWindowsProcD(EnumWindowsProc);
+ GCHandle hItems = GCHandle.Alloc(items);
+ IntPtr lItems = GCHandle.ToIntPtr(hItems);
+ EnumWindows(CallBackPtr, ref lItems);
+ return items;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("An error occured during window enumeration: " + ex.Message);
+ }
+ }
+
+ public static string GetWindowText(IntPtr hWnd)
+ {
+ int iTextLength = GetWindowTextLength(hWnd);
+ if (iTextLength > 0)
+ {
+ StringBuilder sb = new StringBuilder(iTextLength);
+ GetWindowText(hWnd, sb, iTextLength + 1);
+ return sb.ToString();
+ }
+ else
+ {
+ return String.Empty;
+ }
+ }
+
+ public static bool BringWindowToFront(IntPtr windowHandle)
+ {
+ bool breturn = false;
+ if (IsIconic(windowHandle))
+ {
+ // Show minimized window because SetForegroundWindow does not work for minimized windows
+ ShowWindow(windowHandle, ShowWindowEnum.ShowMaximized);
+ }
+
+ int lpdwProcessId;
+ int windowThreadProcessId = GetWindowThreadProcessId(GetForegroundWindow(), out lpdwProcessId);
+ int currentThreadId = GetCurrentThreadId();
+ AttachThreadInput(windowThreadProcessId, currentThreadId, true);
+
+ BringWindowToTop(windowHandle);
+ breturn = SetForegroundWindow(windowHandle);
+ SetActiveWindow(windowHandle);
+ SetFocus(windowHandle);
+
+ AttachThreadInput(windowThreadProcessId, currentThreadId, false);
+ return breturn;
+ }
+
+ public static int GetWindowThreadProcessId(IntPtr windowHandle)
+ {
+ int processID = 0;
+ GetWindowThreadProcessId(windowHandle, out processID);
+ return processID;
+ }
+
+ public static IntPtr GetWindowLong(IntPtr hWnd, int nIndex)
+ {
+ if (IntPtr.Size == 4)
+ {
+ return GetWindowLong32(hWnd, nIndex);
+ }
+ return GetWindowLongPtr64(hWnd, nIndex);
+ }
+
+ public static string GetUserNotificationState()
+ {
+ // Only works for Windows Vista or higher
+ UserNotificationState state;
+ int returnVal = SHQueryUserNotificationState(out state);
+ return state.ToString();
+ }
+ }
+
+ public class QueryUser
+ {
+ [DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern IntPtr WTSOpenServer(string pServerName);
+
+ [DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern void WTSCloseServer(IntPtr hServer);
+
+ [DllImport("wtsapi32.dll", CharSet = CharSet.Ansi, SetLastError = false)]
+ public static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr pBuffer, out int pBytesReturned);
+
+ [DllImport("wtsapi32.dll", CharSet = CharSet.Ansi, SetLastError = false)]
+ public static extern int WTSEnumerateSessions(IntPtr hServer, int Reserved, int Version, out IntPtr pSessionInfo, out int pCount);
+
+ [DllImport("wtsapi32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern void WTSFreeMemory(IntPtr pMemory);
+
+ [DllImport("winsta.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern int WinStationQueryInformation(IntPtr hServer, int sessionId, int information, ref WINSTATIONINFORMATIONW pBuffer, int bufferLength, ref int returnedLength);
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern int GetCurrentProcessId();
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = false)]
+ public static extern bool ProcessIdToSessionId(int processId, ref int pSessionId);
+
+ public class TerminalSessionData
+ {
+ public int SessionId;
+ public string ConnectionState;
+ public string SessionName;
+ public bool IsUserSession;
+ public TerminalSessionData(int sessionId, string connState, string sessionName, bool isUserSession)
+ {
+ SessionId = sessionId;
+ ConnectionState = connState;
+ SessionName = sessionName;
+ IsUserSession = isUserSession;
+ }
+ }
+
+ public class TerminalSessionInfo
+ {
+ public string NTAccount;
+ public string SID;
+ public string UserName;
+ public string DomainName;
+ public int SessionId;
+ public string SessionName;
+ public string ConnectState;
+ public bool IsCurrentSession;
+ public bool IsConsoleSession;
+ public bool IsActiveUserSession;
+ public bool IsUserSession;
+ public bool IsRdpSession;
+ public bool IsLocalAdmin;
+ public DateTime? LogonTime;
+ public TimeSpan? IdleTime;
+ public DateTime? DisconnectTime;
+ public string ClientName;
+ public string ClientProtocolType;
+ public string ClientDirectory;
+ public int ClientBuildNumber;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct WTS_SESSION_INFO
+ {
+ public Int32 SessionId;
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string SessionName;
+ public WTS_CONNECTSTATE_CLASS State;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct WINSTATIONINFORMATIONW
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 70)]
+ private byte[] Reserved1;
+ public int SessionId;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ private byte[] Reserved2;
+ public FILETIME ConnectTime;
+ public FILETIME DisconnectTime;
+ public FILETIME LastInputTime;
+ public FILETIME LoginTime;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1096)]
+ private byte[] Reserved3;
+ public FILETIME CurrentTime;
+ }
+
+ public enum WINSTATIONINFOCLASS
+ {
+ WinStationInformation = 8
+ }
+
+ public enum WTS_CONNECTSTATE_CLASS
+ {
+ Active,
+ Connected,
+ ConnectQuery,
+ Shadow,
+ Disconnected,
+ Idle,
+ Listen,
+ Reset,
+ Down,
+ Init
+ }
+
+ public enum WTS_INFO_CLASS
+ {
+ SessionId=4,
+ UserName,
+ SessionName,
+ DomainName,
+ ConnectState,
+ ClientBuildNumber,
+ ClientName,
+ ClientDirectory,
+ ClientProtocolType=16
+ }
+
+ private static IntPtr OpenServer(string Name)
+ {
+ IntPtr server = WTSOpenServer(Name);
+ return server;
+ }
+
+ private static void CloseServer(IntPtr ServerHandle)
+ {
+ WTSCloseServer(ServerHandle);
+ }
+
+ private static IList PtrToStructureList(IntPtr ppList, int count) where T : struct
+ {
+ List result = new List();
+ long pointer = ppList.ToInt64();
+ int sizeOf = Marshal.SizeOf(typeof(T));
+
+ for (int index = 0; index < count; index++)
+ {
+ T item = (T) Marshal.PtrToStructure(new IntPtr(pointer), typeof(T));
+ result.Add(item);
+ pointer += sizeOf;
+ }
+ return result;
+ }
+
+ public static DateTime? FileTimeToDateTime(FILETIME ft)
+ {
+ if (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0)
+ {
+ return null;
+ }
+ long hFT = (((long) ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
+ return DateTime.FromFileTime(hFT);
+ }
+
+ public static WINSTATIONINFORMATIONW GetWinStationInformation(IntPtr server, int sessionId)
+ {
+ int retLen = 0;
+ WINSTATIONINFORMATIONW wsInfo = new WINSTATIONINFORMATIONW();
+ WinStationQueryInformation(server, sessionId, (int) WINSTATIONINFOCLASS.WinStationInformation, ref wsInfo, Marshal.SizeOf(typeof(WINSTATIONINFORMATIONW)), ref retLen);
+ return wsInfo;
+ }
+
+ public static TerminalSessionData[] ListSessions(string ServerName)
+ {
+ IntPtr server = IntPtr.Zero;
+ if (ServerName == "localhost" || ServerName == String.Empty)
+ {
+ ServerName = Environment.MachineName;
+ }
+
+ List results = new List();
+
+ try
+ {
+ server = OpenServer(ServerName);
+ IntPtr ppSessionInfo = IntPtr.Zero;
+ int count;
+ bool _isUserSession = false;
+ IList sessionsInfo;
+
+ if (WTSEnumerateSessions(server, 0, 1, out ppSessionInfo, out count) == 0)
+ {
+ throw new Win32Exception();
+ }
+
+ try
+ {
+ sessionsInfo = PtrToStructureList(ppSessionInfo, count);
+ }
+ finally
+ {
+ WTSFreeMemory(ppSessionInfo);
+ }
+
+ foreach (WTS_SESSION_INFO sessionInfo in sessionsInfo)
+ {
+ if (sessionInfo.SessionName != "Services" && sessionInfo.SessionName != "RDP-Tcp")
+ {
+ _isUserSession = true;
+ }
+ results.Add(new TerminalSessionData(sessionInfo.SessionId, sessionInfo.State.ToString(), sessionInfo.SessionName, _isUserSession));
+ _isUserSession = false;
+ }
+ }
+ finally
+ {
+ CloseServer(server);
+ }
+
+ TerminalSessionData[] returnData = results.ToArray();
+ return returnData;
+ }
+
+ public static TerminalSessionInfo GetSessionInfo(string ServerName, int SessionId)
+ {
+ IntPtr server = IntPtr.Zero;
+ IntPtr buffer = IntPtr.Zero;
+ int bytesReturned;
+ TerminalSessionInfo data = new TerminalSessionInfo();
+ bool _IsCurrentSessionId = false;
+ bool _IsConsoleSession = false;
+ bool _IsUserSession = false;
+ int currentSessionID = 0;
+ string _NTAccount = String.Empty;
+ if (ServerName == "localhost" || ServerName == String.Empty)
+ {
+ ServerName = Environment.MachineName;
+ }
+ if (ProcessIdToSessionId(GetCurrentProcessId(), ref currentSessionID) == false)
+ {
+ currentSessionID = -1;
+ }
+
+ // Get all members of the local administrators group
+ bool _IsLocalAdminCheckSuccess = false;
+ List localAdminGroupSidsList = new List();
+ try
+ {
+ DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + ServerName + ",Computer");
+ string localAdminGroupName = new SecurityIdentifier("S-1-5-32-544").Translate(typeof(NTAccount)).Value.Split('\\')[1];
+ DirectoryEntry admGroup = localMachine.Children.Find(localAdminGroupName, "group");
+ object members = admGroup.Invoke("members", null);
+ foreach (object groupMember in (IEnumerable)members)
+ {
+ DirectoryEntry member = new DirectoryEntry(groupMember);
+ if (member.Name != String.Empty)
+ {
+ localAdminGroupSidsList.Add((new NTAccount(member.Name)).Translate(typeof(SecurityIdentifier)).Value);
+ }
+ }
+ _IsLocalAdminCheckSuccess = true;
+ }
+ catch { }
+
+ try
+ {
+ server = OpenServer(ServerName);
+
+ if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.ClientBuildNumber, out buffer, out bytesReturned) == false)
+ {
+ return data;
+ }
+ int lData = Marshal.ReadInt32(buffer);
+ data.ClientBuildNumber = lData;
+
+ if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.ClientDirectory, out buffer, out bytesReturned) == false)
+ {
+ return data;
+ }
+ string strData = Marshal.PtrToStringAnsi(buffer);
+ data.ClientDirectory = strData;
+
+ if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.ClientName, out buffer, out bytesReturned) == false)
+ {
+ return data;
+ }
+ strData = Marshal.PtrToStringAnsi(buffer);
+ data.ClientName = strData;
+
+ if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.ClientProtocolType, out buffer, out bytesReturned) == false)
+ {
+ return data;
+ }
+ Int16 intData = Marshal.ReadInt16(buffer);
+ if (intData == 2)
+ {
+ strData = "RDP";
+ data.IsRdpSession = true;
+ }
+ else
+ {
+ strData = "";
+ data.IsRdpSession = false;
+ }
+ data.ClientProtocolType = strData;
+
+ if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.ConnectState, out buffer, out bytesReturned) == false)
+ {
+ return data;
+ }
+ lData = Marshal.ReadInt32(buffer);
+ data.ConnectState = ((WTS_CONNECTSTATE_CLASS) lData).ToString();
+
+ if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.SessionId, out buffer, out bytesReturned) == false)
+ {
+ return data;
+ }
+ lData = Marshal.ReadInt32(buffer);
+ data.SessionId = lData;
+
+ if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.DomainName, out buffer, out bytesReturned) == false)
+ {
+ return data;
+ }
+ strData = Marshal.PtrToStringAnsi(buffer).ToUpper();
+ data.DomainName = strData;
+ if (strData != String.Empty)
+ {
+ _NTAccount = strData;
+ }
+
+ if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.UserName, out buffer, out bytesReturned) == false)
+ {
+ return data;
+ }
+ strData = Marshal.PtrToStringAnsi(buffer);
+ data.UserName = strData;
+ if (strData != String.Empty)
+ {
+ data.NTAccount = _NTAccount + "\\" + strData;
+ string _Sid = (new NTAccount(_NTAccount + "\\" + strData)).Translate(typeof(SecurityIdentifier)).Value;
+ data.SID = _Sid;
+ if (_IsLocalAdminCheckSuccess == true)
+ {
+ foreach (string localAdminGroupSid in localAdminGroupSidsList)
+ {
+ if (localAdminGroupSid == _Sid)
+ {
+ data.IsLocalAdmin = true;
+ break;
+ }
+ else
+ {
+ data.IsLocalAdmin = false;
+ }
+ }
+ }
+ }
+
+ if (WTSQuerySessionInformation(server, SessionId, WTS_INFO_CLASS.SessionName, out buffer, out bytesReturned) == false)
+ {
+ return data;
+ }
+ strData = Marshal.PtrToStringAnsi(buffer);
+ data.SessionName = strData;
+ if (strData != "Services" && strData != "RDP-Tcp" && data.UserName != String.Empty)
+ {
+ _IsUserSession = true;
+ }
+ data.IsUserSession = _IsUserSession;
+ if (strData == "Console")
+ {
+ _IsConsoleSession = true;
+ }
+ data.IsConsoleSession = _IsConsoleSession;
+
+ WINSTATIONINFORMATIONW wsInfo = GetWinStationInformation(server, SessionId);
+ DateTime? _loginTime = FileTimeToDateTime(wsInfo.LoginTime);
+ DateTime? _lastInputTime = FileTimeToDateTime(wsInfo.LastInputTime);
+ DateTime? _disconnectTime = FileTimeToDateTime(wsInfo.DisconnectTime);
+ DateTime? _currentTime = FileTimeToDateTime(wsInfo.CurrentTime);
+ TimeSpan? _idleTime = (_currentTime != null && _lastInputTime != null) ? _currentTime.Value - _lastInputTime.Value : TimeSpan.Zero;
+ data.LogonTime = _loginTime;
+ data.IdleTime = _idleTime;
+ data.DisconnectTime = _disconnectTime;
+
+ if (currentSessionID == SessionId)
+ {
+ _IsCurrentSessionId = true;
+ }
+ data.IsCurrentSession = _IsCurrentSessionId;
+ }
+ finally
+ {
+ WTSFreeMemory(buffer);
+ buffer = IntPtr.Zero;
+ CloseServer(server);
+ }
+ return data;
+ }
+
+ public static TerminalSessionInfo[] GetUserSessionInfo(string ServerName)
+ {
+ if (ServerName == "localhost" || ServerName == String.Empty)
+ {
+ ServerName = Environment.MachineName;
+ }
+
+ // Find and get detailed information for all user sessions
+ // Also determine the active user session. If a console user exists, then that will be the active user session.
+ // If no console user exists but users are logged in, such as on terminal servers, then select the first logged-in non-console user that is either 'Active' or 'Connected' as the active user.
+ TerminalSessionData[] sessions = ListSessions(ServerName);
+ TerminalSessionInfo sessionInfo = new TerminalSessionInfo();
+ List userSessionsInfo = new List();
+ string firstActiveUserNTAccount = String.Empty;
+ bool IsActiveUserSessionSet = false;
+ foreach (TerminalSessionData session in sessions)
+ {
+ if (session.IsUserSession == true)
+ {
+ sessionInfo = GetSessionInfo(ServerName, session.SessionId);
+ if (sessionInfo.IsUserSession == true)
+ {
+ if ((firstActiveUserNTAccount == String.Empty) && (sessionInfo.ConnectState == "Active" || sessionInfo.ConnectState == "Connected"))
+ {
+ firstActiveUserNTAccount = sessionInfo.NTAccount;
+ }
+
+ if (sessionInfo.IsConsoleSession == true)
+ {
+ sessionInfo.IsActiveUserSession = true;
+ IsActiveUserSessionSet = true;
+ }
+ else
+ {
+ sessionInfo.IsActiveUserSession = false;
+ }
+
+ userSessionsInfo.Add(sessionInfo);
+ }
+ }
+ }
+
+ TerminalSessionInfo[] userSessions = userSessionsInfo.ToArray();
+ if (IsActiveUserSessionSet == false)
+ {
+ foreach (TerminalSessionInfo userSession in userSessions)
+ {
+ if (userSession.NTAccount == firstActiveUserNTAccount)
+ {
+ userSession.IsActiveUserSession = true;
+ break;
+ }
+ }
+ }
+
+ return userSessions;
+ }
+ }
+}
diff --git a/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitMain.ps1 b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitMain.ps1
new file mode 100644
index 0000000..9687117
--- /dev/null
+++ b/CFX Maestro/1.1/PS_Deployment/AppDeployToolkit/AppDeployToolkitMain.ps1
@@ -0,0 +1,10830 @@
+<#
+.SYNOPSIS
+ This script contains the functions and logic engine for the Deploy-Application.ps1 script.
+ # LICENSE #
+ PowerShell App Deployment Toolkit - Provides a set of functions to perform common application deployment tasks on Windows.
+ Copyright (C) 2017 - Sean Lillis, Dan Cunningham, Muhammad Mashwani, Aman Motazedian.
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ You should have received a copy of the GNU Lesser General Public License along with this program. If not, see .
+.DESCRIPTION
+ The script can be called directly to dot-source the toolkit functions for testing, but it is usually called by the Deploy-Application.ps1 script.
+ The script can usually be updated to the latest version without impacting your per-application Deploy-Application scripts.
+ Please check release notes before upgrading.
+.PARAMETER CleanupBlockedApps
+ Clean up the blocked applications.
+ This parameter is passed to the script when it is called externally, e.g. from a scheduled task or asynchronously.
+.PARAMETER ShowBlockedAppDialog
+ Display a dialog box showing that the application execution is blocked.
+ This parameter is passed to the script when it is called externally, e.g. from a scheduled task or asynchronously.
+.PARAMETER ReferredInstallName
+ Name of the referring application that invoked the script externally.
+ This parameter is passed to the script when it is called externally, e.g. from a scheduled task or asynchronously.
+.PARAMETER ReferredInstallTitle
+ Title of the referring application that invoked the script externally.
+ This parameter is passed to the script when it is called externally, e.g. from a scheduled task or asynchronously.
+.PARAMETER ReferredLogname
+ Logfile name of the referring application that invoked the script externally.
+ This parameter is passed to the script when it is called externally, e.g. from a scheduled task or asynchronously.
+.PARAMETER AsyncToolkitLaunch
+ This parameter is passed to the script when it is being called externally, e.g. from a scheduled task or asynchronously.
+.NOTES
+ The other parameters specified for this script that are not documented in this help section are for use only by functions in this script that call themselves by running this script again asynchronously.
+.LINK
+ http://psappdeploytoolkit.com
+#>
+[CmdletBinding()]
+Param (
+ ## Script Parameters: These parameters are passed to the script when it is called externally from a scheduled task or because of an Image File Execution Options registry setting
+ [switch]$ShowInstallationPrompt = $false,
+ [switch]$ShowInstallationRestartPrompt = $false,
+ [switch]$CleanupBlockedApps = $false,
+ [switch]$ShowBlockedAppDialog = $false,
+ [switch]$DisableLogging = $false,
+ [string]$ReferredInstallName = '',
+ [string]$ReferredInstallTitle = '',
+ [string]$ReferredLogName = '',
+ [string]$Message = '',
+ [string]$MessageAlignment = '',
+ [string]$ButtonRightText = '',
+ [string]$ButtonLeftText = '',
+ [string]$ButtonMiddleText = '',
+ [string]$Icon = '',
+ [string]$Timeout = '',
+ [switch]$ExitOnTimeout = $false,
+ [boolean]$MinimizeWindows = $false,
+ [switch]$PersistPrompt = $false,
+ [int32]$CountdownSeconds,
+ [int32]$CountdownNoHideSeconds,
+ [switch]$NoCountdown = $false,
+ [switch]$AsyncToolkitLaunch = $false
+)
+
+##*=============================================
+##* VARIABLE DECLARATION
+##*=============================================
+#region VariableDeclaration
+
+## Variables: Toolkit Name
+[string]$appDeployToolkitName = 'PSAppDeployToolkit'
+[string]$appDeployMainScriptFriendlyName = 'App Deploy Toolkit Main'
+
+## Variables: Script Info
+[version]$appDeployMainScriptVersion = [version]'3.7.0'
+[version]$appDeployMainScriptMinimumConfigVersion = [version]'3.6.9'
+[string]$appDeployMainScriptDate = '02/13/2018'
+[hashtable]$appDeployMainScriptParameters = $PSBoundParameters
+
+## Variables: Datetime and Culture
+[datetime]$currentDateTime = Get-Date
+[string]$currentTime = Get-Date -Date $currentDateTime -UFormat '%T'
+[string]$currentDate = Get-Date -Date $currentDateTime -UFormat '%d-%m-%Y'
+[timespan]$currentTimeZoneBias = [timezone]::CurrentTimeZone.GetUtcOffset([datetime]::Now)
+[Globalization.CultureInfo]$culture = Get-Culture
+[string]$currentLanguage = $culture.TwoLetterISOLanguageName.ToUpper()
+[Globalization.CultureInfo]$uiculture = Get-UICulture
+[string]$currentUILanguage = $uiculture.TwoLetterISOLanguageName.ToUpper()
+
+## Variables: Environment Variables
+[psobject]$envHost = $Host
+[psobject]$envShellFolders = Get-ItemProperty -Path 'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders' -ErrorAction 'SilentlyContinue'
+[string]$envAllUsersProfile = $env:ALLUSERSPROFILE
+[string]$envAppData = [Environment]::GetFolderPath('ApplicationData')
+[string]$envArchitecture = $env:PROCESSOR_ARCHITECTURE
+[string]$envCommonProgramFiles = [Environment]::GetFolderPath('CommonProgramFiles')
+[string]$envCommonProgramFilesX86 = ${env:CommonProgramFiles(x86)}
+[string]$envCommonDesktop = $envShellFolders | Select-Object -ExpandProperty 'Common Desktop' -ErrorAction 'SilentlyContinue'
+[string]$envCommonDocuments = $envShellFolders | Select-Object -ExpandProperty 'Common Documents' -ErrorAction 'SilentlyContinue'
+[string]$envCommonStartMenuPrograms = $envShellFolders | Select-Object -ExpandProperty 'Common Programs' -ErrorAction 'SilentlyContinue'
+[string]$envCommonStartMenu = $envShellFolders | Select-Object -ExpandProperty 'Common Start Menu' -ErrorAction 'SilentlyContinue'
+[string]$envCommonStartUp = $envShellFolders | Select-Object -ExpandProperty 'Common Startup' -ErrorAction 'SilentlyContinue'
+[string]$envCommonTemplates = $envShellFolders | Select-Object -ExpandProperty 'Common Templates' -ErrorAction 'SilentlyContinue'
+[string]$envComputerName = [Environment]::MachineName.ToUpper()
+[string]$envComputerNameFQDN = ([Net.Dns]::GetHostEntry('localhost')).HostName
+[string]$envHomeDrive = $env:HOMEDRIVE
+[string]$envHomePath = $env:HOMEPATH
+[string]$envHomeShare = $env:HOMESHARE
+[string]$envLocalAppData = [Environment]::GetFolderPath('LocalApplicationData')
+[string[]]$envLogicalDrives = [Environment]::GetLogicalDrives()
+[string]$envProgramFiles = [Environment]::GetFolderPath('ProgramFiles')
+[string]$envProgramFilesX86 = ${env:ProgramFiles(x86)}
+[string]$envProgramData = [Environment]::GetFolderPath('CommonApplicationData')
+[string]$envPublic = $env:PUBLIC
+[string]$envSystemDrive = $env:SYSTEMDRIVE
+[string]$envSystemRoot = $env:SYSTEMROOT
+[string]$envTemp = [IO.Path]::GetTempPath()
+[string]$envUserCookies = [Environment]::GetFolderPath('Cookies')
+[string]$envUserDesktop = [Environment]::GetFolderPath('DesktopDirectory')
+[string]$envUserFavorites = [Environment]::GetFolderPath('Favorites')
+[string]$envUserInternetCache = [Environment]::GetFolderPath('InternetCache')
+[string]$envUserInternetHistory = [Environment]::GetFolderPath('History')
+[string]$envUserMyDocuments = [Environment]::GetFolderPath('MyDocuments')
+[string]$envUserName = [Environment]::UserName
+[string]$envUserPictures = [Environment]::GetFolderPath('MyPictures')
+[string]$envUserProfile = $env:USERPROFILE
+[string]$envUserSendTo = [Environment]::GetFolderPath('SendTo')
+[string]$envUserStartMenu = [Environment]::GetFolderPath('StartMenu')
+[string]$envUserStartMenuPrograms = [Environment]::GetFolderPath('Programs')
+[string]$envUserStartUp = [Environment]::GetFolderPath('StartUp')
+[string]$envUserTemplates = [Environment]::GetFolderPath('Templates')
+[string]$envSystem32Directory = [Environment]::SystemDirectory
+[string]$envWinDir = $env:WINDIR
+# Handle X86 environment variables so they are never empty
+If (-not $envCommonProgramFilesX86) { [string]$envCommonProgramFilesX86 = $envCommonProgramFiles }
+If (-not $envProgramFilesX86) { [string]$envProgramFilesX86 = $envProgramFiles }
+
+## Variables: Domain Membership
+[boolean]$IsMachinePartOfDomain = (Get-WmiObject -Class 'Win32_ComputerSystem' -ErrorAction 'SilentlyContinue').PartOfDomain
+[string]$envMachineWorkgroup = ''
+[string]$envMachineADDomain = ''
+[string]$envLogonServer = ''
+[string]$MachineDomainController = ''
+If ($IsMachinePartOfDomain) {
+ [string]$envMachineADDomain = (Get-WmiObject -Class 'Win32_ComputerSystem' -ErrorAction 'SilentlyContinue').Domain | Where-Object { $_ } | ForEach-Object { $_.ToLower() }
+ Try {
+ [string]$envLogonServer = $env:LOGONSERVER | Where-Object { (($_) -and (-not $_.Contains('\\MicrosoftAccount'))) } | ForEach-Object { $_.TrimStart('\') } | ForEach-Object { ([Net.Dns]::GetHostEntry($_)).HostName }
+ # If running in system context, fall back on the logonserver value stored in the registry
+ If (-not $envLogonServer) { [string]$envLogonServer = Get-ItemProperty -LiteralPath 'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\History' -ErrorAction 'SilentlyContinue' | Select-Object -ExpandProperty 'DCName' -ErrorAction 'SilentlyContinue' }
+ [string]$MachineDomainController = [DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().FindDomainController().Name
+ }
+ Catch { }
+}
+Else {
+ [string]$envMachineWorkgroup = (Get-WmiObject -Class 'Win32_ComputerSystem' -ErrorAction 'SilentlyContinue').Domain | Where-Object { $_ } | ForEach-Object { $_.ToUpper() }
+}
+[string]$envMachineDNSDomain = [Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties().DomainName | Where-Object { $_ } | ForEach-Object { $_.ToLower() }
+[string]$envUserDNSDomain = $env:USERDNSDOMAIN | Where-Object { $_ } | ForEach-Object { $_.ToLower() }
+Try {
+ [string]$envUserDomain = [Environment]::UserDomainName.ToUpper()
+}
+Catch { }
+
+## Variables: Operating System
+[psobject]$envOS = Get-WmiObject -Class 'Win32_OperatingSystem' -ErrorAction 'SilentlyContinue'
+[string]$envOSName = $envOS.Caption.Trim()
+[string]$envOSServicePack = $envOS.CSDVersion
+[version]$envOSVersion = $envOS.Version
+[string]$envOSVersionMajor = $envOSVersion.Major
+[string]$envOSVersionMinor = $envOSVersion.Minor
+[string]$envOSVersionBuild = $envOSVersion.Build
+If ($envOSVersionMajor -eq 10) {$envOSVersionRevision = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name 'UBR' -ErrorAction SilentlyContinue).UBR}
+Else { [string]$envOSVersionRevision = ,((Get-ItemProperty -Path 'HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name 'BuildLabEx' -ErrorAction 'SilentlyContinue').BuildLabEx -split '\.') | ForEach-Object { $_[1] } }
+If ($envOSVersionRevision -notmatch '^[\d\.]+$') { $envOSVersionRevision = '' }
+If ($envOSVersionRevision) { [string]$envOSVersion = "$($envOSVersion.ToString()).$envOSVersionRevision" } Else { "$($envOSVersion.ToString())" }
+# Get the operating system type
+[int32]$envOSProductType = $envOS.ProductType
+[boolean]$IsServerOS = [boolean]($envOSProductType -eq 3)
+[boolean]$IsDomainControllerOS = [boolean]($envOSProductType -eq 2)
+[boolean]$IsWorkStationOS = [boolean]($envOSProductType -eq 1)
+Switch ($envOSProductType) {
+ 3 { [string]$envOSProductTypeName = 'Server' }
+ 2 { [string]$envOSProductTypeName = 'Domain Controller' }
+ 1 { [string]$envOSProductTypeName = 'Workstation' }
+ Default { [string]$envOSProductTypeName = 'Unknown' }
+}
+# Get the OS Architecture
+[boolean]$Is64Bit = [boolean]((Get-WmiObject -Class 'Win32_Processor' -ErrorAction 'SilentlyContinue' | Where-Object { $_.DeviceID -eq 'CPU0' } | Select-Object -ExpandProperty 'AddressWidth') -eq 64)
+If ($Is64Bit) { [string]$envOSArchitecture = '64-bit' } Else { [string]$envOSArchitecture = '32-bit' }
+
+## Variables: Current Process Architecture
+[boolean]$Is64BitProcess = [boolean]([IntPtr]::Size -eq 8)
+If ($Is64BitProcess) { [string]$psArchitecture = 'x64' } Else { [string]$psArchitecture = 'x86' }
+
+## Variables: Hardware
+[int32]$envSystemRAM = Get-WMIObject -Class Win32_PhysicalMemory -ComputerName $env:COMPUTERNAME -ErrorAction 'SilentlyContinue' | Measure-Object -Property Capacity -Sum -ErrorAction SilentlyContinue | % {[Math]::Round(($_.sum / 1GB),2)}
+
+## Variables: PowerShell And CLR (.NET) Versions
+[hashtable]$envPSVersionTable = $PSVersionTable
+# PowerShell Version
+[version]$envPSVersion = $envPSVersionTable.PSVersion
+[string]$envPSVersionMajor = $envPSVersion.Major
+[string]$envPSVersionMinor = $envPSVersion.Minor
+[string]$envPSVersionBuild = $envPSVersion.Build
+[string]$envPSVersionRevision = $envPSVersion.Revision
+[string]$envPSVersion = $envPSVersion.ToString()
+# CLR (.NET) Version used by PowerShell
+[version]$envCLRVersion = $envPSVersionTable.CLRVersion
+[string]$envCLRVersionMajor = $envCLRVersion.Major
+[string]$envCLRVersionMinor = $envCLRVersion.Minor
+[string]$envCLRVersionBuild = $envCLRVersion.Build
+[string]$envCLRVersionRevision = $envCLRVersion.Revision
+[string]$envCLRVersion = $envCLRVersion.ToString()
+
+## Variables: Permissions/Accounts
+[Security.Principal.WindowsIdentity]$CurrentProcessToken = [Security.Principal.WindowsIdentity]::GetCurrent()
+[Security.Principal.SecurityIdentifier]$CurrentProcessSID = $CurrentProcessToken.User
+[string]$ProcessNTAccount = $CurrentProcessToken.Name
+[string]$ProcessNTAccountSID = $CurrentProcessSID.Value
+[boolean]$IsAdmin = [boolean]($CurrentProcessToken.Groups -contains [Security.Principal.SecurityIdentifier]'S-1-5-32-544')
+[boolean]$IsLocalSystemAccount = $CurrentProcessSID.IsWellKnown([Security.Principal.WellKnownSidType]'LocalSystemSid')
+[boolean]$IsLocalServiceAccount = $CurrentProcessSID.IsWellKnown([Security.Principal.WellKnownSidType]'LocalServiceSid')
+[boolean]$IsNetworkServiceAccount = $CurrentProcessSID.IsWellKnown([Security.Principal.WellKnownSidType]'NetworkServiceSid')
+[boolean]$IsServiceAccount = [boolean]($CurrentProcessToken.Groups -contains [Security.Principal.SecurityIdentifier]'S-1-5-6')
+[boolean]$IsProcessUserInteractive = [Environment]::UserInteractive
+[string]$LocalSystemNTAccount = (New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' -ArgumentList ([Security.Principal.WellKnownSidType]::'LocalSystemSid', $null)).Translate([Security.Principal.NTAccount]).Value
+# Check if script is running in session zero
+If ($IsLocalSystemAccount -or $IsLocalServiceAccount -or $IsNetworkServiceAccount -or $IsServiceAccount) { $SessionZero = $true } Else { $SessionZero = $false }
+
+## Variables: Script Name and Script Paths
+[string]$scriptPath = $MyInvocation.MyCommand.Definition
+[string]$scriptName = [IO.Path]::GetFileNameWithoutExtension($scriptPath)
+[string]$scriptFileName = Split-Path -Path $scriptPath -Leaf
+[string]$scriptRoot = Split-Path -Path $scriptPath -Parent
+[string]$invokingScript = (Get-Variable -Name 'MyInvocation').Value.ScriptName
+# Get the invoking script directory
+If ($invokingScript) {
+ # If this script was invoked by another script
+ [string]$scriptParentPath = Split-Path -Path $invokingScript -Parent
+}
+Else {
+ # If this script was not invoked by another script, fall back to the directory one level above this script
+ [string]$scriptParentPath = (Get-Item -LiteralPath $scriptRoot).Parent.FullName
+}
+
+## Variables: App Deploy Script Dependency Files
+[string]$appDeployLogoIcon = Join-Path -Path $scriptRoot -ChildPath 'AppDeployToolkitLogo.ico'
+[string]$appDeployLogoBanner = Join-Path -Path $scriptRoot -ChildPath 'AppDeployToolkitBanner.png'
+[string]$appDeployConfigFile = Join-Path -Path $scriptRoot -ChildPath 'AppDeployToolkitConfig.xml'
+[string]$appDeployCustomTypesSourceCode = Join-Path -Path $scriptRoot -ChildPath 'AppDeployToolkitMain.cs'
+# App Deploy Optional Extensions File
+[string]$appDeployToolkitDotSourceExtensions = 'AppDeployToolkitExtensions.ps1'
+# Check that dependency files are present
+If (-not (Test-Path -LiteralPath $appDeployLogoIcon -PathType 'Leaf')) { Throw 'App Deploy logo icon file not found.' }
+If (-not (Test-Path -LiteralPath $appDeployLogoBanner -PathType 'Leaf')) { Throw 'App Deploy logo banner file not found.' }
+If (-not (Test-Path -LiteralPath $appDeployConfigFile -PathType 'Leaf')) { Throw 'App Deploy XML configuration file not found.' }
+If (-not (Test-Path -LiteralPath $appDeployCustomTypesSourceCode -PathType 'Leaf')) { Throw 'App Deploy custom types source code file not found.' }
+
+## Import variables from XML configuration file
+[Xml.XmlDocument]$xmlConfigFile = Get-Content -LiteralPath $AppDeployConfigFile
+[Xml.XmlElement]$xmlConfig = $xmlConfigFile.AppDeployToolkit_Config
+# Get Config File Details
+[Xml.XmlElement]$configConfigDetails = $xmlConfig.Config_File
+[string]$configConfigVersion = [version]$configConfigDetails.Config_Version
+[string]$configConfigDate = $configConfigDetails.Config_Date
+# Get Toolkit Options
+[Xml.XmlElement]$xmlToolkitOptions = $xmlConfig.Toolkit_Options
+[boolean]$configToolkitRequireAdmin = [boolean]::Parse($xmlToolkitOptions.Toolkit_RequireAdmin)
+[string]$configToolkitTempPath = $ExecutionContext.InvokeCommand.ExpandString($xmlToolkitOptions.Toolkit_TempPath)
+[string]$configToolkitRegPath = $xmlToolkitOptions.Toolkit_RegPath
+[string]$configToolkitLogDir = $ExecutionContext.InvokeCommand.ExpandString($xmlToolkitOptions.Toolkit_LogPath)
+[boolean]$configToolkitCompressLogs = [boolean]::Parse($xmlToolkitOptions.Toolkit_CompressLogs)
+[string]$configToolkitLogStyle = $xmlToolkitOptions.Toolkit_LogStyle
+[double]$configToolkitLogMaxSize = $xmlToolkitOptions.Toolkit_LogMaxSize
+[boolean]$configToolkitLogWriteToHost = [boolean]::Parse($xmlToolkitOptions.Toolkit_LogWriteToHost)
+[boolean]$configToolkitLogDebugMessage = [boolean]::Parse($xmlToolkitOptions.Toolkit_LogDebugMessage)
+# Get MSI Options
+[Xml.XmlElement]$xmlConfigMSIOptions = $xmlConfig.MSI_Options
+[string]$configMSILoggingOptions = $xmlConfigMSIOptions.MSI_LoggingOptions
+[string]$configMSIInstallParams = $ExecutionContext.InvokeCommand.ExpandString($xmlConfigMSIOptions.MSI_InstallParams)
+[string]$configMSISilentParams = $ExecutionContext.InvokeCommand.ExpandString($xmlConfigMSIOptions.MSI_SilentParams)
+[string]$configMSIUninstallParams = $ExecutionContext.InvokeCommand.ExpandString($xmlConfigMSIOptions.MSI_UninstallParams)
+[string]$configMSILogDir = $ExecutionContext.InvokeCommand.ExpandString($xmlConfigMSIOptions.MSI_LogPath)
+[int32]$configMSIMutexWaitTime = $xmlConfigMSIOptions.MSI_MutexWaitTime
+# Get UI Options
+[Xml.XmlElement]$xmlConfigUIOptions = $xmlConfig.UI_Options
+[string]$configInstallationUILanguageOverride = $xmlConfigUIOptions.InstallationUI_LanguageOverride
+[boolean]$configShowBalloonNotifications = [boolean]::Parse($xmlConfigUIOptions.ShowBalloonNotifications)
+[int32]$configInstallationUITimeout = $xmlConfigUIOptions.InstallationUI_Timeout
+[int32]$configInstallationUIExitCode = $xmlConfigUIOptions.InstallationUI_ExitCode
+[int32]$configInstallationDeferExitCode = $xmlConfigUIOptions.InstallationDefer_ExitCode
+[int32]$configInstallationPersistInterval = $xmlConfigUIOptions.InstallationPrompt_PersistInterval
+[int32]$configInstallationRestartPersistInterval = $xmlConfigUIOptions.InstallationRestartPrompt_PersistInterval
+[int32]$configInstallationPromptToSave = $xmlConfigUIOptions.InstallationPromptToSave_Timeout
+[boolean]$configInstallationWelcomePromptDynamicRunningProcessEvaluation = [boolean]::Parse($xmlConfigUIOptions.InstallationWelcomePrompt_DynamicRunningProcessEvaluation)
+[int32]$configInstallationWelcomePromptDynamicRunningProcessEvaluationInterval = $xmlConfigUIOptions.InstallationWelcomePrompt_DynamicRunningProcessEvaluationInterval
+# Define ScriptBlock for Loading Message UI Language Options (default for English if no localization found)
+[scriptblock]$xmlLoadLocalizedUIMessages = {
+ # If a user is logged on, then get primary UI language for logged on user (even if running in session 0)
+ If ($RunAsActiveUser) {
+ # Read language defined by Group Policy
+ If (-not $HKULanguages) {
+ [string[]]$HKULanguages = Get-RegistryKey -Key 'HKLM:SOFTWARE\Policies\Microsoft\MUI\Settings' -Value 'PreferredUILanguages'
+ }
+ If (-not $HKULanguages) {
+ [string[]]$HKULanguages = Get-RegistryKey -Key 'HKCU\Software\Policies\Microsoft\Windows\Control Panel\Desktop' -Value 'PreferredUILanguages' -SID $RunAsActiveUser.SID
+ }
+ # Read language for Win Vista & higher machines
+ If (-not $HKULanguages) {
+ [string[]]$HKULanguages = Get-RegistryKey -Key 'HKCU\Control Panel\Desktop' -Value 'PreferredUILanguages' -SID $RunAsActiveUser.SID
+ }
+ If (-not $HKULanguages) {
+ [string[]]$HKULanguages = Get-RegistryKey -Key 'HKCU\Control Panel\Desktop\MuiCached' -Value 'MachinePreferredUILanguages' -SID $RunAsActiveUser.SID
+ }
+ If (-not $HKULanguages) {
+ [string[]]$HKULanguages = Get-RegistryKey -Key 'HKCU\Control Panel\International' -Value 'LocaleName' -SID $RunAsActiveUser.SID
+ }
+ # Read language for Win XP machines
+ If (-not $HKULanguages) {
+ [string]$HKULocale = Get-RegistryKey -Key 'HKCU\Control Panel\International' -Value 'Locale' -SID $RunAsActiveUser.SID
+ If ($HKULocale) {
+ [int32]$HKULocale = [Convert]::ToInt32('0x' + $HKULocale, 16)
+ [string[]]$HKULanguages = ([Globalization.CultureInfo]($HKULocale)).Name
+ }
+ }
+ If ($HKULanguages) {
+ [Globalization.CultureInfo]$PrimaryWindowsUILanguage = [Globalization.CultureInfo]($HKULanguages[0])
+ [string]$HKUPrimaryLanguageShort = $PrimaryWindowsUILanguage.TwoLetterISOLanguageName.ToUpper()
+
+ # If the detected language is Chinese, determine if it is simplified or traditional Chinese
+ If ($HKUPrimaryLanguageShort -eq 'ZH') {
+ If ($PrimaryWindowsUILanguage.EnglishName -match 'Simplified') {
+ [string]$HKUPrimaryLanguageShort = 'ZH-Hans'
+ }
+ If ($PrimaryWindowsUILanguage.EnglishName -match 'Traditional') {
+ [string]$HKUPrimaryLanguageShort = 'ZH-Hant'
+ }
+ }
+
+ # If the detected language is Portuguese, determine if it is Brazilian Portuguese
+ If ($HKUPrimaryLanguageShort -eq 'PT') {
+ If ($PrimaryWindowsUILanguage.ThreeLetterWindowsLanguageName -eq 'PTB') {
+ [string]$HKUPrimaryLanguageShort = 'PT-BR'
+ }
+ }
+ }
+ }
+
+ If ($HKUPrimaryLanguageShort) {
+ # Use the primary UI language of the logged in user
+ [string]$xmlUIMessageLanguage = "UI_Messages_$HKUPrimaryLanguageShort"
+ }
+ Else {
+ # Default to UI language of the account executing current process (even if it is the SYSTEM account)
+ [string]$xmlUIMessageLanguage = "UI_Messages_$currentLanguage"
+ }
+ # Default to English if the detected UI language is not available in the XMl config file
+ If (-not ($xmlConfig.$xmlUIMessageLanguage)) { [string]$xmlUIMessageLanguage = 'UI_Messages_EN' }
+ # Override the detected language if the override option was specified in the XML config file
+ If ($configInstallationUILanguageOverride) { [string]$xmlUIMessageLanguage = "UI_Messages_$configInstallationUILanguageOverride" }
+
+ [Xml.XmlElement]$xmlUIMessages = $xmlConfig.$xmlUIMessageLanguage
+ [string]$configDiskSpaceMessage = $xmlUIMessages.DiskSpace_Message
+ [string]$configBalloonTextStart = $xmlUIMessages.BalloonText_Start
+ [string]$configBalloonTextComplete = $xmlUIMessages.BalloonText_Complete
+ [string]$configBalloonTextRestartRequired = $xmlUIMessages.BalloonText_RestartRequired
+ [string]$configBalloonTextFastRetry = $xmlUIMessages.BalloonText_FastRetry
+ [string]$configBalloonTextError = $xmlUIMessages.BalloonText_Error
+ [string]$configProgressMessageInstall = $xmlUIMessages.Progress_MessageInstall
+ [string]$configProgressMessageUninstall = $xmlUIMessages.Progress_MessageUninstall
+ [string]$configClosePromptMessage = $xmlUIMessages.ClosePrompt_Message
+ [string]$configClosePromptButtonClose = $xmlUIMessages.ClosePrompt_ButtonClose
+ [string]$configClosePromptButtonDefer = $xmlUIMessages.ClosePrompt_ButtonDefer
+ [string]$configClosePromptButtonContinue = $xmlUIMessages.ClosePrompt_ButtonContinue
+ [string]$configClosePromptButtonContinueTooltip = $xmlUIMessages.ClosePrompt_ButtonContinueTooltip
+ [string]$configClosePromptCountdownMessage = $xmlUIMessages.ClosePrompt_CountdownMessage
+ [string]$configDeferPromptWelcomeMessage = $xmlUIMessages.DeferPrompt_WelcomeMessage
+ [string]$configDeferPromptExpiryMessage = $xmlUIMessages.DeferPrompt_ExpiryMessage
+ [string]$configDeferPromptWarningMessage = $xmlUIMessages.DeferPrompt_WarningMessage
+ [string]$configDeferPromptRemainingDeferrals = $xmlUIMessages.DeferPrompt_RemainingDeferrals
+ [string]$configDeferPromptDeadline = $xmlUIMessages.DeferPrompt_Deadline
+ [string]$configBlockExecutionMessage = $xmlUIMessages.BlockExecution_Message
+ [string]$configDeploymentTypeInstall = $xmlUIMessages.DeploymentType_Install
+ [string]$configDeploymentTypeUnInstall = $xmlUIMessages.DeploymentType_UnInstall
+ [string]$configRestartPromptTitle = $xmlUIMessages.RestartPrompt_Title
+ [string]$configRestartPromptMessage = $xmlUIMessages.RestartPrompt_Message
+ [string]$configRestartPromptMessageTime = $xmlUIMessages.RestartPrompt_MessageTime
+ [string]$configRestartPromptMessageRestart = $xmlUIMessages.RestartPrompt_MessageRestart
+ [string]$configRestartPromptTimeRemaining = $xmlUIMessages.RestartPrompt_TimeRemaining
+ [string]$configRestartPromptButtonRestartLater = $xmlUIMessages.RestartPrompt_ButtonRestartLater
+ [string]$configRestartPromptButtonRestartNow = $xmlUIMessages.RestartPrompt_ButtonRestartNow
+ [string]$configWelcomePromptCountdownMessage = $xmlUIMessages.WelcomePrompt_CountdownMessage
+ [string]$configWelcomePromptCustomMessage = $xmlUIMessages.WelcomePrompt_CustomMessage
+}
+
+## Variables: Script Directories
+[string]$dirFiles = Join-Path -Path $scriptParentPath -ChildPath 'Files'
+[string]$dirSupportFiles = Join-Path -Path $scriptParentPath -ChildPath 'SupportFiles'
+[string]$dirAppDeployTemp = Join-Path -Path $configToolkitTempPath -ChildPath $appDeployToolkitName
+
+## Set the deployment type to "Install" if it has not been specified
+If (-not $deploymentType) { [string]$deploymentType = 'Install' }
+
+## Variables: Executables
+[string]$exeWusa = 'wusa.exe' # Installs Standalone Windows Updates
+[string]$exeMsiexec = 'msiexec.exe' # Installs MSI Installers
+[string]$exeSchTasks = "$envWinDir\System32\schtasks.exe" # Manages Scheduled Tasks
+
+## Variables: RegEx Patterns
+[string]$MSIProductCodeRegExPattern = '^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$'
+
+## Variables: Registry Keys
+# Registry keys for native and WOW64 applications
+[string[]]$regKeyApplications = 'HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall','HKLM:SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall'
+If ($is64Bit) {
+ [string]$regKeyLotusNotes = 'HKLM:SOFTWARE\Wow6432Node\Lotus\Notes'
+}
+Else {
+ [string]$regKeyLotusNotes = 'HKLM:SOFTWARE\Lotus\Notes'
+}
+[string]$regKeyAppExecution = 'HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options'
+
+## COM Objects: Initialize
+[__comobject]$Shell = New-Object -ComObject 'WScript.Shell' -ErrorAction 'SilentlyContinue'
+[__comobject]$ShellApp = New-Object -ComObject 'Shell.Application' -ErrorAction 'SilentlyContinue'
+
+## Variables: Reset/Remove Variables
+[boolean]$msiRebootDetected = $false
+[boolean]$BlockExecution = $false
+[boolean]$installationStarted = $false
+[boolean]$runningTaskSequence = $false
+If (Test-Path -LiteralPath 'variable:welcomeTimer') { Remove-Variable -Name 'welcomeTimer' -Scope 'Script'}
+# Reset the deferral history
+If (Test-Path -LiteralPath 'variable:deferHistory') { Remove-Variable -Name 'deferHistory' }
+If (Test-Path -LiteralPath 'variable:deferTimes') { Remove-Variable -Name 'deferTimes' }
+If (Test-Path -LiteralPath 'variable:deferDays') { Remove-Variable -Name 'deferDays' }
+
+## Variables: System DPI Scale Factor
+[scriptblock]$GetDisplayScaleFactor = {
+ # If a user is logged on, then get display scale factor for logged on user (even if running in session 0)
+ [boolean]$UserDisplayScaleFactor = $false
+ If ($RunAsActiveUser) {
+ [int32]$dpiPixels = Get-RegistryKey -Key 'HKCU\Control Panel\Desktop\WindowMetrics' -Value 'AppliedDPI' -SID $RunAsActiveUser.SID
+ If (-not ([string]$dpiPixels)) {
+ [int32]$dpiPixels = Get-RegistryKey -Key 'HKCU\Control Panel\Desktop' -Value 'LogPixels' -SID $RunAsActiveUser.SID
+ }
+ [boolean]$UserDisplayScaleFactor = $true
+ }
+ If (-not ([string]$dpiPixels)) {
+ # This registry setting only exists if system scale factor has been changed at least once
+ [int32]$dpiPixels = Get-RegistryKey -Key 'HKLM:SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontDPI' -Value 'LogPixels'
+ [boolean]$UserDisplayScaleFactor = $false
+ }
+ Switch ($dpiPixels) {
+ 96 { [int32]$dpiScale = 100 }
+ 120 { [int32]$dpiScale = 125 }
+ 144 { [int32]$dpiScale = 150 }
+ 192 { [int32]$dpiScale = 200 }
+ Default { [int32]$dpiScale = 100 }
+ }
+}
+#endregion
+##*=============================================
+##* END VARIABLE DECLARATION
+##*=============================================
+
+##*=============================================
+##* FUNCTION LISTINGS
+##*=============================================
+#region FunctionListings
+
+#region Function Write-FunctionHeaderOrFooter
+Function Write-FunctionHeaderOrFooter {
+<#
+.SYNOPSIS
+ Write the function header or footer to the log upon first entering or exiting a function.
+.DESCRIPTION
+ Write the "Function Start" message, the bound parameters the function was invoked with, or the "Function End" message when entering or exiting a function.
+ Messages are debug messages so will only be logged if LogDebugMessage option is enabled in XML config file.
+.PARAMETER CmdletName
+ The name of the function this function is invoked from.
+.PARAMETER CmdletBoundParameters
+ The bound parameters of the function this function is invoked from.
+.PARAMETER Header
+ Write the function header.
+.PARAMETER Footer
+ Write the function footer.
+.EXAMPLE
+ Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -CmdletBoundParameters $PSBoundParameters -Header
+.EXAMPLE
+ Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -Footer
+.NOTES
+ This is an internal script function and should typically not be called directly.
+.LINK
+ http://psappdeploytoolkit.com
+#>
+ [CmdletBinding()]
+ Param (
+ [Parameter(Mandatory=$true)]
+ [ValidateNotNullorEmpty()]
+ [string]$CmdletName,
+ [Parameter(Mandatory=$true,ParameterSetName='Header')]
+ [AllowEmptyCollection()]
+ [hashtable]$CmdletBoundParameters,
+ [Parameter(Mandatory=$true,ParameterSetName='Header')]
+ [switch]$Header,
+ [Parameter(Mandatory=$true,ParameterSetName='Footer')]
+ [switch]$Footer
+ )
+
+ If ($Header) {
+ Write-Log -Message 'Function Start' -Source ${CmdletName} -DebugMessage
+
+ ## Get the parameters that the calling function was invoked with
+ [string]$CmdletBoundParameters = $CmdletBoundParameters | Format-Table -Property @{ Label = 'Parameter'; Expression = { "[-$($_.Key)]" } }, @{ Label = 'Value'; Expression = { $_.Value }; Alignment = 'Left' }, @{ Label = 'Type'; Expression = { $_.Value.GetType().Name }; Alignment = 'Left' } -AutoSize -Wrap | Out-String
+ If ($CmdletBoundParameters) {
+ Write-Log -Message "Function invoked with bound parameter(s): `n$CmdletBoundParameters" -Source ${CmdletName} -DebugMessage
+ }
+ Else {
+ Write-Log -Message 'Function invoked without any bound parameters.' -Source ${CmdletName} -DebugMessage
+ }
+ }
+ ElseIf ($Footer) {
+ Write-Log -Message 'Function End' -Source ${CmdletName} -DebugMessage
+ }
+}
+#endregion
+#region Function Execute-MSP
+Function Execute-MSP {
+<#
+.SYNOPSIS
+ Reads SummaryInfo targeted product codes in MSP file and determines if the MSP file applies to any installed products
+ If a valid installed product is found, triggers the Execute-MSI function to patch the installation.
+.PARAMETER Path
+.EXAMPLE
+ Execute-MSP -Path 'Adobe_Reader_11.0.3_EN.msp'
+.NOTES
+.LINK
+ http://psappdeploytoolkit.com
+#>
+ [CmdletBinding()]
+ Param (
+ [Parameter(Mandatory=$true,HelpMessage='Please enter the path to the MSP file')]
+ [ValidateScript({('.msp' -contains [IO.Path]::GetExtension($_))})]
+ [Alias('FilePath')]
+ [string]$Path
+ )
+
+ Begin {
+ ## Get the name of this function and write header
+ [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
+ Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -CmdletBoundParameters $PSBoundParameters -Header
+ }
+ Process {
+ ## If the MSP is in the Files directory, set the full path to the MSP
+ If (Test-Path -LiteralPath (Join-Path -Path $dirFiles -ChildPath $path -ErrorAction 'SilentlyContinue') -PathType 'Leaf' -ErrorAction 'SilentlyContinue') {
+ [string]$mspFile = Join-Path -Path $dirFiles -ChildPath $path
+ }
+ ElseIf (Test-Path -LiteralPath $Path -ErrorAction 'SilentlyContinue') {
+ [string]$mspFile = (Get-Item -LiteralPath $Path).FullName
+ }
+ Else {
+ Write-Log -Message "Failed to find MSP file [$path]." -Severity 3 -Source ${CmdletName}
+ If (-not $ContinueOnError) {
+ Throw "Failed to find MSP file [$path]."
+ }
+ Continue
+ }
+ Write-Log -Message 'Checking MSP file for valid product codes' -Source ${CmdletName}
+
+ [boolean]$IsMSPNeeded = $false
+
+ $Installer = New-Object -com WindowsInstaller.Installer
+ $Database = $Installer.GetType().InvokeMember(“OpenDatabase”, “InvokeMethod”, $Null, $Installer, $($mspFile,([int32]32)))
+ [__comobject]$SummaryInformation = Get-ObjectProperty -InputObject $Database -PropertyName 'SummaryInformation'
+ [hashtable]$SummaryInfoProperty = @{}
+ $all = (Get-ObjectProperty -InputObject $SummaryInformation -PropertyName 'Property' -ArgumentList @(7)).Split(";")
+ Foreach($FormattedProductCode in $all) {
+ [psobject]$MSIInstalled = Get-InstalledApplication -ProductCode $FormattedProductCode
+ If ($MSIInstalled) {[boolean]$IsMSPNeeded = $true }
+ }
+ Try { $null = [Runtime.Interopservices.Marshal]::ReleaseComObject($SummaryInformation) } Catch { }
+ Try { $null = [Runtime.Interopservices.Marshal]::ReleaseComObject($DataBase) } Catch { }
+ Try { $null = [Runtime.Interopservices.Marshal]::ReleaseComObject($Installer) } Catch { }
+ If ($IsMSPNeeded) { Execute-MSI -Action Patch -Path $Path }
+ }
+}
+#endregion
+
+#region Function Write-Log
+Function Write-Log {
+<#
+.SYNOPSIS
+ Write messages to a log file in CMTrace.exe compatible format or Legacy text file format.
+.DESCRIPTION
+ Write messages to a log file in CMTrace.exe compatible format or Legacy text file format and optionally display in the console.
+.PARAMETER Message
+ The message to write to the log file or output to the console.
+.PARAMETER Severity
+ Defines message type. When writing to console or CMTrace.exe log format, it allows highlighting of message type.
+ Options: 1 = Information (default), 2 = Warning (highlighted in yellow), 3 = Error (highlighted in red)
+.PARAMETER Source
+ The source of the message being logged.
+.PARAMETER ScriptSection
+ The heading for the portion of the script that is being executed. Default is: $script:installPhase.
+.PARAMETER LogType
+ Choose whether to write a CMTrace.exe compatible log file or a Legacy text log file.
+.PARAMETER LogFileDirectory
+ Set the directory where the log file will be saved.
+.PARAMETER LogFileName
+ Set the name of the log file.
+.PARAMETER MaxLogFileSizeMB
+ Maximum file size limit for log file in megabytes (MB). Default is 10 MB.
+.PARAMETER WriteHost
+ Write the log message to the console.
+.PARAMETER ContinueOnError
+ Suppress writing log message to console on failure to write message to log file. Default is: $true.
+.PARAMETER PassThru
+ Return the message that was passed to the function
+.PARAMETER DebugMessage
+ Specifies that the message is a debug message. Debug messages only get logged if -LogDebugMessage is set to $true.
+.PARAMETER LogDebugMessage
+ Debug messages only get logged if this parameter is set to $true in the config XML file.
+.EXAMPLE
+ Write-Log -Message "Installing patch MS15-031" -Source 'Add-Patch' -LogType 'CMTrace'
+.EXAMPLE
+ Write-Log -Message "Script is running on Windows 8" -Source 'Test-ValidOS' -LogType 'Legacy'
+.NOTES
+.LINK
+ http://psappdeploytoolkit.com
+#>
+ [CmdletBinding()]
+ Param (
+ [Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
+ [AllowEmptyCollection()]
+ [Alias('Text')]
+ [string[]]$Message,
+ [Parameter(Mandatory=$false,Position=1)]
+ [ValidateRange(1,3)]
+ [int16]$Severity = 1,
+ [Parameter(Mandatory=$false,Position=2)]
+ [ValidateNotNull()]
+ [string]$Source = '',
+ [Parameter(Mandatory=$false,Position=3)]
+ [ValidateNotNullorEmpty()]
+ [string]$ScriptSection = $script:installPhase,
+ [Parameter(Mandatory=$false,Position=4)]
+ [ValidateSet('CMTrace','Legacy')]
+ [string]$LogType = $configToolkitLogStyle,
+ [Parameter(Mandatory=$false,Position=5)]
+ [ValidateNotNullorEmpty()]
+ [string]$LogFileDirectory = $(If ($configToolkitCompressLogs) { $logTempFolder } Else { $configToolkitLogDir }),
+ [Parameter(Mandatory=$false,Position=6)]
+ [ValidateNotNullorEmpty()]
+ [string]$LogFileName = $logName,
+ [Parameter(Mandatory=$false,Position=7)]
+ [ValidateNotNullorEmpty()]
+ [decimal]$MaxLogFileSizeMB = $configToolkitLogMaxSize,
+ [Parameter(Mandatory=$false,Position=8)]
+ [ValidateNotNullorEmpty()]
+ [boolean]$WriteHost = $configToolkitLogWriteToHost,
+ [Parameter(Mandatory=$false,Position=9)]
+ [ValidateNotNullorEmpty()]
+ [boolean]$ContinueOnError = $true,
+ [Parameter(Mandatory=$false,Position=10)]
+ [switch]$PassThru = $false,
+ [Parameter(Mandatory=$false,Position=11)]
+ [switch]$DebugMessage = $false,
+ [Parameter(Mandatory=$false,Position=12)]
+ [boolean]$LogDebugMessage = $configToolkitLogDebugMessage
+ )
+
+ Begin {
+ ## Get the name of this function
+ [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
+
+ ## Logging Variables
+ # Log file date/time
+ [string]$LogTime = (Get-Date -Format 'HH:mm:ss.fff').ToString()
+ [string]$LogDate = (Get-Date -Format 'MM-dd-yyyy').ToString()
+ If (-not (Test-Path -LiteralPath 'variable:LogTimeZoneBias')) { [int32]$script:LogTimeZoneBias = [timezone]::CurrentTimeZone.GetUtcOffset([datetime]::Now).TotalMinutes }
+ [string]$LogTimePlusBias = $LogTime + $script:LogTimeZoneBias
+ # Initialize variables
+ [boolean]$ExitLoggingFunction = $false
+ If (-not (Test-Path -LiteralPath 'variable:DisableLogging')) { $DisableLogging = $false }
+ # Check if the script section is defined
+ [boolean]$ScriptSectionDefined = [boolean](-not [string]::IsNullOrEmpty($ScriptSection))
+ # Get the file name of the source script
+ Try {
+ If ($script:MyInvocation.Value.ScriptName) {
+ [string]$ScriptSource = Split-Path -Path $script:MyInvocation.Value.ScriptName -Leaf -ErrorAction 'Stop'
+ }
+ Else {
+ [string]$ScriptSource = Split-Path -Path $script:MyInvocation.MyCommand.Definition -Leaf -ErrorAction 'Stop'
+ }
+ }
+ Catch {
+ $ScriptSource = ''
+ }
+
+ ## Create script block for generating CMTrace.exe compatible log entry
+ [scriptblock]$CMTraceLogString = {
+ Param (
+ [string]$lMessage,
+ [string]$lSource,
+ [int16]$lSeverity
+ )
+ "" + "