diff --git a/Content/Example_Applications.xml b/Content/Example_Applications.xml
new file mode 100644
index 0000000..efcd305
--- /dev/null
+++ b/Content/Example_Applications.xml
@@ -0,0 +1 @@
+Microsoft Visual C++ Redistributables10/18/2022 7:29:18 PMDSW\amote3/17/2023 5:11:54 PMAzureAD\AlphaeusMoteMicrosoft Visual C++ RedistributablesMicrosoft Visual C++ Redistributables100Microsoft Corporation$True.\Applications\MicrosoftVisualC+Redistributableswscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\MicrosoftVisualC+RedistributablesTrue7-Zip File Manager10/18/2022 7:29:40 PMDSW\amote3/17/2023 5:12:48 PMAzureAD\AlphaeusMote7-Zip File Manager7-Zip File Manager102Ivan Pavlov$True.\Applications\7-ZipFileManagerwscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\7-ZipFileManagerFalseNotepad++10/18/2022 7:29:49 PMDSW\amote3/17/2023 5:13:22 PMAzureAD\AlphaeusMoteNotepad++Notepad++105Don Ho$True.\Applications\NotepadPlusPluswscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\NotepadPlusPlusFalseDell Command UpdateDell Command | Update is a stand-alone application, for commercial client computers, that provides updates for system software that is released by Dell. This application simplifies the BIOS, firmware, driver, and application update experience for Dell commercial client hardware. This application can also be used to install drivers after the operating system and network drivers are installed based on the computer identity.10/18/2022 7:30:04 PMDSW\amote3/17/2023 5:15:26 PMAzureAD\AlphaeusMoteDell Command UpdateDell Command Update1Dell($ComputerSystem.Manufacturer -imatch '.*Dell.*').\Applications\DellCommandUpdatewscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\DellCommandUpdateFalseGoogle Chrome10/18/2022 7:30:48 PMDSW\amote3/17/2023 5:15:03 PMAzureAD\AlphaeusMoteGoogle ChromeGoogle Chrome109Google Incorporated($OperatingSystem.ProductType -in @(1)).\Applications\GoogleChromewscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\GoogleChromeFalseConfiguration Manager Support Center10/18/2022 7:30:57 PMDSW\amote3/17/2023 5:13:00 PMAzureAD\AlphaeusMoteConfiguration Manager Support CenterConfiguration Manager Support Center103Microsoft Corporation$True.\Applications\MicrosoftCorporation_SupportCenterwscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\MicrosoftCorporation_SupportCenterFalseMicrosoft Office 365 Apps For EnterpriseMicrosoft 365 Apps for enterprise is the most productive and most secure Office experience for enterprises, allowing your teams to work together seamlessly from anywhere, anytime.10/18/2022 7:32:36 PMDSW\amote3/17/2023 5:16:24 PMAzureAD\AlphaeusMoteMicrosoft Office 365 Apps For EnterpriseMicrosoft Office 365 Apps For Enterprise113Microsoft Corporation($OperatingSystem.ProductType -in @(1)).\Applications\MicrosoftOffice365wscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\MicrosoftOffice365TrueAdobe Acrobat Reader10/18/2022 7:33:32 PMDSW\amote3/17/2023 5:15:09 PMAzureAD\AlphaeusMoteAdobe Acrobat ReaderAdobe Acrobat Reader110Adobe Systems Incorporated($OperatingSystem.ProductType -in @(1)).\Applications\AdobeReaderwscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\AdobeReaderFalseJava Runtime Environment10/18/2022 7:34:30 PMDSW\amote3/17/2023 5:14:42 PMAzureAD\AlphaeusMoteJava Runtime EnvironmentJava Runtime Environment108SunMicro($OperatingSystem.ProductType -in @(1)).\Applications\JavaRuntimeEnvironmentwscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\JavaRuntimeEnvironmentFalseZoom Meetings12/9/2022 9:48:07 PMDSW\amote3/17/2023 5:16:52 PMAzureAD\AlphaeusMoteZoom MeetingsZoom Meetings112Zoom Video Communications, Inc.($OperatingSystem.ProductType -in @(1)).\Applications\ZoomMeetingswscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\ZoomMeetingsFalsePowershell 712/9/2022 9:58:53 PMDSW\amote3/17/2023 5:15:59 PMAzureAD\AlphaeusMotePowershell 7Powershell 7111Microsoft Corporation$True.\Applications\Powershell7wscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\Powershell7FalseVEEAM Agent for Windows2/21/2023 3:12:41 PMAzureAD\AlphaeusMote3/17/2023 5:16:30 PMAzureAD\AlphaeusMoteVEEAM Agent for WindowsVEEAM Agent for Windows114VEEAM Software Group($OperatingSystem.ProductType -in @(2, 3)).\Applications\VEEAMAgentforWindowswscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\VEEAMAgentforWindowsTrueVMware Tools2/21/2023 4:11:11 PMAzureAD\AlphaeusMote3/17/2023 5:12:01 PMAzureAD\AlphaeusMoteVMware ToolsVMware Tools1VMware, Inc.($ComputerSystem.Manufacturer -imatch '.*VM.*Ware.*').\Applications\VMwareToolswscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\VMwareToolsTrueWindows Assessment and Deployment Kit2/21/2023 4:34:10 PMAzureAD\AlphaeusMote3/17/2023 5:11:03 PMAzureAD\AlphaeusMoteWindows Assessment and Deployment KitWindows Assessment and Deployment Kit300Microsoft CorporationOptional.\Applications\WindowsAssessmentAndDeploymentKitwscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\WindowsAssessmentAndDeploymentKitTrueRemote Desktop Manager Agent2/21/2023 8:03:37 PMAzureAD\AlphaeusMote3/17/2023 5:13:12 PMAzureAD\AlphaeusMoteRemote Desktop Manager AgentRemote Desktop Manager Agent104Devolutions Inc.$True.\Applications\RemoteDesktopManagerAgentwscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\RemoteDesktopManagerAgentFalseDameWare Mini Remote Control Agent3/8/2023 7:07:21 PMAzureAD\AlphaeusMote3/17/2023 5:12:31 PMAzureAD\AlphaeusMoteDameWare Mini Remote Control AgentDameWare Mini Remote Control Agent101SolarWinds$True.\Applications\DamewareRemoteControlAgentwscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\DamewareRemoteControlAgentFalseDesktopInfohttps://www.glenn.delahoy.com/desktopinfo/3/10/2023 4:25:47 PMAzureAD\AlphaeusMote3/17/2023 5:14:16 PMAzureAD\AlphaeusMoteDesktopInfoDesktopInfo107Glenn Delayhoy$True.\Applications\DesktopInfowscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\DesktopInfoXYPlorer3/13/2023 6:02:59 PMAzureAD\AlphaeusMote3/17/2023 5:14:08 PMAzureAD\AlphaeusMoteXYPlorerXYPlorer106Cologne Code Company$True.\Applications\XYPlorerwscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\XYPlorerAdaptiva Systems Management Suite3/17/2023 1:22:47 AMAzureAD\AlphaeusMote3/18/2023 2:51:01 AMCND04700NS\amoteAdaptiva Systems Management SuiteAdaptiva Systems Management Suite200Adaptiva$True.\Applications\AdaptivaSystemsManagementSuitewscript.exe "Deploy-Application.vbs" /DeploymentType:"Install" /DeployMode:"Silent".\Applications\AdaptivaSystemsManagementSuite
\ No newline at end of file
diff --git a/Content/TaskSequenceTemplates/ts.xml b/Content/TaskSequenceTemplates/ts.xml
new file mode 100644
index 0000000..a439f80
--- /dev/null
+++ b/Content/TaskSequenceTemplates/ts.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+ %CustomContentPath%\Invoke-OSDApplicationList\Invoke-OSDApplicationList.ps1
+
+
+
+ cscript.exe "%SCRIPTROOT%\ZTIPowerShell.wsf
+
+
+
+
+ 0 1 3010
+
+ cscript.exe "%SCRIPTROOT%\ZTIApplications.wsf"
+
+
+
\ No newline at end of file
diff --git a/Functions/Get-InstalledSoftware.ps1 b/Functions/Get-InstalledSoftware.ps1
new file mode 100644
index 0000000..da12016
--- /dev/null
+++ b/Functions/Get-InstalledSoftware.ps1
@@ -0,0 +1,450 @@
+## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx
+
+#region Function Get-InstalledSoftware
+Function Get-InstalledSoftware
+ {
+ <#
+ .SYNOPSIS
+ Retrieves a list of software installed on the current device.
+
+ .DESCRIPTION
+ Supports filtering the resulting list of software by using regular expressions.
+
+ .PARAMETER FilterInclusionExpression
+ Includes software based on their display name.
+
+ .PARAMETER FilterInclusionExpression
+ Excludes software based on their display name.
+
+ .PARAMETER ContinueOnError
+ Continues processing even if an error has occured.
+
+ .EXAMPLE
+ Get-InstalledSoftware
+
+ .EXAMPLE
+ Get-InstalledSoftware -Verbose
+
+ .EXAMPLE
+ $GetInstalledSoftwareParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $GetInstalledSoftwareParameters.FilterInclusionExpression = "(.*)"
+ $GetInstalledSoftwareParameters.FilterExclusionExpression = "(^.{0,0}$)"
+ $GetInstalledSoftwareParameters.ContinueOnError = $False
+ $GetInstalledSoftwareParameters.Verbose = $True
+
+ $GetInstalledSoftwareResult = Get-InstalledSoftware @GetInstalledSoftwareParameters
+
+ Write-Output -InputObject ($GetInstalledSoftwareResult)
+ #>
+
+ [CmdletBinding()]
+
+ Param
+ (
+ [Parameter(Mandatory=$False)]
+ [ValidateNotNullOrEmpty()]
+ [Alias('FIE')]
+ [Regex]$FilterInclusionExpression,
+
+ [Parameter(Mandatory=$False)]
+ [ValidateNotNullOrEmpty()]
+ [Alias('FEE')]
+ [Regex]$FilterExclusionExpression,
+
+ [Parameter(Mandatory=$False)]
+ [Alias('COE')]
+ [Switch]$ContinueOnError
+ )
+
+ Begin
+ {
+ Try
+ {
+ $DateTimeLogFormat = 'dddd, MMMM dd, yyyy @ hh:mm:ss.FFF tt' ###Monday, January 01, 2019 @ 10:15:34.000 AM###
+ [ScriptBlock]$GetCurrentDateTimeLogFormat = {(Get-Date).ToString($DateTimeLogFormat)}
+ $DateTimeMessageFormat = 'MM/dd/yyyy HH:mm:ss.FFF' ###03/23/2022 11:12:48.347###
+ [ScriptBlock]$GetCurrentDateTimeMessageFormat = {(Get-Date).ToString($DateTimeMessageFormat)}
+ $DateFileFormat = 'yyyyMMdd' ###20190403###
+ [ScriptBlock]$GetCurrentDateFileFormat = {(Get-Date).ToString($DateFileFormat)}
+ $DateTimeFileFormat = 'yyyyMMdd_HHmmss' ###20190403_115354###
+ [ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)}
+ $TextInfo = (Get-Culture).TextInfo
+ $LoggingDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $LoggingDetails.Add('LogMessage', $Null)
+ $LoggingDetails.Add('WarningMessage', $Null)
+ $LoggingDetails.Add('ErrorMessage', $Null)
+ $CommonParameterList = New-Object -TypeName 'System.Collections.Generic.List[String]'
+ $CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::CommonParameters)
+ $CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::OptionalCommonParameters)
+
+ [ScriptBlock]$ErrorHandlingDefinition = {
+ $ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $ErrorMessageList.Add('Message', $_.Exception.Message)
+ $ErrorMessageList.Add('Category', $_.Exception.ErrorRecord.FullyQualifiedErrorID)
+ $ErrorMessageList.Add('Script', $_.InvocationInfo.ScriptName)
+ $ErrorMessageList.Add('LineNumber', $_.InvocationInfo.ScriptLineNumber)
+ $ErrorMessageList.Add('LinePosition', $_.InvocationInfo.OffsetInLine)
+ $ErrorMessageList.Add('Code', $_.InvocationInfo.Line.Trim())
+
+ ForEach ($ErrorMessage In $ErrorMessageList.GetEnumerator())
+ {
+ $LoggingDetails.ErrorMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - ERROR: $($ErrorMessage.Key): $($ErrorMessage.Value)"
+ Write-Warning -Message ($LoggingDetails.ErrorMessage)
+ }
+
+ Switch (($ContinueOnError.IsPresent -eq $False) -or ($ContinueOnError -eq $False))
+ {
+ {($_ -eq $True)}
+ {
+ Throw
+ }
+ }
+ }
+
+ #Determine the date and time we executed the function
+ $FunctionStartTime = (Get-Date)
+
+ [String]$FunctionName = $MyInvocation.MyCommand
+ [System.IO.FileInfo]$InvokingScriptPath = $MyInvocation.PSCommandPath
+ [System.IO.DirectoryInfo]$InvokingScriptDirectory = $InvokingScriptPath.Directory.FullName
+ [System.IO.FileInfo]$FunctionPath = "$($InvokingScriptDirectory.FullName)\Functions\$($FunctionName).ps1"
+ [System.IO.DirectoryInfo]$FunctionDirectory = "$($FunctionPath.Directory.FullName)"
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is beginning. Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ #Define Default Action Preferences
+ $ErrorActionPreference = 'Stop'
+
+ [String[]]$AvailableScriptParameters = (Get-Command -Name ($FunctionName)).Parameters.GetEnumerator() | Where-Object {($_.Value.Name -inotin $CommonParameterList)} | ForEach-Object {"-$($_.Value.Name):$($_.Value.ParameterType.Name)"}
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Available Function Parameter(s) = $($AvailableScriptParameters -Join ', ')"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ [String[]]$SuppliedScriptParameters = $PSBoundParameters.GetEnumerator() | ForEach-Object {"-$($_.Key):$($_.Value.GetType().Name)"}
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Supplied Function Parameter(s) = $($SuppliedScriptParameters -Join ', ')"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($FunctionName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ #region Set Default Parameter Values
+ Switch ($True)
+ {
+ {([String]::IsNullOrEmpty($FilterInclusionExpression) -eq $True) -or ([String]::IsNullOrWhiteSpace($FilterInclusionExpression) -eq $True)}
+ {
+ [Regex]$FilterInclusionExpression = '(.*)'
+ }
+
+ {([String]::IsNullOrEmpty($FilterExclusionExpression) -eq $True) -or ([String]::IsNullOrWhiteSpace($FilterExclusionExpression) -eq $True)}
+ {
+ [Regex]$FilterExclusionExpression = '(^.{0,0}$)'
+ }
+ }
+ #endregion
+
+ #Create a table for the conversion of dates
+ $DateTimeProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $DateTimeProperties.FormatList = New-Object -TypeName 'System.Collections.Generic.List[String]'
+ $DateTimeProperties.FormatList.AddRange(([System.Globalization.DateTimeFormatInfo]::CurrentInfo.GetAllDateTimePatterns()))
+ $DateTimeProperties.FormatList.AddRange(([System.Globalization.DateTimeFormatInfo]::InvariantInfo.GetAllDateTimePatterns()))
+ $DateTimeProperties.FormatList.Add('yyyyMM')
+ $DateTimeProperties.FormatList.Add('yyyyMMdd')
+ $DateTimeProperties.Culture = $Null
+ $DateTimeProperties.Styles = New-Object -TypeName 'System.Collections.Generic.List[System.Globalization.DateTimeStyles]'
+ $DateTimeProperties.Styles.Add([System.Globalization.DateTimeStyles]::AssumeLocal)
+ $DateTimeProperties.Styles.Add([System.Globalization.DateTimeStyles]::AllowWhiteSpaces)
+
+ #Create an object that will contain the functions output.
+ $OutputObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
+ }
+ Catch
+ {
+ $ErrorHandlingDefinition.Invoke()
+ }
+ Finally
+ {
+
+ }
+ }
+
+ Process
+ {
+ Try
+ {
+ $DateTimeLogFormat = 'dddd, MMMM dd, yyyy @ hh:mm:ss.FFF tt' ###Monday, January 01, 2019 @ 10:15:34.000 AM###
+ [ScriptBlock]$GetCurrentDateTimeLogFormat = {(Get-Date).ToString($DateTimeLogFormat)}
+ $DateTimeMessageFormat = 'MM/dd/yyyy HH:mm:ss.FFF' ###03/23/2022 11:12:48.347###
+ [ScriptBlock]$GetCurrentDateTimeMessageFormat = {(Get-Date).ToString($DateTimeMessageFormat)}
+ $DateFileFormat = 'yyyyMMdd' ###20190403###
+ [ScriptBlock]$GetCurrentDateFileFormat = {(Get-Date).ToString($DateFileFormat)}
+ $DateTimeFileFormat = 'yyyyMMdd_HHmmss' ###20190403_115354###
+ [ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)}
+ $TextInfo = (Get-Culture).TextInfo
+ $LoggingDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $LoggingDetails.Add('LogMessage', $Null)
+ $LoggingDetails.Add('WarningMessage', $Null)
+ $LoggingDetails.Add('ErrorMessage', $Null)
+ $CommonParameterList = New-Object -TypeName 'System.Collections.Generic.List[String]'
+ $CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::CommonParameters)
+ $CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::OptionalCommonParameters)
+ $RegularExpressionTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $RegularExpressionTable.Base64 = '^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$' -As [Regex]
+ $RegularExpressionTable.GUID = '(\{){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}' -As [Regex]
+ $RegexOptionList = New-Object -TypeName 'System.Collections.Generic.List[System.Text.RegularExpressions.RegexOptions[]]'
+ $RegexOptionList.Add([System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
+ $RegexOptionList.Add([System.Text.RegularExpressions.RegexOptions]::Multiline)
+
+ [ScriptBlock]$ErrorHandlingDefinition = {
+ $ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $ErrorMessageList.Add('Message', $_.Exception.Message)
+ $ErrorMessageList.Add('Category', $_.Exception.ErrorRecord.FullyQualifiedErrorID)
+ $ErrorMessageList.Add('Script', $_.InvocationInfo.ScriptName)
+ $ErrorMessageList.Add('LineNumber', $_.InvocationInfo.ScriptLineNumber)
+ $ErrorMessageList.Add('LinePosition', $_.InvocationInfo.OffsetInLine)
+ $ErrorMessageList.Add('Code', $_.InvocationInfo.Line.Trim())
+
+ ForEach ($ErrorMessage In $ErrorMessageList.GetEnumerator())
+ {
+ $LoggingDetails.ErrorMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - ERROR: $($ErrorMessage.Key): $($ErrorMessage.Value)"
+ Write-Warning -Message ($LoggingDetails.ErrorMessage)
+ }
+
+ Switch (($ContinueOnError.IsPresent -eq $False) -or ($ContinueOnError -eq $False))
+ {
+ {($_ -eq $True)}
+ {
+ Throw
+ }
+ }
+ }
+
+ $OutputObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
+
+ $OutputObjectValueList = New-Object -TypeName 'System.Collections.Generic.List[String]'
+ $OutputObjectValueList.Add('DisplayName')
+ $OutputObjectValueList.Add('DisplayVersion')
+ $OutputObjectValueList.Add('UninstallString')
+ $OutputObjectValueList.Add('InstallLocation')
+ $OutputObjectValueList.Add('Publisher')
+ $OutputObjectValueList.Add('InstallDate')
+
+ $RegistryHiveList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
+
+ $RegistryHiveProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $RegistryHiveProperties.Add('Type', [Microsoft.Win32.RegistryHive]::LocalMachine)
+ $RegistryHiveProperties.Add('KeyList', (New-Object -TypeName 'System.Collections.Generic.List[String]'))
+ $RegistryHiveProperties.KeyList.Add('Software\Microsoft\Windows\CurrentVersion\Uninstall')
+ $RegistryHiveProperties.KeyList.Add('Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall')
+ $RegistryHiveObject = New-Object -TypeName 'PSObject' -Property ($RegistryHiveProperties)
+ $RegistryHiveList.Add($RegistryHiveObject)
+
+ $RegistryHiveProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $RegistryHiveProperties.Add('Type', [Microsoft.Win32.RegistryHive]::CurrentUser)
+ $RegistryHiveProperties.Add('KeyList', (New-Object -TypeName 'System.Collections.Generic.List[String]'))
+ $RegistryHiveProperties.KeyList.Add('Software\Microsoft\Windows\CurrentVersion\Uninstall')
+ $RegistryHiveObject = New-Object -TypeName 'PSObject' -Property ($RegistryHiveProperties)
+ $RegistryHiveList.Add($RegistryHiveObject)
+
+ For ($RegistryHiveListIndex = 0; $RegistryHiveListIndex -lt $RegistryHiveList.Count; $RegistryHiveListIndex++)
+ {
+ $RegistryHive = $RegistryHiveList[$RegistryHiveListIndex]
+
+ $RegistryHiveObject = [Microsoft.Win32.RegistryKey]::OpenBaseKey($RegistryHive.Type, [Microsoft.Win32.RegistryView]::Default)
+
+ For ($KeyListIndex = 0; $KeyListIndex -lt $RegistryHive.KeyList.Count; $KeyListIndex++)
+ {
+ $RegistryKey = $RegistryHive.KeyList[$KeyListIndex]
+
+ $RegistryKeyObject = $RegistryHiveObject.OpenSubKey($RegistryKey)
+
+ Switch ($Null -ine $RegistryKeyObject)
+ {
+ {($_ -eq $True)}
+ {
+ $SubKeyNameList = $RegistryKeyObject.GetSubKeyNames() | Sort-Object
+
+ For ($SubKeyNameListIndex = 0; $SubKeyNameListIndex -lt $SubKeyNameList.Count; $SubKeyNameListIndex++)
+ {
+ Try
+ {
+ $SubKeyName = $SubKeyNameList[$SubKeyNameListIndex]
+
+ $SubKeyObject = $RegistryKeyObject.OpenSubKey($SubKeyName)
+
+ $SubKeyObjectSegments = $SubKeyObject.Name.Split('\')
+
+ $OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $OutputObjectProperties.Path = $SubKeyObject.Name
+ $OutputObjectProperties.Hive = $SubKeyObjectSegments[0]
+ $OutputObjectProperties.Location = ($SubKeyObjectSegments[1..$($SubKeyObjectSegments.GetUpperBound(0))]) -Join '\'
+
+
+
+ ForEach ($OutputObjectValueName In $OutputObjectValueList)
+ {
+ $OutputObjectProperties.$($OutputObjectValueName) = $Null
+ }
+
+ $ValueNameList = $SubKeyObject.GetValueNames() | Sort-Object
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Now processing entry `"$($OutputObjectProperties.Path)`" [ValueCount: $($ValueNameList.Count)]. Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage)
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Value Name List: $(($ValueNameList | Sort-Object) -Join '; ')"
+ Write-Verbose -Message ($LoggingDetails.LogMessage)
+
+ Switch ($ValueNameList.Count -gt 0)
+ {
+ {($_ -eq $True)}
+ {
+ For ($ValueNameListIndex = 0; $ValueNameListIndex -lt $ValueNameList.Count; $ValueNameListIndex++)
+ {
+ $ValueName = $ValueNameList[$ValueNameListIndex]
+
+ $ValueKind = $SubKeyObject.GetValueKind($ValueName)
+
+ Switch ($ValueKind)
+ {
+ {($_ -ieq 'PlaceHolder')}
+ {
+
+ }
+
+ Default
+ {
+ $Value = $SubKeyObject.GetValue($ValueName)
+ }
+ }
+
+ $OutputObjectProperties.$ValueName = $Value
+ }
+
+ $OutputObjectProperties.ProductCode = Try {[Regex]::Match($OutputObjectProperties.Location, $RegularExpressionTable.GUID.ToString(), $RegexOptionList.ToArray()).Value.Trim()} Catch {$Null}
+
+ Switch (($OutputObjectProperties.DisplayName -imatch $FilterInclusionExpression.ToString()) -and ($OutputObjectProperties.DisplayName -inotmatch $FilterExclusionExpression.ToString()))
+ {
+ {($_ -eq $True)}
+ {
+ ForEach ($OutputObjectProperty In ($OutputObjectProperties.Keys | Sort-Object))
+ {
+ $OutputObjectPropertyName = $OutputObjectProperty
+
+ $OutputObjectPropertyValue = $OutputObjectProperties.$($OutputObjectPropertyName)
+
+ Switch ($OutputObjectPropertyName)
+ {
+ {($_ -iin @('DisplayVersion'))}
+ {
+ $OutputObjectPropertyValue = Try {New-Object -TypeName 'System.Version' -ArgumentList ($OutputObjectPropertyValue)} Catch {$OutputObjectPropertyValue}
+ }
+
+ {($_ -iin @('InstallDate'))}
+ {
+ $DateTime = New-Object -TypeName 'DateTime'
+
+ $DateTimeProperties.Input = $OutputObjectPropertyValue
+ $DateTimeProperties.Successful = [DateTime]::TryParseExact($DateTimeProperties.Input, $DateTimeProperties.FormatList, $DateTimeProperties.Culture, $DateTimeProperties.Styles.ToArray(), [Ref]$DateTime)
+ $DateTimeProperties.DateTime = $DateTime
+
+ $DateTimeObject = New-Object -TypeName 'PSObject' -Property ($DateTimeProperties)
+
+ Switch ($DateTimeObject.Successful)
+ {
+ {($_ -eq $True)}
+ {
+ $OutputObjectPropertyValue = $DateTimeObject.DateTime
+ }
+ }
+ }
+
+ Default
+ {
+ Switch ($OutputObjectPropertyValue)
+ {
+ {($_ -imatch '(^\d+$)')}
+ {
+ $OutputObjectPropertyValue = $OutputObjectPropertyValue -As [Int32]
+ }
+ }
+ }
+ }
+
+ $OutputObjectProperties.Remove($OutputObjectPropertyName)
+
+ $OutputObjectProperties.$($OutputObjectPropertyName) = $OutputObjectPropertyValue
+ }
+
+ $OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties)
+
+ $OutputObjectList.Add($OutputObject)
+ }
+ }
+ }
+ }
+
+ Try {$Null = $SubKeyObject.Close()} Catch {}
+ }
+ Catch
+ {
+
+ }
+ Finally
+ {
+
+ }
+ }
+ }
+ }
+
+ Try {$Null = $RegistryKeyObject.Close()} Catch {}
+ }
+
+ Try {$Null = $RegistryHiveObject.Close()} Catch {}
+ }
+ }
+ Catch
+ {
+ $ErrorHandlingDefinition.Invoke()
+ }
+ Finally
+ {
+
+ }
+ }
+
+ End
+ {
+ Try
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Found $($OutputObjectList.Count) instances of software matching the specified regular expression(s)."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ #Determine the date and time the function completed execution
+ $FunctionEndTime = (Get-Date)
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($FunctionName) ended on $($FunctionEndTime.ToString($DateTimeLogFormat))"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ #Log the total script execution time
+ $FunctionExecutionTimespan = New-TimeSpan -Start ($FunctionStartTime) -End ($FunctionEndTime)
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function execution took $($FunctionExecutionTimespan.Hours.ToString()) hour(s), $($FunctionExecutionTimespan.Minutes.ToString()) minute(s), $($FunctionExecutionTimespan.Seconds.ToString()) second(s), and $($FunctionExecutionTimespan.Milliseconds.ToString()) millisecond(s)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is completed."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ Catch
+ {
+ $ErrorHandlingDefinition.Invoke()
+ }
+ Finally
+ {
+ #Write the object to the powershell pipeline
+ $OutputObjectList = $OutputObjectList.ToArray()
+
+ Write-Output -InputObject ($OutputObjectList)
+ }
+ }
+ }
+#endregion
\ No newline at end of file
diff --git a/Functions/Start-ProcessWithOutput.ps1 b/Functions/Start-ProcessWithOutput.ps1
new file mode 100644
index 0000000..b2ef7ad
--- /dev/null
+++ b/Functions/Start-ProcessWithOutput.ps1
@@ -0,0 +1,288 @@
+#region Start-ProcessWithOutput
+Function Start-ProcessWithOutput
+ {
+ [CmdletBinding()]
+ Param
+ (
+ [Parameter(Mandatory=$True)]
+ [ValidateNotNullOrEmpty()]
+ [String]$FilePath,
+
+ [Parameter(Mandatory=$False)]
+ [AllowEmptyCollection()]
+ [AllowNull()]
+ [String[]]$ArgumentList,
+
+ [Parameter(Mandatory=$False)]
+ [AllowEmptyCollection()]
+ [AllowNull()]
+ [String[]]$AcceptableExitCodeList,
+
+ [Parameter(Mandatory=$False)]
+ [Switch]$CreateNoWindow,
+
+ [Parameter(Mandatory=$False)]
+ [ValidateNotNullOrEmpty()]
+ #[Regex]$StandardOutputParsingExpression = "(?:\s+)(?.+)(?:\s+\:\s+)(?.+)",
+ [Regex]$StandardOutputParsingExpression,
+
+ [Parameter(Mandatory=$False)]
+ [Switch]$LogOutput
+ )
+
+ Try
+ {
+ $DateTimeLogFormat = 'dddd, MMMM dd, yyyy @ hh:mm:ss.FFF tt' ###Monday, January 01, 2019 @ 10:15:34.000 AM###
+ [ScriptBlock]$GetCurrentDateTimeLogFormat = {(Get-Date).ToString($DateTimeLogFormat)}
+
+ $DateTimeMessageFormat = 'MM/dd/yyyy HH:mm:ss.FFF' ###03/23/2022 11:12:48.347###
+ [ScriptBlock]$GetCurrentDateTimeMessageFormat = {(Get-Date).ToString($DateTimeMessageFormat)}
+
+ $DateFileFormat = 'yyyyMMdd' ###20190403###
+ [ScriptBlock]$GetCurrentDateFileFormat = {(Get-Date).ToString($DateFileFormat)}
+
+ $DateTimeFileFormat = 'yyyyMMdd_HHmmss' ###20190403_115354###
+ [ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)}
+
+ $LoggingDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $LoggingDetails.LogMessage = $Null
+ $LoggingDetails.WarningMessage = $Null
+ $LoggingDetails.ErrorMessage = $Null
+
+ $OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $OutputObjectProperties.ExitCode = $Null
+ $OutputObjectProperties.ExitCodeAsHex = $Null
+ $OutputObjectProperties.ExitCodeAsInteger = $Null
+ $OutputObjectProperties.ExitCodeAsDecimal = $Null
+ $OutputObjectProperties.StandardOutput = $Null
+ $OutputObjectProperties.StandardOutputObject = $Null
+ $OutputObjectProperties.StandardError = $Null
+ $OutputObjectProperties.StandardErrorObject = $Null
+
+ $Process = New-Object -TypeName 'System.Diagnostics.Process'
+ $Process.StartInfo.FileName = $FilePath
+ $Process.StartInfo.UseShellExecute = $False
+ $Process.StartInfo.CreateNoWindow = ($CreateNoWindow.IsPresent)
+ $Process.StartInfo.RedirectStandardOutput = $True
+ $Process.StartInfo.RedirectStandardError = $True
+
+ Switch (($Null -ieq $AcceptableExitCodeList) -or ($AcceptableExitCodeList.Count -eq 0))
+ {
+ {($_ -eq $True)}
+ {
+ $AcceptableExitCodeList += '0'
+ }
+ }
+
+ Switch (($Null -ine $ArgumentList) -and ($ArgumentList.Count -gt 0))
+ {
+ {($_ -eq $True)}
+ {
+ $Process.StartInfo.Arguments = $ArgumentList -Join ' '
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to execute the following command: `"$($Process.StartInfo.FileName)`" $($Process.StartInfo.Arguments)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage)
+ }
+
+ Default
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to execute the following command: `"$($Process.StartInfo.FileName)`""
+ Write-Verbose -Message ($LoggingDetails.LogMessage)
+ }
+ }
+
+ $Null = $Process.Start()
+
+ $OutputObjectProperties.StandardOutput = $Process.StandardOutput.ReadToEnd()
+ $OutputObjectProperties.StandardError = $Process.StandardError.ReadToEnd()
+
+ $Null = $Process.WaitForExit()
+
+ $OutputObjectProperties.ExitCode = $Process.ExitCode
+ $OutputObjectProperties.ExitCodeAsHex = Try {'0x' + [System.Convert]::ToString($OutputObjectProperties.ExitCode, 16).PadLeft(8, '0').ToUpper()} Catch {$Null}
+ $OutputObjectProperties.ExitCodeAsInteger = Try {$OutputObjectProperties.ExitCodeAsHex -As [Int]} Catch {$Null}
+ $OutputObjectProperties.ExitCodeAsDecimal = Try {[System.Convert]::ToString($OutputObjectProperties.ExitCodeAsHex, 10)} Catch {$Null}
+
+ $ExitCodeMessageList = New-Object -TypeName 'System.Collections.Generic.List[String]'
+
+ $Null = $OutputObjectProperties.GetEnumerator() | Where-Object {($_.Key -imatch '(^ExitCode.*$)')} | Sort-Object -Property @('Key') | ForEach-Object {$ExitCodeMessageList.Add("[$($_.Key): $($_.Value)]")}
+
+ $StartProcessExecutionTimespan = New-TimeSpan -Start ($Process.StartTime) -End ($Process.ExitTime)
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The command execution took $($StartProcessExecutionTimespan.Hours.ToString()) hour(s), $($StartProcessExecutionTimespan.Minutes.ToString()) minute(s), $($StartProcessExecutionTimespan.Seconds.ToString()) second(s), and $($StartProcessExecutionTimespan.Milliseconds.ToString()) millisecond(s)."
+ Write-Verbose -Message ($LoggingDetails.LogMessage)
+
+ Switch (($OutputObjectProperties.ExitCode.ToString() -iin $AcceptableExitCodeList) -or ($OutputObjectProperties.ExitCodeAsHex.ToString() -iin $AcceptableExitCodeList) -or ($OutputObjectProperties.ExitCodeAsInteger.ToString() -iin $AcceptableExitCodeList) -or ($OutputObjectProperties.ExitCodeAsDecimal.ToString() -iin $AcceptableExitCodeList))
+ {
+ {($_ -eq $True)}
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The command execution was successful. $($ExitCodeMessageList -Join ' ')"
+ Write-Verbose -Message ($LoggingDetails.LogMessage)
+ }
+
+ {($_ -eq $False)}
+ {
+ $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The command execution was unsuccessful. $($ExitCodeMessageList -Join ' ')"
+ Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose
+
+ $ErrorMessage = "$($LoggingDetails.WarningMessage)"
+ $Exception = [System.Exception]::New($ErrorMessage)
+ $ErrorRecord = [System.Management.Automation.ErrorRecord]::New($Exception, [System.Management.Automation.ErrorCategory]::InvalidResult.ToString(), [System.Management.Automation.ErrorCategory]::InvalidResult, $Process)
+
+ $PSCmdlet.ThrowTerminatingError($ErrorRecord)
+ }
+ }
+
+ Switch (($OutputObjectProperties.ExitCode.ToString() -iin $AcceptableExitCodeList) -or ($OutputObjectProperties.ExitCodeAsHex.ToString() -iin $AcceptableExitCodeList) -or ($OutputObjectProperties.ExitCodeAsInteger.ToString() -iin $AcceptableExitCodeList) -or ($OutputObjectProperties.ExitCodeAsDecimal.ToString() -iin $AcceptableExitCodeList))
+ {
+ {($_ -eq $True)}
+ {
+ [String]$CommandContents = $OutputObjectProperties.StandardOutput
+
+ Switch (([String]::IsNullOrEmpty($StandardOutputParsingExpression) -eq $False) -and ([String]::IsNullOrWhiteSpace($StandardOutputParsingExpression) -eq $False))
+ {
+ {($_ -eq $True)}
+ {
+ $RegexOptions = New-Object -TypeName 'System.Collections.Generic.List[System.Text.RegularExpressions.RegexOptions]'
+ $RegexOptions.Add([System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
+ $RegexOptions.Add([System.Text.RegularExpressions.RegexOptions]::Multiline)
+
+ [System.Text.RegularExpressions.Regex]$RegularExpression = [System.Text.RegularExpressions.Regex]::New($StandardOutputParsingExpression, $RegexOptions.ToArray())
+
+ [String[]]$RegularExpressionGroups = $RegularExpression.GetGroupNames() | Where-Object {($_ -notin @('0'))}
+
+ [System.Text.RegularExpressions.MatchCollection]$RegularExpressionMatches = $RegularExpression.Matches($CommandContents)
+
+ $StandardOutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+
+ For ($RegularExpressionMatchIndex = 0; $RegularExpressionMatchIndex -lt $RegularExpressionMatches.Count; $RegularExpressionMatchIndex++)
+ {
+ [System.Text.RegularExpressions.Match]$RegularExpressionMatch = $RegularExpressionMatches[$RegularExpressionMatchIndex]
+
+ For ($RegularExpressionGroupIndex = 0; $RegularExpressionGroupIndex -lt $RegularExpressionGroups.Count; $RegularExpressionGroupIndex++)
+ {
+ [String]$RegularExpressionGroup = $RegularExpressionGroups[$RegularExpressionGroupIndex]
+
+ Switch ($RegularExpressionGroup)
+ {
+ {($_ -imatch '(^PropertyName$)')}
+ {
+ $PropertyDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $PropertyDetails.Add('Name', $Null)
+ $PropertyDetails.Add('Value', $Null)
+
+ $PropertyDetails.Name = ($RegularExpressionMatch.Groups[$($RegularExpressionGroup)].Value) -ireplace '(\s+)|(\-)|(_)', ''
+ }
+
+ {($_ -imatch '(^PropertyValue$)')}
+ {
+ $PropertyDetails.Value = $RegularExpressionMatch.Groups[$($RegularExpressionGroup)].Value
+
+ Switch ($True)
+ {
+ {($PropertyDetails.Value -imatch '\+(\-){1,}\+')}
+ {
+ $PropertyDetails.Value = $Null
+ }
+
+ {($PropertyDetails.Value -imatch '(.+\,\s+.+){1,}')}
+ {
+ #$PropertyDetails.Value = $PropertyDetails.Value.Split(',').Trim()
+ }
+
+ {($PropertyDetails.Value -imatch '.+\(.+\).+')}
+ {
+ #$PropertyDetails.Value = ($PropertyDetails.Value.Split('()', [System.StringSplitOptions]::RemoveEmptyEntries) -ireplace 'bytes', '')[1]
+ }
+ }
+
+ Switch ($Null -ine $PropertyDetails.Value)
+ {
+ {($_ -eq $True)}
+ {
+ $PropertyDetails.Value = $PropertyDetails.Value.Trim()
+ }
+ }
+ }
+ }
+ }
+
+ Switch ($StandardOutputObjectProperties.Contains($PropertyDetails.Name))
+ {
+ {($_ -eq $False)}
+ {
+ $Null = $StandardOutputObjectProperties.Add($PropertyDetails.Name, $PropertyDetails.Value)
+ }
+ }
+ }
+
+ $OutputObjectProperties.StandardOutputObject = New-Object -TypeName 'PSObject' -Property ($StandardOutputObjectProperties)
+ }
+ }
+ }
+ }
+ }
+ Catch
+ {
+ $ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $ErrorMessageList.Add('Message', $_.Exception.Message)
+ $ErrorMessageList.Add('Category', $_.Exception.ErrorRecord.FullyQualifiedErrorID)
+ $ErrorMessageList.Add('Script', $_.InvocationInfo.ScriptName)
+ $ErrorMessageList.Add('LineNumber', $_.InvocationInfo.ScriptLineNumber)
+ $ErrorMessageList.Add('LinePosition', $_.InvocationInfo.OffsetInLine)
+ $ErrorMessageList.Add('Code', $_.InvocationInfo.Line.Trim())
+
+ ForEach ($ErrorMessage In $ErrorMessageList.GetEnumerator())
+ {
+ $LoggingDetails.ErrorMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - ERROR: $($ErrorMessage.Key): $($ErrorMessage.Value)"
+ Write-Warning -Message ($LoggingDetails.ErrorMessage) -Verbose
+ }
+
+ Throw "$($_.Exception.Message)"
+ }
+ Finally
+ {
+ $OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties)
+
+ Switch (($LogOutput.IsPresent -eq $True) -or ($LogOutput -eq $True))
+ {
+ {($_ -eq $True)}
+ {
+ ForEach ($Property In $OutputObject.PSObject.Properties)
+ {
+ Switch ($Property.Name)
+ {
+ {($_ -iin @('StandardOutput', 'StandardError'))}
+ {
+ Switch (([String]::IsNullOrEmpty($Property.Value) -eq $False) -and ([String]::IsNullOrWhiteSpace($Property.Value) -eq $False))
+ {
+ {($_ -eq $True)}
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($Property.Name): $($Property.Value)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+
+ Default
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($Property.Name): N/A"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Write-Output -InputObject ($OutputObject)
+ }
+ }
+#endregion
+
+<#
+ $ProcessOutput = Start-ProcessWithOutput -FilePath 'dsregcmd.exe' -ArgumentList '/status' -CreateNoWindow -Verbose
+
+ $ProcessOutput.StandardOutputObject | ConvertTo-JSON -Depth 10 -OutVariable 'AzureADDetails'
+
+ $ProcessOutput
+#>
\ No newline at end of file
diff --git a/Guides/Place_Guides_Here.txt b/Guides/Place_Guides_Here.txt
new file mode 100644
index 0000000..fa7cc9c
--- /dev/null
+++ b/Guides/Place_Guides_Here.txt
@@ -0,0 +1 @@
+###
\ No newline at end of file
diff --git a/Invoke-OSDApplicationList.ps1 b/Invoke-OSDApplicationList.ps1
new file mode 100644
index 0000000..2486805
--- /dev/null
+++ b/Invoke-OSDApplicationList.ps1
@@ -0,0 +1,944 @@
+#Requires -Version 3
+
+<#
+ .SYNOPSIS
+ Dynamically creates 'MandatoryApplicationXXX' task sequence variables with the GUIDs of MDT application objects to install on a device during operating system deployment.
+
+ .DESCRIPTION
+ Individual applications or entire application folders can be disabled to exclude the application(s) from being considered by the script during deployment.
+
+ Application(s) that have already been installed by the task sequence whose GUID is stored within a 'InstalledApplicationsXXX' variable will be skipped if this script is executed multiple times during a task sequence.
+
+ .PARAMETER ApplicationFolderDefinitionPath
+ A valid path to the ApplicationGroups.xml file stored within the 'Control' folder within a MDT deployment share.
+
+ .PARAMETER ApplicationDefinitionPath
+ A valid path to the Applications.xml file stored within the 'Control' folder within a MDT deployment share.
+
+ .PARAMETER TaskSequenceVariables
+ One or more task sequence variable(s) to retrieve during task sequence execution.
+ If this parameter is not specified, all task sequence variable(s) will be stored into the variable 'TSVariableTable'.
+ Any task sequence variables that are new or have been updated will be saved back to the task sequence engine for futher usage.
+
+ $TSVariable.MyCustomVariableName = "MyCustomVariableValue"
+ $TSVariable.Make = "MyDeviceModel"
+
+ .PARAMETER LogDir
+ A valid folder path. If the folder does not exist, it will be created. This parameter can also be specified by the alias "LogPath".
+
+ .PARAMETER ContinueOnError
+ Ignore failures.
+
+ .PARAMETER DebugMode
+ Allows for testing to see which applications would be deployed without running a task sequence.
+
+ .EXAMPLE
+ Use this command to execute a VBSCript that will launch this powershell script automatically with the specified parameters. This is useful to avoid powershell execution complexities.
+
+ cscript.exe /nologo "%FolderPathContainingScript%\%ScriptName%.vbs" /SwitchParameter /ScriptParameter:"%ScriptParameterValue%" /ScriptParameterArray:"%ScriptParameterValue1%,%ScriptParameterValue2%"
+
+ wscript.exe /nologo "%FolderPathContainingScript%\%ScriptName%.vbs" /SwitchParameter /ScriptParameter:"%ScriptParameterValue%" /ScriptParameterArray:"%ScriptParameterValue1%,%ScriptParameterValue2%"
+
+ .EXAMPLE
+ powershell.exe -ExecutionPolicy Bypass -NoProfile -NoLogo -File "%FolderPathContainingScript%\%ScriptName%.ps1" -SwitchParameter -ScriptParameter "%ScriptParameterValue%"
+
+ .EXAMPLE
+ powershell.exe -ExecutionPolicy Bypass -NonInteractive -NoProfile -NoLogo -WindowStyle Hidden -Command "& '%FolderPathContainingScript%\%ScriptName%.ps1' -ScriptParameter1 '%ScriptParameter1Value%' -ScriptParameter2 %ScriptParameter2Value% -SwitchParameter"
+
+ .NOTES
+ Came up with this concept to keep task sequence modification to an absolute minimum.
+
+ .LINK
+ Place any useful link here where your function or cmdlet can be referenced
+#>
+
+[CmdletBinding(SupportsShouldProcess=$True)]
+ Param
+ (
+ [Parameter(Mandatory=$False)]
+ [ValidateNotNullOrEmpty()]
+ [Alias('AFDP')]
+ [System.IO.FileInfo]$ApplicationFolderDefinitionPath,
+
+ [Parameter(Mandatory=$False)]
+ [ValidateNotNullOrEmpty()]
+ [Alias('ADP')]
+ [System.IO.FileInfo]$ApplicationDefinitionPath,
+
+ [Parameter(Mandatory=$False)]
+ [ValidateNotNullOrEmpty()]
+ [Alias('TSVars', 'TSVs')]
+ [String[]]$TaskSequenceVariables,
+
+ [Parameter(Mandatory=$False)]
+ [ValidateNotNullOrEmpty()]
+ [Alias('LogDir', 'LogPath')]
+ [System.IO.DirectoryInfo]$LogDirectory,
+
+ [Parameter(Mandatory=$False)]
+ [Switch]$ContinueOnError,
+
+ [Parameter(Mandatory=$False)]
+ [Switch]$DebugMode
+ )
+
+Function Get-AdministrativePrivilege
+ {
+ $Identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
+ $Principal = New-Object System.Security.Principal.WindowsPrincipal($Identity)
+ Write-Output -InputObject ($Principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator))
+ }
+
+If ((Get-AdministrativePrivilege) -eq $False)
+ {
+ [System.IO.FileInfo]$ScriptPath = "$($MyInvocation.MyCommand.Path)"
+
+ $ArgumentList = New-Object -TypeName 'System.Collections.Generic.List[String]'
+ $ArgumentList.Add('-ExecutionPolicy Bypass')
+ $ArgumentList.Add('-NoProfile')
+ $ArgumentList.Add('-NoExit')
+ $ArgumentList.Add('-NoLogo')
+ $ArgumentList.Add("-File `"$($ScriptPath.FullName)`"")
+
+ $Null = Start-Process -FilePath "$([System.Environment]::SystemDirectory)\WindowsPowershell\v1.0\powershell.exe" -WorkingDirectory "$([System.Environment]::SystemDirectory)" -ArgumentList ($ArgumentList.ToArray()) -WindowStyle Normal -Verb RunAs -PassThru
+ }
+Else
+ {
+ #Determine the date and time we executed the function
+ $ScriptStartTime = (Get-Date)
+
+ #Define Default Action Preferences
+ $Script:DebugPreference = 'SilentlyContinue'
+ $Script:ErrorActionPreference = 'Stop'
+ $Script:VerbosePreference = 'SilentlyContinue'
+ $Script:WarningPreference = 'Continue'
+ $Script:ConfirmPreference = 'None'
+ $Script:WhatIfPreference = $False
+
+ #Load WMI Classes
+ $Baseboard = Get-WmiObject -Namespace "root\CIMv2" -Class "Win32_Baseboard" -Property *
+ $Bios = Get-WmiObject -Namespace "root\CIMv2" -Class "Win32_Bios" -Property *
+ $ComputerSystem = Get-WmiObject -Namespace "root\CIMv2" -Class "Win32_ComputerSystem" -Property *
+ $OperatingSystem = Get-WmiObject -Namespace "root\CIMv2" -Class "Win32_OperatingSystem" -Property *
+ $MSSystemInformation = Get-WmiObject -Namespace "root\WMI" -Class "MS_SystemInformation" -Property *
+
+ #Retrieve property values
+ $OSArchitecture = $($OperatingSystem.OSArchitecture).Replace("-bit", "").Replace("32", "86").Insert(0,"x").ToUpper()
+
+ #Define variable(s)
+ $DateTimeLogFormat = 'dddd, MMMM dd, yyyy @ hh:mm:ss.FFF tt' ###Monday, January 01, 2019 @ 10:15:34.000 AM###
+ [ScriptBlock]$GetCurrentDateTimeLogFormat = {(Get-Date).ToString($DateTimeLogFormat)}
+ $DateTimeMessageFormat = 'MM/dd/yyyy HH:mm:ss.FFF' ###03/23/2022 11:12:48.347###
+ [ScriptBlock]$GetCurrentDateTimeMessageFormat = {(Get-Date).ToString($DateTimeMessageFormat)}
+ $DateFileFormat = 'yyyyMMdd' ###20190403###
+ [ScriptBlock]$GetCurrentDateFileFormat = {(Get-Date).ToString($DateFileFormat)}
+ $DateTimeFileFormat = 'yyyyMMdd_HHmmss' ###20190403_115354###
+ [ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)}
+ [System.IO.FileInfo]$ScriptPath = "$($MyInvocation.MyCommand.Definition)"
+ [System.IO.DirectoryInfo]$ScriptDirectory = "$($ScriptPath.Directory.FullName)"
+ [System.IO.DirectoryInfo]$ContentDirectory = "$($ScriptDirectory.FullName)\Content"
+ [System.IO.DirectoryInfo]$FunctionsDirectory = "$($ScriptDirectory.FullName)\Functions"
+ [System.IO.DirectoryInfo]$ModulesDirectory = "$($ScriptDirectory.FullName)\Modules"
+ [System.IO.DirectoryInfo]$ToolsDirectory = "$($ScriptDirectory.FullName)\Tools"
+ [System.IO.DirectoryInfo]$ToolsDirectory_OSAll = "$($ToolsDirectory.FullName)\All"
+ [System.IO.DirectoryInfo]$ToolsDirectory_OSArchSpecific = "$($ToolsDirectory.FullName)\$($OSArchitecture)"
+ [System.IO.DirectoryInfo]$System32Directory = [System.Environment]::SystemDirectory
+ [System.IO.DirectoryInfo]$ProgramFilesDirectory = "$($Env:SystemDrive)\Program Files"
+ [System.IO.DirectoryInfo]$ProgramFilesx86Directory = "$($Env:SystemDrive)\Program Files (x86)"
+ [System.IO.FileInfo]$PowershellPath = "$($System32Directory.FullName)\WindowsPowershell\v1.0\powershell.exe"
+ [System.IO.DirectoryInfo]$System32Directory = "$([System.Environment]::SystemDirectory)"
+ $IsWindowsPE = Test-Path -Path 'HKLM:\SYSTEM\ControlSet001\Control\MiniNT' -ErrorAction SilentlyContinue
+ [System.Text.RegularExpressions.RegexOptions[]]$RegexOptions = [System.Text.RegularExpressions.RegexOptions]::IgnoreCase, [System.Text.RegularExpressions.RegexOptions]::Multiline
+ [ScriptBlock]$GetRandomGUID = {[System.GUID]::NewGUID().GUID.ToString().ToUpper()}
+ [String]$ParameterSetName = "$($PSCmdlet.ParameterSetName)"
+ $TextInfo = (Get-Culture).TextInfo
+ $Script:LASTEXITCODE = 0
+ $TerminationCodes = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $TerminationCodes.Add('Success', @(0))
+ $TerminationCodes.Add('Warning', @(5000..5999))
+ $TerminationCodes.Add('Error', @(6000..6999))
+ $Script:WarningCodeIndex = 0
+ [ScriptBlock]$GetAvailableWarningCode = {$TerminationCodes.Warning[$Script:WarningCodeIndex]; $Script:WarningCodeIndex++}
+ $Script:ErrorCodeIndex = 0
+ [ScriptBlock]$GetAvailableErrorCode = {$TerminationCodes.Error[$Script:ErrorCodeIndex]; $Script:ErrorCodeIndex++}
+ $LoggingDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $LoggingDetails.Add('LogMessage', $Null)
+ $LoggingDetails.Add('WarningMessage', $Null)
+ $LoggingDetails.Add('ErrorMessage', $Null)
+ $RegularExpressionTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $RegularExpressionTable.Base64 = '^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$' -As [Regex]
+ $CommonParameterList = New-Object -TypeName 'System.Collections.Generic.List[String]'
+ $CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::CommonParameters)
+ $CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::OptionalCommonParameters)
+
+ #Define the error handling definition
+ [ScriptBlock]$ErrorHandlingDefinition = {
+ If (($Null -ieq $Script:LASTEXITCODE) -or ($Script:LASTEXITCODE -eq 0))
+ {
+ [Int]$Script:LASTEXITCODE = $GetAvailableErrorCode.InvokeReturnAsIs()
+ }
+
+ $ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $ErrorMessageList.Add('Message', $_.Exception.Message)
+ $ErrorMessageList.Add('Category', $_.Exception.ErrorRecord.FullyQualifiedErrorID)
+ $ErrorMessageList.Add('ExitCode', $Script:LASTEXITCODE)
+ $ErrorMessageList.Add('Script', $_.InvocationInfo.ScriptName)
+ $ErrorMessageList.Add('LineNumber', $_.InvocationInfo.ScriptLineNumber)
+ $ErrorMessageList.Add('LinePosition', $_.InvocationInfo.OffsetInLine)
+ $ErrorMessageList.Add('Code', $_.InvocationInfo.Line.Trim())
+
+ ForEach ($ErrorMessage In $ErrorMessageList.GetEnumerator())
+ {
+ $LoggingDetails.ErrorMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - ERROR: $($ErrorMessage.Key): $($ErrorMessage.Value)"
+ Write-Warning -Message ($LoggingDetails.ErrorMessage) -Verbose
+ }
+
+ Switch (($ContinueOnError.IsPresent -eq $False) -or ($ContinueOnError -eq $False))
+ {
+ {($_ -eq $True)}
+ {
+ Throw
+ }
+ }
+ }
+
+ #Log task sequence variables if debug mode is enabled within the task sequence
+ Try
+ {
+ [System.__ComObject]$TSEnvironment = New-Object -ComObject "Microsoft.SMS.TSEnvironment"
+
+ If ($Null -ine $TSEnvironment)
+ {
+ $IsRunningTaskSequence = $True
+
+ [Boolean]$IsConfigurationManagerTaskSequence = [String]::IsNullOrEmpty($TSEnvironment.Value("_SMSTSPackageID")) -eq $False
+
+ Switch ($IsConfigurationManagerTaskSequence)
+ {
+ {($_ -eq $True)}
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A Microsoft Endpoint Configuration Manager (MECM) task sequence was detected."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+
+ {($_ -eq $False)}
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A Microsoft Deployment Toolkit (MDT) task sequence was detected."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ }
+ }
+ }
+ Catch
+ {
+ $IsRunningTaskSequence = $False
+ }
+
+ #Determine default parameter value(s)
+ Switch ($True)
+ {
+ {([String]::IsNullOrEmpty($LogDirectory) -eq $True) -or ([String]::IsNullOrWhiteSpace($LogDirectory) -eq $True)}
+ {
+ Switch ($IsRunningTaskSequence)
+ {
+ {($_ -eq $True)}
+ {
+ Switch ($IsConfigurationManagerTaskSequence)
+ {
+ {($_ -eq $True)}
+ {
+ [String]$_SMSTSLogPath = "$($TSEnvironment.Value('_SMSTSLogPath'))"
+ }
+
+ {($_ -eq $False)}
+ {
+ [String]$_SMSTSLogPath = "$($TSEnvironment.Value('LogPath'))"
+ }
+ }
+
+ Switch ([String]::IsNullOrEmpty($_SMSTSLogPath))
+ {
+ {($_ -eq $True)}
+ {
+ [System.IO.DirectoryInfo]$TSLogDirectory = "$($Env:Windir)\Temp\SMSTSLog"
+ }
+
+ {($_ -eq $False)}
+ {
+ Switch ($True)
+ {
+ {(Test-Path -Path ($_SMSTSLogPath) -PathType Container)}
+ {
+ [System.IO.DirectoryInfo]$TSLogDirectory = ($_SMSTSLogPath)
+ }
+
+ {(Test-Path -Path ($_SMSTSLogPath) -PathType Leaf)}
+ {
+ [System.IO.DirectoryInfo]$TSLogDirectory = Split-Path -Path ($_SMSTSLogPath) -Parent
+ }
+ }
+ }
+ }
+
+ [System.IO.DirectoryInfo]$LogDirectory = "$($TSLogDirectory.FullName)\$($ScriptPath.BaseName)"
+ }
+
+ {($_ -eq $False)}
+ {
+ Switch ($IsWindowsPE)
+ {
+ {($_ -eq $True)}
+ {
+ [System.IO.FileInfo]$MDTBootImageDetectionPath = "$($Env:SystemDrive)\Deploy\Scripts\Litetouch.wsf"
+
+ [Boolean]$MDTBootImageDetected = Test-Path -Path ($MDTBootImageDetectionPath.FullName)
+
+ Switch ($MDTBootImageDetected)
+ {
+ {($_ -eq $True)}
+ {
+ [System.IO.DirectoryInfo]$LogDirectory = "$($Env:SystemDrive)\MININT\SMSOSD\OSDLOGS\$($ScriptPath.BaseName)"
+ }
+
+ {($_ -eq $False)}
+ {
+ [System.IO.DirectoryInfo]$LogDirectory = "$($Env:Windir)\Temp\SMSTSLog"
+ }
+ }
+ }
+
+ {($_ -eq $False)}
+ {
+ [System.IO.DirectoryInfo]$LogDirectory = "$($Env:Windir)\Logs\Software\$($ScriptPath.BaseName)"
+ }
+ }
+ }
+ }
+ }
+ }
+
+ #Start transcripting (Logging)
+ [System.IO.FileInfo]$ScriptLogPath = "$($LogDirectory.FullName)\$($ScriptPath.BaseName)_$($GetCurrentDateFileFormat.Invoke()).log"
+ If ($ScriptLogPath.Directory.Exists -eq $False) {$Null = [System.IO.Directory]::CreateDirectory($ScriptLogPath.Directory.FullName)}
+ Start-Transcript -Path "$($ScriptLogPath.FullName)" -Force -WhatIf:$False
+
+ #Log any useful information
+ [String]$CmdletName = $MyInvocation.MyCommand.Name
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of script `"$($CmdletName)`" began on $($ScriptStartTime.ToString($DateTimeLogFormat))"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Script Path = $($ScriptPath.FullName)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ [String[]]$AvailableScriptParameters = (Get-Command -Name ($ScriptPath.FullName)).Parameters.GetEnumerator() | Where-Object {($_.Value.Name -inotin $CommonParameterList)} | ForEach-Object {"-$($_.Value.Name):$($_.Value.ParameterType.Name)"}
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Available Script Parameter(s) = $($AvailableScriptParameters -Join ', ')"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ [String[]]$SuppliedScriptParameters = $PSBoundParameters.GetEnumerator() | ForEach-Object {"-$($_.Key):$($_.Value.GetType().Name)"}
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Supplied Script Parameter(s) = $($SuppliedScriptParameters -Join ', ')"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ Switch ($True)
+ {
+ {([String]::IsNullOrEmpty($ParameterSetName) -eq $False)}
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Parameter Set Name = $($ParameterSetName)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ }
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Command Line: $((Get-WMIObject -Namespace 'Root\CIMv2' -Class 'Win32_Process' -Filter "ProcessID = $($PID)").CommandLine)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($PSBoundParameters.Count) command line parameter(s) were specified."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $OperatingSystemDetailsTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $OperatingSystemDetailsTable.ProductName = $OperatingSystem.Caption -ireplace '(Microsoft\s+)', ''
+ $OperatingSystemDetailsTable.Version = $OperatingSystem.Version
+ $OperatingSystemDetailsTable.Architecture = $OperatingSystem.OSArchitecture
+
+ $OperatingSystemRegistryDetails = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
+ $OperatingSystemRegistryDetails.Add((New-Object -TypeName 'PSObject' -Property @{Alias = ''; Path = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'; ValueName = 'UBR'; Value = $Null}))
+ $OperatingSystemRegistryDetails.Add((New-Object -TypeName 'PSObject' -Property @{Alias = 'ReleaseVersion'; Path = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'; ValueName = 'ReleaseID'; Value = $Null}))
+ $OperatingSystemRegistryDetails.Add((New-Object -TypeName 'PSObject' -Property @{Alias = 'ReleaseID'; Path = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'; ValueName = 'DisplayVersion'; Value = $Null}))
+
+ ForEach ($OperatingSystemRegistryDetail In $OperatingSystemRegistryDetails)
+ {
+ $OperatingSystemRegistryDetail.Value = Try {(Get-Item -Path $OperatingSystemRegistryDetail.Path).GetValue($OperatingSystemRegistryDetail.ValueName)} Catch {}
+
+ :NextOSDetail Switch (([String]::IsNullOrEmpty($OperatingSystemRegistryDetail.Value) -eq $False) -and ([String]::IsNullOrWhiteSpace($OperatingSystemRegistryDetail.Value) -eq $False))
+ {
+ {($_ -eq $True)}
+ {
+ Switch ($OperatingSystemRegistryDetail.ValueName)
+ {
+ {($_ -ieq 'UBR')}
+ {
+ $OperatingSystemDetailsTable.Version = $OperatingSystemDetailsTable.Version + '.' + $OperatingSystemRegistryDetail.Value
+
+ Break NextOSDetail
+ }
+ }
+
+ Switch (([String]::IsNullOrEmpty($OperatingSystemRegistryDetail.Alias) -eq $False) -and ([String]::IsNullOrWhiteSpace($OperatingSystemRegistryDetail.Alias) -eq $False))
+ {
+ {($_ -eq $True)}
+ {
+ $OperatingSystemDetailsTable.$($OperatingSystemRegistryDetail.Alias) = $OperatingSystemRegistryDetail.Value
+ }
+
+ Default
+ {
+ $OperatingSystemDetailsTable.$($OperatingSystemRegistryDetail.ValueName) = $OperatingSystemRegistryDetail.Value
+ }
+ }
+ }
+
+ Default
+ {
+ $OperatingSystemDetailsTable.$($OperatingSystemRegistryDetail.ValueName) = $OperatingSystemRegistryDetail.Value
+ }
+ }
+ }
+
+ ForEach ($OperatingSystemDetail In $OperatingSystemDetailsTable.GetEnumerator())
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($OperatingSystemDetail.Key): $($OperatingSystemDetail.Value)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Powershell Version: $($PSVersionTable.PSVersion.ToString())"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $ExecutionPolicyList = Get-ExecutionPolicy -List
+
+ For ($ExecutionPolicyListIndex = 0; $ExecutionPolicyListIndex -lt $ExecutionPolicyList.Count; $ExecutionPolicyListIndex++)
+ {
+ $ExecutionPolicy = $ExecutionPolicyList[$ExecutionPolicyListIndex]
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The powershell execution policy is currently set to `"$($ExecutionPolicy.ExecutionPolicy.ToString())`" for the `"$($ExecutionPolicy.Scope.ToString())`" scope."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+
+ #Log hardware information
+ $MSSystemInformationMembers = $MSSystemInformation.PSObject.Properties | Where-Object {($_.MemberType -imatch '^NoteProperty$|^Property$') -and ($_.Name -imatch '^Base.*|Bios.*|System.*$') -and ($_.Name -inotmatch '^.*Major.*|.*Minor.*|.*Properties.*$')} | Sort-Object -Property @('Name')
+
+ Switch ($MSSystemInformationMembers.Count -gt 0)
+ {
+ {($_ -eq $True)}
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to display device information properties from the `"$($MSSystemInformation.__CLASS)`" WMI class located within the `"$($MSSystemInformation.__NAMESPACE)`" WMI namespace. Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ ForEach ($MSSystemInformationMember In $MSSystemInformationMembers)
+ {
+ [String]$MSSystemInformationMemberName = ($MSSystemInformationMember.Name)
+ [String]$MSSystemInformationMemberValue = $MSSystemInformation.$($MSSystemInformationMemberName)
+
+ Switch ([String]::IsNullOrEmpty($MSSystemInformationMemberValue))
+ {
+ {($_ -eq $False)}
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($MSSystemInformationMemberName) = $($MSSystemInformationMemberValue)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ }
+ }
+ }
+
+ Default
+ {
+ $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The `"MSSystemInformation`" WMI class could not be found."
+ Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose
+ }
+ }
+
+ #region Log Cleanup
+ [Int]$MaximumLogHistory = 3
+
+ $LogList = Get-ChildItem -Path ($LogDirectory.FullName) -Filter "$($ScriptPath.BaseName)_*" -Recurse -Force | Where-Object {($_ -is [System.IO.FileInfo])}
+
+ $SortedLogList = $LogList | Sort-Object -Property @('LastWriteTime') -Descending | Select-Object -Skip ($MaximumLogHistory)
+
+ Switch ($SortedLogList.Count -gt 0)
+ {
+ {($_ -eq $True)}
+ {
+ $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - There are $($SortedLogList.Count) log file(s) requiring cleanup."
+ Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose
+
+ For ($SortedLogListIndex = 0; $SortedLogListIndex -lt $SortedLogList.Count; $SortedLogListIndex++)
+ {
+ Try
+ {
+ $Log = $SortedLogList[$SortedLogListIndex]
+
+ $LogAge = New-TimeSpan -Start ($Log.LastWriteTime) -End (Get-Date)
+
+ $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to cleanup log file `"$($Log.FullName)`". Please Wait... [Last Modified: $($Log.LastWriteTime.ToString($DateTimeMessageFormat))] [Age: $($LogAge.Days.ToString()) day(s); $($LogAge.Hours.ToString()) hours(s); $($LogAge.Minutes.ToString()) minute(s); $($LogAge.Seconds.ToString()) second(s)]."
+ Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose
+
+ $Null = [System.IO.File]::Delete($Log.FullName)
+ }
+ Catch
+ {
+
+ }
+ }
+ }
+
+ Default
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - There are $($SortedLogList.Count) log file(s) requiring cleanup."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ }
+ #endregion
+
+ #region Import Dependency Modules
+ If (($ModulesDirectory.Exists -eq $True) -and ($ModulesDirectory.GetDirectories().Count -gt 0))
+ {
+ $Modules = Get-Module -Name "$($ModulesDirectory.FullName)\*" -ListAvailable -ErrorAction Stop
+
+ $ModuleGroups = $Modules | Group-Object -Property @('Name')
+
+ ForEach ($ModuleGroup In $ModuleGroups)
+ {
+ $LatestModuleVersion = $ModuleGroup.Group | Sort-Object -Property @('Version') -Descending | Select-Object -First 1
+
+ If ($Null -ine $LatestModuleVersion)
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to import dependency powershell module `"$($LatestModuleVersion.Name)`" [Version: $($LatestModuleVersion.Version.ToString())]. Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ Import-Module -Name "$($LatestModuleVersion.Path)" -Global -DisableNameChecking -Force -ErrorAction Stop
+ }
+ }
+ }
+ #endregion
+
+ #region Dot Source Dependency Scripts
+ #Dot source any additional script(s) from the functions directory. This will provide flexibility to add additional functions without adding complexity to the main script and to maintain function consistency.
+ Try
+ {
+ If ($FunctionsDirectory.Exists -eq $True)
+ {
+ $AdditionalFunctionsFilter = New-Object -TypeName 'System.Collections.Generic.List[String]'
+ $AdditionalFunctionsFilter.Add('*.ps1')
+
+ $AdditionalFunctionsToImport = Get-ChildItem -Path "$($FunctionsDirectory.FullName)" -Include ($AdditionalFunctionsFilter) -Recurse -Force | Where-Object {($_ -is [System.IO.FileInfo])}
+
+ $AdditionalFunctionsToImportCount = $AdditionalFunctionsToImport | Measure-Object | Select-Object -ExpandProperty Count
+
+ If ($AdditionalFunctionsToImportCount -gt 0)
+ {
+ ForEach ($AdditionalFunctionToImport In $AdditionalFunctionsToImport)
+ {
+ Try
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to dot source the functions contained within the dependency script `"$($AdditionalFunctionToImport.Name)`". Please Wait... [Script Path: `"$($AdditionalFunctionToImport.FullName)`"]"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ . "$($AdditionalFunctionToImport.FullName)"
+ }
+ Catch
+ {
+ $ErrorHandlingDefinition.Invoke()
+ }
+ }
+ }
+ }
+ }
+ Catch
+ {
+ $ErrorHandlingDefinition.Invoke()
+ }
+ #endregion
+
+ #region Load any required libraries
+ [System.IO.DirectoryInfo]$LibariesDirectory = "$($FunctionsDirectory.FullName)\Libraries"
+
+ Switch ([System.IO.Directory]::Exists($LibariesDirectory.FullName))
+ {
+ {($_ -eq $True)}
+ {
+ $LibraryPatternList = New-Object -TypeName 'System.Collections.Generic.List[String]'
+ #$LibraryPatternList.Add('')
+
+ Switch ($LibraryPatternList.Count -gt 0)
+ {
+ {($_ -eq $True)}
+ {
+ $LibraryList = Get-ChildItem -Path ($LibariesDirectory.FullName) -Include ($LibraryPatternList.ToArray()) -Recurse -Force | Where-Object {($_ -is [System.IO.FileInfo])}
+
+ $LibraryListCount = ($LibraryList | Measure-Object).Count
+
+ Switch ($LibraryListCount -gt 0)
+ {
+ {($_ -eq $True)}
+ {
+ For ($LibraryListIndex = 0; $LibraryListIndex -lt $LibraryListCount; $LibraryListIndex++)
+ {
+ $Library = $LibraryList[$LibraryListIndex]
+
+ [Byte[]]$LibraryBytes = [System.IO.File]::ReadAllBytes($Library.FullName)
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to load assembly `"$($Library.FullName)`". Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $Null = [System.Reflection.Assembly]::Load($LibraryBytes)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ #endregion
+
+ #Perform script action(s)
+ Try
+ {
+ $GetInstalledSoftwareParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $GetInstalledSoftwareParameters.FilterInclusionExpression = "(.*)"
+ $GetInstalledSoftwareParameters.FilterExclusionExpression = "(^.{0,0}$)"
+ $GetInstalledSoftwareParameters.ContinueOnError = $True
+ $GetInstalledSoftwareParameters.Verbose = $False
+
+ $InstalledSoftwareList = Get-InstalledSoftware @GetInstalledSoftwareParameters
+
+ #If necessary, create, get, and or set any task sequence variable(s).
+ Switch (($IsRunningTaskSequence -eq $True) -or ($DebugMode.IsPresent -eq $True))
+ {
+ {($_ -eq $True)}
+ {
+ Try
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A task sequence is currently running."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $TSVariableTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+
+ $TaskSequenceVariableRetrievalList = New-Object -TypeName 'System.Collections.Generic.List[String]'
+
+ Switch ($TaskSequenceVariables.Count -gt 0)
+ {
+ {($_ -eq $True)}
+ {
+ ForEach ($TaskSequenceVariable In $TaskSequenceVariables)
+ {
+ $TaskSequenceVariableRetrievalList.Add($TaskSequenceVariable)
+ }
+ }
+ }
+
+ $TSVariableTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to retrieve the task sequence variable list. Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ Switch ($TaskSequenceVariableRetrievalList.Count -gt 0)
+ {
+ {($_ -eq $True)}
+ {
+ $TSVariableList = $TSEnvironment.GetVariables() | Where-Object {($_ -iin $TaskSequenceVariableRetrievalList)} | Sort-Object
+ }
+
+ Default
+ {
+ $TSVariableList = $TSEnvironment.GetVariables() | Sort-Object
+ }
+ }
+
+ ForEach ($TSVariable In $TSVariableList)
+ {
+ $TSVariableName = $TSVariable
+ $TSVariableValue = $TSEnvironment.Value($TSVariableName)
+
+ Switch ($True)
+ {
+ {($TSVariableName -inotmatch '(^_SMSTSTaskSequence$)|(^TaskSequence$)|(^.*Pass.*word.*$)')}
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to retrieve the value of task sequence variable `"$($TSVariableName)`". Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+
+ {($TSVariableTable.Contains($TSVariableName) -eq $False)}
+ {
+ $TSVariableTable.Add($TSVariableName, $TSVariableValue)
+ }
+ }
+ }
+
+ $InstalledApplicationDictionary = $TSVariableTable.GetEnumerator() | Where-Object {($_.Key -imatch '(^InstalledApplications\d{3,3}$)')}
+
+ $InstalledApplicationDictionaryCount = ($InstalledApplicationDictionary | Measure-Object).Count
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($InstalledApplicationDictionaryCount) application(s) have already been installed on `"$($Env:ComputerName.ToUpper())`" during task sequence `"$($TSVariableTable.TASKSEQUENCENAME)`"."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ Catch
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - [Error Message: $($_.Exception.Message)] [Code: $($_.InvocationInfo.Line.Trim())] [Line Number: $($_.InvocationInfo.ScriptLineNumber)] [Line Position: $($_.InvocationInfo.OffsetInLine)]"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ Finally
+ {
+
+ }
+ }
+ }
+
+ Switch (($IsRunningTaskSequence -eq $True) -or ($DebugMode.IsPresent -eq $True))
+ {
+ {($_ -eq $True)}
+ {
+ #Set default parameter values
+ Switch ($True)
+ {
+ {([String]::IsNullOrEmpty($ApplicationFolderDefinitionPath) -eq $True) -or ([String]::IsNullOrWhiteSpace($ApplicationFolderDefinitionPath) -eq $True)}
+ {
+ [System.IO.FileInfo]$ApplicationFolderDefinitionPath = "$($TSVariableTable.DEPLOYROOT)\Control\ApplicationGroups.xml"
+ }
+
+ {([String]::IsNullOrEmpty($ApplicationDefinitionPath) -eq $True) -or ([String]::IsNullOrWhiteSpace($ApplicationDefinitionPath) -eq $True)}
+ {
+ [System.IO.FileInfo]$ApplicationDefinitionPath = "$($TSVariableTable.DEPLOYROOT)\Control\Applications.xml"
+ }
+ }
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Application Folder Defintion Path: $($ApplicationFolderDefinitionPath.FullName)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Application Definition Path: $($ApplicationDefinitionPath.FullName)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ Switch ([System.IO.File]::Exists($ApplicationFolderDefinitionPath.FullName))
+ {
+ {($_ -eq $True)}
+ {
+ Switch ([System.IO.File]::Exists($ApplicationDefinitionPath.FullName))
+ {
+ {($_ -eq $True)}
+ {
+ $ApplicationFolderDefinitionContents = [System.IO.File]::ReadAllText($ApplicationFolderDefinitionPath.FullName)
+
+ $ApplicationFolderDefinition = New-Object -TypeName 'System.Xml.XmlDocument'
+ $ApplicationFolderDefinition.LoadXml($ApplicationFolderDefinitionContents)
+
+ $ApplicationFolderObjectList = $ApplicationFolderDefinition.groups.group | Where-Object {($_.Enable -eq $True)}
+
+ $ApplicationDefinitionContents = [System.IO.File]::ReadAllText($ApplicationDefinitionPath.FullName)
+
+ $ApplicationDefinition = New-Object -TypeName 'System.Xml.XmlDocument'
+ $ApplicationDefinition.LoadXml($ApplicationDefinitionContents)
+
+ $AvailableApplicationList = $ApplicationDefinition.applications.application | Where-Object {($_.Enable -eq $True) -and ($ApplicationFolderObjectList.Member -icontains $_.GUID)} | Sort-Object -Property @{Expression = {Try {($_.Version -As [Int])} Catch {($_.Version)}}}
+
+ Switch ($InstalledApplicationDictionaryCount -gt 0)
+ {
+ {($_ -eq $True)}
+ {
+ $InstalledApplicationList = $AvailableApplicationList | Where-Object {($InstalledApplicationList.Value -icontains $_.GUID)}
+
+ ForEach ($InstalledApplication In $InstalledApplicationList)
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Application `"$($InstalledApplication.Name)`" [GUID: $($InstalledApplication.GUID.ToUpper())] has already been installed on `"$($Env:ComputerName.ToUpper())`" and will be removed from the available application list."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+
+ $AvailableApplicationList = $AvailableApplicationList | Where-Object {($InstalledApplicationDictionary.Value -inotcontains $_.GUID)}
+ }
+ }
+
+ $ApplicationObjectList = New-Object -TypeName 'System.Collections.Generic.List[Object]'
+
+ For ($AvailableApplicationListIndex = 0; $AvailableApplicationListIndex -lt $AvailableApplicationList.Count; $AvailableApplicationListIndex++)
+ {
+ $AvailableApplication = $AvailableApplicationList[$AvailableApplicationListIndex]
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Adding available application `"$($AvailableApplication.Name)`" to the available application list. Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $ApplicationObjectList.Add($AvailableApplication)
+ }
+
+ [Int]$ApplicationVariableCounter = 1
+
+ For ($ApplicationObjectListIndex = 0; $ApplicationObjectListIndex -lt $ApplicationObjectList.Count; $ApplicationObjectListIndex++)
+ {
+ Try
+ {
+ $ApplicationObject = $ApplicationObjectList[$ApplicationObjectListIndex]
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to determine the applicability of application object `"$($ApplicationObject.Name)`". Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $ApplicationObjectConfiguration = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $ApplicationObjectConfiguration.Applicable = $False
+
+ $ApplicationApplicabilityConditionContent = $ApplicationObject.Language
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Application Applicability Condition: $($ApplicationApplicabilityConditionContent)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ Switch ($ApplicationApplicabilityConditionContent -imatch '.*\$.*')
+ {
+ {($_ -eq $True)}
+ {
+ $ApplicationApplicabilityCondition = [ScriptBlock]::Create($ApplicationApplicabilityConditionContent)
+
+ $ApplicationObjectConfiguration.Applicable = $ApplicationApplicabilityCondition.InvokeReturnAsIs()
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Application Applicability Condition Result: `$$($ApplicationObjectConfiguration.Applicable)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ Switch ($ApplicationObjectConfiguration.Applicable)
+ {
+ {($_ -eq $True)}
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Application object `"$($ApplicationObject.Name)`" is applicable and WILL be installed."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $ApplicationInstallationDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $ApplicationInstallationDetails.Number = $ApplicationVariableCounter++
+ $ApplicationInstallationDetails.TSVariableName = 'MandatoryApplications' + $ApplicationInstallationDetails.Number.ToString('000')
+ $ApplicationInstallationDetails.TSVariableValue = $ApplicationObject.GUID.ToUpper()
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to add `"$($ApplicationObject.Name)`" to the application installation list. Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Task Sequence Variable: $($ApplicationInstallationDetails.TSVariableName)=$($ApplicationInstallationDetails.TSVariableValue)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $TSVariableTable."$($ApplicationInstallationDetails.TSVariableName)" = $ApplicationInstallationDetails.TSVariableValue
+ }
+
+ Default
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Application object `"$($ApplicationObject.Name)`" is NOT applicable and will NOT be installed."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ }
+ }
+
+ Default
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The application applicability could not determined. Skipping..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ Continue
+ }
+ }
+ }
+ Catch
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Application: `"$($ApplicationObject.Name)`" [Error Message: $($_.Exception.Message)] [Code: $($_.InvocationInfo.Line.Trim())] [Line Number: $($_.InvocationInfo.ScriptLineNumber)] [Line Position: $($_.InvocationInfo.OffsetInLine)]"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ Finally
+ {
+
+ }
+ }
+ }
+
+ Default
+ {
+ $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Application definition file `"$($ApplicationDefinitionPath.FullName)`" does not exist."
+ Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose
+ }
+ }
+ }
+
+ Default
+ {
+ $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Application folder definition file `"$($ApplicationFolderDefinitionPath.FullName)`" does not exist."
+ Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose
+ }
+ }
+ }
+ }
+
+
+
+ #If necessary, create, get, and or set any task sequence variable(s).
+ Switch (($IsRunningTaskSequence -eq $True) -or ($DebugMode.IsPresent -eq $True))
+ {
+ {($_ -eq $True)}
+ {
+ Try
+ {
+ ForEach ($TSVariable In $TSVariableTable.GetEnumerator())
+ {
+ [String]$TSVariableName = "$($TSVariable.Key)"
+ [String]$TSVariableCurrentValue = $TSEnvironment.Value($TSVariableName)
+ [String]$TSVariableNewValue = "$($TSVariable.Value -Join ',')"
+
+ Switch ($TSVariableCurrentValue -ine $TSVariableNewValue)
+ {
+ {($_ -eq $True)}
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to set the task sequence variable of `"$($TSVariableName)`". Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $Null = $TSEnvironment.Value($TSVariableName) = "$($TSVariableNewValue)"
+ }
+ }
+ }
+
+ $Null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($TSEnvironment)
+ }
+ Catch
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - [Error Message: $($_.Exception.Message)] [Code: $($_.InvocationInfo.Line.Trim())] [Line Number: $($_.InvocationInfo.ScriptLineNumber)] [Line Position: $($_.InvocationInfo.OffsetInLine)]"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ Finally
+ {
+
+ }
+ }
+
+ {($_ -eq $False)}
+ {
+ $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - There is no task sequence running."
+ Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose
+ }
+ }
+
+ $Script:LASTEXITCODE = $TerminationCodes.Success[0]
+ }
+ Catch
+ {
+ $ErrorHandlingDefinition.Invoke()
+ }
+ Finally
+ {
+ Try
+ {
+ #Determine the date and time the function completed execution
+ $ScriptEndTime = (Get-Date)
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Script execution of `"$($CmdletName)`" ended on $($ScriptEndTime.ToString($DateTimeLogFormat))"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ #Log the total script execution time
+ $ScriptExecutionTimespan = New-TimeSpan -Start ($ScriptStartTime) -End ($ScriptEndTime)
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Script execution took $($ScriptExecutionTimespan.Hours.ToString()) hour(s), $($ScriptExecutionTimespan.Minutes.ToString()) minute(s), $($ScriptExecutionTimespan.Seconds.ToString()) second(s), and $($ScriptExecutionTimespan.Milliseconds.ToString()) millisecond(s)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Exiting script `"$($ScriptPath.FullName)`" with exit code $($Script:LASTEXITCODE)."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ Stop-Transcript
+ }
+ Catch
+ {
+
+ }
+ }
+ }
\ No newline at end of file
diff --git a/Invoke-OSDApplicationList.vbs b/Invoke-OSDApplicationList.vbs
new file mode 100644
index 0000000..b23503e
--- /dev/null
+++ b/Invoke-OSDApplicationList.vbs
@@ -0,0 +1,145 @@
+'Set object values
+ Set oArguments = WScript.Arguments.Named
+ Set oFSO = CreateObject("Scripting.FileSystemObject")
+ Set oShell = CreateObject("WScript.Shell")
+ Set oCMD = oFSO.GetFile(oShell.ExpandEnvironmentStrings("%COMSPEC%"))
+ Set oPowershell = oFSO.GetFile(oShell.ExpandEnvironmentStrings("%WINDIR%") & "\System32\WindowsPowershell\v1.0\powershell.exe")
+
+'Define ASCII Characters
+ chrSpace = Chr(32)
+ chrSingleQuote = Chr(39)
+ chrDoubleQuote = Chr(34)
+
+'Define Variable(s)
+ ScriptInterpreter = CreateObject("Scripting.FileSystemObject").GetFileName(WScript.FullName)
+ If (oArguments.Exists("Debug") = True) Then DebugMode = True End If
+
+'Dynamically convert named VBScript arguments to their eqivalent powershell format
+oArgumentCount = oArguments.Count
+
+If (oArgumentCount > 0) Then
+ StringBuilder = ""
+
+ oArgumentCounter = 1
+
+ Set ArgumentNameExpression = New RegExp
+
+ With ArgumentNameExpression
+ .Pattern = "^Debug$"
+ .IgnoreCase = True
+ .Global = False
+ .Multiline = False
+ End With
+
+ Set ArgumentValueExpression = New RegExp
+
+ With ArgumentValueExpression
+ .Pattern = "^.*True|.*False$"
+ .IgnoreCase = True
+ .Global = False
+ .Multiline = False
+ End With
+
+ For Each oArgument In oArguments
+ ArgumentName = Trim(oArgument)
+ ArgumentValue = oArguments.Item(oArgument)
+
+ If (Not(ArgumentNameExpression.Test(ArgumentName))) Then
+ Select Case ((Len(ArgumentValue) > 0) And (Not(ArgumentValueExpression.Test(ArgumentValue))))
+ Case True
+ If (InStr(ArgumentValue, ",") > 0) Then
+ ArgumentValueParts = Split(ArgumentValue, ",")
+
+ ArgumentValuePartsCount = UBound(ArgumentValueParts)
+
+ ArgumentValuePartStringBuilder = ""
+
+ ArgumentValuePartCounter = 0
+
+ For Each ArgumentValuePart In ArgumentValueParts
+ ArgumentValuePartFormat = chrDoubleQuote & ArgumentValuePart & chrDoubleQuote
+
+ ArgumentValuePartStringBuilder = ArgumentValuePartStringBuilder & ArgumentValuePartFormat
+
+ If ((ArgumentValuePartsCount > 0) And (ArgumentValuePartCounter < ArgumentValuePartsCount)) Then
+ ArgumentValuePartStringBuilder = ArgumentValuePartStringBuilder & ","
+ ArgumentValuePartCounter = ArgumentValuePartCounter + 1
+ End If
+ Next
+
+ ParameterFormat = "-" & ArgumentName & chrSpace & ArgumentValuePartStringBuilder
+ ElseIf (IsNumeric(ArgumentValue) = True) Then
+ ParameterFormat = "-" & ArgumentName & chrSpace & ArgumentValue
+ Else
+ ParameterFormat = "-" & ArgumentName & chrSpace & chrDoubleQuote & ArgumentValue & chrDoubleQuote
+ End If
+ Case False
+ ParameterFormat = "-" & ArgumentName
+ End Select
+
+ If (Len(ParameterFormat) > 0) Then
+
+ If ((oArgumentCount > 1) And (oArgumentCounter < oArgumentCount)) Then
+ StringBuilder = StringBuilder & chrSpace
+ End If
+
+ StringBuilder = StringBuilder & ParameterFormat
+
+ ArgumentCounter = oArgumentCounter + 1
+
+ ParameterFormat = Null
+ End If
+ End If
+ Next
+
+ StringBuilderResult = Trim(StringBuilder)
+
+ If (Len(StringBuilderResult) > 0) Then
+ PowershellScriptParameters = StringBuilderResult & ";" & chrSpace & "[System.Environment]::Exit(($LASTEXITCODE -Bor [Int](-Not $? -And -Not $LASTEXITCODE)))"
+ Else
+ If (DebugMode = True) Then
+ WScript.Echo("Debug mode is enabled. The specified command will NOT be executed.")
+ End If
+
+ PowershellScriptParameters = ";" & chrSpace & "[System.Environment]::Exit(($LASTEXITCODE -Bor [Int](-Not $? -And -Not $LASTEXITCODE)))"
+ End If
+
+ Set ArgumentNameExpression = Nothing
+
+ Set ArgumentValueExpression = Nothing
+Else
+ If (DebugMode = True) Then
+ WScript.Echo(oArgumentCount & chrSpace & "arguments were specified.")
+ End If
+End If
+
+'Define Additional Variable(s)
+ Set ScriptPath = oFSO.GetFile(WScript.ScriptFullName)
+ ScriptDirectory = ScriptPath.ParentFolder
+ System32Directory = oShell.ExpandEnvironmentStrings("%WINDIR%") & "\System32"
+ CommandPromptExecutionParameters = oCMD.Name & chrSpace & "/c"
+ PowershellExecutionParameters = chrDoubleQuote & oPowershell.Path & chrDoubleQuote & chrSpace & "-ExecutionPolicy Bypass -NonInteractive -NoProfile -NoLogo -WindowStyle Hidden -Command"
+ PowershellScriptPath = ScriptDirectory & "\" & oFSO.GetBaseName(ScriptPath) & ".ps1"
+
+'Execute Powershell Script
+ If (Len(PowershellScriptParameters) > 0) Then
+ Command = PowershellExecutionParameters & chrSpace & chrDoubleQuote & "&" & chrSpace & chrSingleQuote & PowershellScriptPath & chrSingleQuote & chrSpace & PowershellScriptParameters & chrDoubleQuote
+ Else
+ Command = PowershellExecutionParameters & chrSpace & chrDoubleQuote & "&" & chrSpace & chrSingleQuote & PowershellScriptPath & chrSingleQuote & chrDoubleQuote
+ End If
+
+ If ((ScriptInterpreter = "cscript.exe") Or (DebugMode = True)) Then
+ WScript.Echo("Command:" & chrSpace & Command)
+ End If
+
+ If (DebugMode = False) Then
+ RunCommand = oShell.Run(Command, 0, True)
+ End If
+
+ If ((ScriptInterpreter = "cscript.exe") Or (DebugMode = True)) And (IsEmpty(RunCommand) = False) Then
+ WScript.Echo("Exit Code:" & chrSpace & RunCommand)
+ End If
+
+ If (DebugMode = False) Then
+ WScript.Quit(RunCommand)
+ End If
\ No newline at end of file
diff --git a/README.md b/README.md
index e13a83b..9514851 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,34 @@
# Dynamic OSD Application List
Allows for the dynamic installation of applications during a MDT task sequence.
+
+Run the Update-MDTApplicationXML.ps1 and provide the path to the Applications.xml within the control folder inside the MDT deployment share.
+
+This will make the application object specific adjustments to support the script that runs during the task sequence. It is totally safe and will not cause disruptive issues.
+
+Updates the MDT Applications.xml file to support the functionality built into the Invoke-OSDApplicationList.ps1 powershell script.
+
+Just refresh the 'Applications' view within the MDT Deployment Workbench after executing this script and make any application specific adjustments as needed.
+
+Sort the application(s) by the version column within the MDT Deployment Workbench to see the order in which the applications would be installed by the task sequence.
+
+
+Updates the 'Version' property of each application with the installation order (Will be based on creation date initially, but can be adjusted according to any specific needs.
+Updates the 'Language' property of each application within the Applications.xml with a powershell based condition that will determine if the application will be installed during a task sequence.
+
+To install in all cases, just simply use "$True" without the quotes.
+To skip in all cases, just simply use "$False" without the quotes.
+
+Setting the right mixture of condition and installation order will provide a super smooth and consistent installation experience.
+
+Example: VMWare Tools
+Installation Order = 1
+Condition = ($ComputerSystem.Manufacturer -imatch '.*VM.*Ware.*')
+This would ensure that VMWare Tools gets installed first only VMWare virtual machines.
+
+Any variable that will be available during the execution of the Invoke-OSDApplicationList.ps1 powershell script can be used within a condition.
+
+Dynamically creates 'MandatoryApplicationXXX' task sequence variables with the GUIDs of MDT application objects to install on a device during operating system deployment.
+
+Individual applications or entire application folders can be disabled to exclude the application(s) from being considered by the script during deployment.
+
+Application(s) that have already been installed by the task sequence whose GUID is stored within a 'InstalledApplicationsXXX' variable will be skipped if this script is executed multiple times during a task sequence.
\ No newline at end of file
diff --git a/Tools/X64/Place_Additional_Tools_Here.txt b/Tools/X64/Place_Additional_Tools_Here.txt
new file mode 100644
index 0000000..fa7cc9c
--- /dev/null
+++ b/Tools/X64/Place_Additional_Tools_Here.txt
@@ -0,0 +1 @@
+###
\ No newline at end of file
diff --git a/Tools/X86/Place_Additional_Tools_Here.txt b/Tools/X86/Place_Additional_Tools_Here.txt
new file mode 100644
index 0000000..fa7cc9c
--- /dev/null
+++ b/Tools/X86/Place_Additional_Tools_Here.txt
@@ -0,0 +1 @@
+###
\ No newline at end of file
diff --git a/Update-MDTApplicationXML.ps1 b/Update-MDTApplicationXML.ps1
new file mode 100644
index 0000000..0327e60
--- /dev/null
+++ b/Update-MDTApplicationXML.ps1
@@ -0,0 +1,569 @@
+#Requires -Version 3
+
+<#
+ .SYNOPSIS
+ Updates the MDT Applications.xml to support the functionality built into the Invoke-OSDApplicationList.ps1 powershell script.
+
+ Just refresh the 'Applications' view within the MDT Deployment Workbench after executing this script and make any application specific adjustments as needed.
+
+ Sort the application(s) by the version column within the MDT Deployment Workbench to see the order in which the applications would be installed by the task sequence.
+
+ .DESCRIPTION
+ Updates the 'Version' property of each application with the installation order (Will be based on creation date initially, but can be adjusted according to any specific needs.
+ Updates the 'Language' property of each application within the Applications.xml with a powershell based condition that will determine if the application will be installed during a task sequence.
+
+ To install in all cases, just simply use "$True" without the quotes.
+ To skip in all cases, just simply use "$False" without the quotes.
+
+ Setting the right mixture of condition and installation order will provide a super smooth and consistent installation experience.
+
+ Example: VMWare Tools
+ Installation Order = 1
+ Condition = ($ComputerSystem.Manufacturer -imatch '.*VM.*Ware.*')
+ This would ensure that VMWare Tools gets installed first only VMWare virtual machines.
+
+ Any variable that will be available during the execution of the Invoke-OSDApplicationList.ps1 powershell script can be used within a condition.
+
+ .PARAMETER ApplicationFolderDefinitionPath
+ A valid path to the ApplicationGroups.xml file stored within the 'Control' folder within a MDT deployment share.
+
+ .PARAMETER ApplicationDefinitionPath
+ A valid path to the Applications.xml file stored within the 'Control' folder within a MDT deployment share.
+
+ .PARAMETER LogDir
+ A valid folder path. If the folder does not exist, it will be created. This parameter can also be specified by the alias "LogPath".
+
+ .PARAMETER ContinueOnError
+ Ignore failures.
+
+ .PARAMETER DebugMode
+ Allows for testing to see which applications would be deployed without running a task sequence.
+
+ .EXAMPLE
+ Use this command to execute a VBSCript that will launch this powershell script automatically with the specified parameters. This is useful to avoid powershell execution complexities.
+
+ cscript.exe /nologo "%FolderPathContainingScript%\%ScriptName%.vbs" /SwitchParameter /ScriptParameter:"%ScriptParameterValue%" /ScriptParameterArray:"%ScriptParameterValue1%,%ScriptParameterValue2%"
+
+ wscript.exe /nologo "%FolderPathContainingScript%\%ScriptName%.vbs" /SwitchParameter /ScriptParameter:"%ScriptParameterValue%" /ScriptParameterArray:"%ScriptParameterValue1%,%ScriptParameterValue2%"
+
+ .EXAMPLE
+ powershell.exe -ExecutionPolicy Bypass -NoProfile -NoLogo -File "%FolderPathContainingScript%\%ScriptName%.ps1" -SwitchParameter -ScriptParameter "%ScriptParameterValue%"
+
+ .EXAMPLE
+ powershell.exe -ExecutionPolicy Bypass -NonInteractive -NoProfile -NoLogo -WindowStyle Hidden -Command "& '%FolderPathContainingScript%\%ScriptName%.ps1' -ScriptParameter1 '%ScriptParameter1Value%' -ScriptParameter2 %ScriptParameter2Value% -SwitchParameter"
+
+ .NOTES
+ Came up with this concept to keep task sequence modification to an absolute minimum.
+
+ .LINK
+ Place any useful link here where your function or cmdlet can be referenced
+#>
+
+[CmdletBinding(SupportsShouldProcess=$True)]
+ Param
+ (
+ [Parameter(Mandatory=$False)]
+ [ValidateNotNullOrEmpty()]
+ [Alias('ADP')]
+ [System.IO.FileInfo]$ApplicationDefinitionPath,
+
+ [Parameter(Mandatory=$False)]
+ [ValidateNotNullOrEmpty()]
+ [Alias('LogDir', 'LogPath')]
+ [System.IO.DirectoryInfo]$LogDirectory,
+
+ [Parameter(Mandatory=$False)]
+ [Switch]$ContinueOnError
+ )
+
+Function Get-AdministrativePrivilege
+ {
+ $Identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
+ $Principal = New-Object System.Security.Principal.WindowsPrincipal($Identity)
+ Write-Output -InputObject ($Principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator))
+ }
+
+If ((Get-AdministrativePrivilege) -eq $False)
+ {
+ [System.IO.FileInfo]$ScriptPath = "$($MyInvocation.MyCommand.Path)"
+
+ $ArgumentList = New-Object -TypeName 'System.Collections.Generic.List[String]'
+ $ArgumentList.Add('-ExecutionPolicy Bypass')
+ $ArgumentList.Add('-NoProfile')
+ $ArgumentList.Add('-NoExit')
+ $ArgumentList.Add('-NoLogo')
+ $ArgumentList.Add("-File `"$($ScriptPath.FullName)`"")
+
+ $Null = Start-Process -FilePath "$([System.Environment]::SystemDirectory)\WindowsPowershell\v1.0\powershell.exe" -WorkingDirectory "$([System.Environment]::SystemDirectory)" -ArgumentList ($ArgumentList.ToArray()) -WindowStyle Normal -Verb RunAs -PassThru
+ }
+Else
+ {
+ #Determine the date and time we executed the function
+ $ScriptStartTime = (Get-Date)
+
+ #Define Default Action Preferences
+ $Script:DebugPreference = 'SilentlyContinue'
+ $Script:ErrorActionPreference = 'Stop'
+ $Script:VerbosePreference = 'SilentlyContinue'
+ $Script:WarningPreference = 'Continue'
+ $Script:ConfirmPreference = 'None'
+ $Script:WhatIfPreference = $False
+
+ #Load WMI Classes
+ $Baseboard = Get-WmiObject -Namespace "root\CIMv2" -Class "Win32_Baseboard" -Property *
+ $Bios = Get-WmiObject -Namespace "root\CIMv2" -Class "Win32_Bios" -Property *
+ $ComputerSystem = Get-WmiObject -Namespace "root\CIMv2" -Class "Win32_ComputerSystem" -Property *
+ $OperatingSystem = Get-WmiObject -Namespace "root\CIMv2" -Class "Win32_OperatingSystem" -Property *
+ $MSSystemInformation = Get-WmiObject -Namespace "root\WMI" -Class "MS_SystemInformation" -Property *
+
+ #Retrieve property values
+ $OSArchitecture = $($OperatingSystem.OSArchitecture).Replace("-bit", "").Replace("32", "86").Insert(0,"x").ToUpper()
+
+ #Define variable(s)
+ $DateTimeLogFormat = 'dddd, MMMM dd, yyyy @ hh:mm:ss.FFF tt' ###Monday, January 01, 2019 @ 10:15:34.000 AM###
+ [ScriptBlock]$GetCurrentDateTimeLogFormat = {(Get-Date).ToString($DateTimeLogFormat)}
+ $DateTimeMessageFormat = 'MM/dd/yyyy HH:mm:ss.FFF' ###03/23/2022 11:12:48.347###
+ [ScriptBlock]$GetCurrentDateTimeMessageFormat = {(Get-Date).ToString($DateTimeMessageFormat)}
+ $DateFileFormat = 'yyyyMMdd' ###20190403###
+ [ScriptBlock]$GetCurrentDateFileFormat = {(Get-Date).ToString($DateFileFormat)}
+ $DateTimeFileFormat = 'yyyyMMdd_HHmmss' ###20190403_115354###
+ [ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)}
+ [System.IO.FileInfo]$ScriptPath = "$($MyInvocation.MyCommand.Definition)"
+ [System.IO.DirectoryInfo]$ScriptDirectory = "$($ScriptPath.Directory.FullName)"
+ [System.IO.DirectoryInfo]$ContentDirectory = "$($ScriptDirectory.FullName)\Content"
+ [System.IO.DirectoryInfo]$FunctionsDirectory = "$($ScriptDirectory.FullName)\Functions"
+ [System.IO.DirectoryInfo]$ModulesDirectory = "$($ScriptDirectory.FullName)\Modules"
+ [System.IO.DirectoryInfo]$ToolsDirectory = "$($ScriptDirectory.FullName)\Tools"
+ [System.IO.DirectoryInfo]$ToolsDirectory_OSAll = "$($ToolsDirectory.FullName)\All"
+ [System.IO.DirectoryInfo]$ToolsDirectory_OSArchSpecific = "$($ToolsDirectory.FullName)\$($OSArchitecture)"
+ [System.IO.DirectoryInfo]$System32Directory = [System.Environment]::SystemDirectory
+ [System.IO.DirectoryInfo]$ProgramFilesDirectory = "$($Env:SystemDrive)\Program Files"
+ [System.IO.DirectoryInfo]$ProgramFilesx86Directory = "$($Env:SystemDrive)\Program Files (x86)"
+ [System.IO.FileInfo]$PowershellPath = "$($System32Directory.FullName)\WindowsPowershell\v1.0\powershell.exe"
+ [System.IO.DirectoryInfo]$System32Directory = "$([System.Environment]::SystemDirectory)"
+ $IsWindowsPE = Test-Path -Path 'HKLM:\SYSTEM\ControlSet001\Control\MiniNT' -ErrorAction SilentlyContinue
+ [System.Text.RegularExpressions.RegexOptions[]]$RegexOptions = [System.Text.RegularExpressions.RegexOptions]::IgnoreCase, [System.Text.RegularExpressions.RegexOptions]::Multiline
+ [ScriptBlock]$GetRandomGUID = {[System.GUID]::NewGUID().GUID.ToString().ToUpper()}
+ [String]$ParameterSetName = "$($PSCmdlet.ParameterSetName)"
+ $TextInfo = (Get-Culture).TextInfo
+ $Script:LASTEXITCODE = 0
+ $TerminationCodes = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $TerminationCodes.Add('Success', @(0))
+ $TerminationCodes.Add('Warning', @(5000..5999))
+ $TerminationCodes.Add('Error', @(6000..6999))
+ $Script:WarningCodeIndex = 0
+ [ScriptBlock]$GetAvailableWarningCode = {$TerminationCodes.Warning[$Script:WarningCodeIndex]; $Script:WarningCodeIndex++}
+ $Script:ErrorCodeIndex = 0
+ [ScriptBlock]$GetAvailableErrorCode = {$TerminationCodes.Error[$Script:ErrorCodeIndex]; $Script:ErrorCodeIndex++}
+ $LoggingDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $LoggingDetails.Add('LogMessage', $Null)
+ $LoggingDetails.Add('WarningMessage', $Null)
+ $LoggingDetails.Add('ErrorMessage', $Null)
+ $RegularExpressionTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $RegularExpressionTable.Base64 = '^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$' -As [Regex]
+ $CommonParameterList = New-Object -TypeName 'System.Collections.Generic.List[String]'
+ $CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::CommonParameters)
+ $CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::OptionalCommonParameters)
+
+ #Define the error handling definition
+ [ScriptBlock]$ErrorHandlingDefinition = {
+ If (($Null -ieq $Script:LASTEXITCODE) -or ($Script:LASTEXITCODE -eq 0))
+ {
+ [Int]$Script:LASTEXITCODE = $GetAvailableErrorCode.InvokeReturnAsIs()
+ }
+
+ $ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $ErrorMessageList.Add('Message', $_.Exception.Message)
+ $ErrorMessageList.Add('Category', $_.Exception.ErrorRecord.FullyQualifiedErrorID)
+ $ErrorMessageList.Add('ExitCode', $Script:LASTEXITCODE)
+ $ErrorMessageList.Add('Script', $_.InvocationInfo.ScriptName)
+ $ErrorMessageList.Add('LineNumber', $_.InvocationInfo.ScriptLineNumber)
+ $ErrorMessageList.Add('LinePosition', $_.InvocationInfo.OffsetInLine)
+ $ErrorMessageList.Add('Code', $_.InvocationInfo.Line.Trim())
+
+ ForEach ($ErrorMessage In $ErrorMessageList.GetEnumerator())
+ {
+ $LoggingDetails.ErrorMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - ERROR: $($ErrorMessage.Key): $($ErrorMessage.Value)"
+ Write-Warning -Message ($LoggingDetails.ErrorMessage) -Verbose
+ }
+
+ Switch (($ContinueOnError.IsPresent -eq $False) -or ($ContinueOnError -eq $False))
+ {
+ {($_ -eq $True)}
+ {
+ Throw
+ }
+ }
+ }
+
+ #Determine default parameter value(s)
+ Switch ($True)
+ {
+ {([String]::IsNullOrEmpty($LogDirectory) -eq $True) -or ([String]::IsNullOrWhiteSpace($LogDirectory) -eq $True)}
+ {
+ [System.IO.DirectoryInfo]$LogDirectory = "$($Env:Windir)\Logs\Software\$($ScriptPath.BaseName)"
+ }
+ }
+
+ #Start transcripting (Logging)
+ [System.IO.FileInfo]$ScriptLogPath = "$($LogDirectory.FullName)\$($ScriptPath.BaseName)_$($GetCurrentDateFileFormat.Invoke()).log"
+ If ($ScriptLogPath.Directory.Exists -eq $False) {$Null = [System.IO.Directory]::CreateDirectory($ScriptLogPath.Directory.FullName)}
+ Start-Transcript -Path "$($ScriptLogPath.FullName)" -Force -WhatIf:$False
+
+ #Log any useful information
+ [String]$CmdletName = $MyInvocation.MyCommand.Name
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of script `"$($CmdletName)`" began on $($ScriptStartTime.ToString($DateTimeLogFormat))"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Script Path = $($ScriptPath.FullName)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ [String[]]$AvailableScriptParameters = (Get-Command -Name ($ScriptPath.FullName)).Parameters.GetEnumerator() | Where-Object {($_.Value.Name -inotin $CommonParameterList)} | ForEach-Object {"-$($_.Value.Name):$($_.Value.ParameterType.Name)"}
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Available Script Parameter(s) = $($AvailableScriptParameters -Join ', ')"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ [String[]]$SuppliedScriptParameters = $PSBoundParameters.GetEnumerator() | ForEach-Object {"-$($_.Key):$($_.Value.GetType().Name)"}
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Supplied Script Parameter(s) = $($SuppliedScriptParameters -Join ', ')"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ Switch ($True)
+ {
+ {([String]::IsNullOrEmpty($ParameterSetName) -eq $False)}
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Parameter Set Name = $($ParameterSetName)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ }
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Command Line: $((Get-WMIObject -Namespace 'Root\CIMv2' -Class 'Win32_Process' -Filter "ProcessID = $($PID)").CommandLine)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($PSBoundParameters.Count) command line parameter(s) were specified."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $OperatingSystemDetailsTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
+ $OperatingSystemDetailsTable.ProductName = $OperatingSystem.Caption -ireplace '(Microsoft\s+)', ''
+ $OperatingSystemDetailsTable.Version = $OperatingSystem.Version
+ $OperatingSystemDetailsTable.Architecture = $OperatingSystem.OSArchitecture
+
+ $OperatingSystemRegistryDetails = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
+ $OperatingSystemRegistryDetails.Add((New-Object -TypeName 'PSObject' -Property @{Alias = ''; Path = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'; ValueName = 'UBR'; Value = $Null}))
+ $OperatingSystemRegistryDetails.Add((New-Object -TypeName 'PSObject' -Property @{Alias = 'ReleaseVersion'; Path = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'; ValueName = 'ReleaseID'; Value = $Null}))
+ $OperatingSystemRegistryDetails.Add((New-Object -TypeName 'PSObject' -Property @{Alias = 'ReleaseID'; Path = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'; ValueName = 'DisplayVersion'; Value = $Null}))
+
+ ForEach ($OperatingSystemRegistryDetail In $OperatingSystemRegistryDetails)
+ {
+ $OperatingSystemRegistryDetail.Value = Try {(Get-Item -Path $OperatingSystemRegistryDetail.Path).GetValue($OperatingSystemRegistryDetail.ValueName)} Catch {}
+
+ :NextOSDetail Switch (([String]::IsNullOrEmpty($OperatingSystemRegistryDetail.Value) -eq $False) -and ([String]::IsNullOrWhiteSpace($OperatingSystemRegistryDetail.Value) -eq $False))
+ {
+ {($_ -eq $True)}
+ {
+ Switch ($OperatingSystemRegistryDetail.ValueName)
+ {
+ {($_ -ieq 'UBR')}
+ {
+ $OperatingSystemDetailsTable.Version = $OperatingSystemDetailsTable.Version + '.' + $OperatingSystemRegistryDetail.Value
+
+ Break NextOSDetail
+ }
+ }
+
+ Switch (([String]::IsNullOrEmpty($OperatingSystemRegistryDetail.Alias) -eq $False) -and ([String]::IsNullOrWhiteSpace($OperatingSystemRegistryDetail.Alias) -eq $False))
+ {
+ {($_ -eq $True)}
+ {
+ $OperatingSystemDetailsTable.$($OperatingSystemRegistryDetail.Alias) = $OperatingSystemRegistryDetail.Value
+ }
+
+ Default
+ {
+ $OperatingSystemDetailsTable.$($OperatingSystemRegistryDetail.ValueName) = $OperatingSystemRegistryDetail.Value
+ }
+ }
+ }
+
+ Default
+ {
+ $OperatingSystemDetailsTable.$($OperatingSystemRegistryDetail.ValueName) = $OperatingSystemRegistryDetail.Value
+ }
+ }
+ }
+
+ ForEach ($OperatingSystemDetail In $OperatingSystemDetailsTable.GetEnumerator())
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($OperatingSystemDetail.Key): $($OperatingSystemDetail.Value)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Powershell Version: $($PSVersionTable.PSVersion.ToString())"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $ExecutionPolicyList = Get-ExecutionPolicy -List
+
+ For ($ExecutionPolicyListIndex = 0; $ExecutionPolicyListIndex -lt $ExecutionPolicyList.Count; $ExecutionPolicyListIndex++)
+ {
+ $ExecutionPolicy = $ExecutionPolicyList[$ExecutionPolicyListIndex]
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The powershell execution policy is currently set to `"$($ExecutionPolicy.ExecutionPolicy.ToString())`" for the `"$($ExecutionPolicy.Scope.ToString())`" scope."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+
+ #Log hardware information
+ $MSSystemInformationMembers = $MSSystemInformation.PSObject.Properties | Where-Object {($_.MemberType -imatch '^NoteProperty$|^Property$') -and ($_.Name -imatch '^Base.*|Bios.*|System.*$') -and ($_.Name -inotmatch '^.*Major.*|.*Minor.*|.*Properties.*$')} | Sort-Object -Property @('Name')
+
+ Switch ($MSSystemInformationMembers.Count -gt 0)
+ {
+ {($_ -eq $True)}
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to display device information properties from the `"$($MSSystemInformation.__CLASS)`" WMI class located within the `"$($MSSystemInformation.__NAMESPACE)`" WMI namespace. Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ ForEach ($MSSystemInformationMember In $MSSystemInformationMembers)
+ {
+ [String]$MSSystemInformationMemberName = ($MSSystemInformationMember.Name)
+ [String]$MSSystemInformationMemberValue = $MSSystemInformation.$($MSSystemInformationMemberName)
+
+ Switch ([String]::IsNullOrEmpty($MSSystemInformationMemberValue))
+ {
+ {($_ -eq $False)}
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($MSSystemInformationMemberName) = $($MSSystemInformationMemberValue)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ }
+ }
+ }
+
+ Default
+ {
+ $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The `"MSSystemInformation`" WMI class could not be found."
+ Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose
+ }
+ }
+
+ #region Log Cleanup
+ [Int]$MaximumLogHistory = 3
+
+ $LogList = Get-ChildItem -Path ($LogDirectory.FullName) -Filter "$($ScriptPath.BaseName)_*" -Recurse -Force | Where-Object {($_ -is [System.IO.FileInfo])}
+
+ $SortedLogList = $LogList | Sort-Object -Property @('LastWriteTime') -Descending | Select-Object -Skip ($MaximumLogHistory)
+
+ Switch ($SortedLogList.Count -gt 0)
+ {
+ {($_ -eq $True)}
+ {
+ $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - There are $($SortedLogList.Count) log file(s) requiring cleanup."
+ Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose
+
+ For ($SortedLogListIndex = 0; $SortedLogListIndex -lt $SortedLogList.Count; $SortedLogListIndex++)
+ {
+ Try
+ {
+ $Log = $SortedLogList[$SortedLogListIndex]
+
+ $LogAge = New-TimeSpan -Start ($Log.LastWriteTime) -End (Get-Date)
+
+ $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to cleanup log file `"$($Log.FullName)`". Please Wait... [Last Modified: $($Log.LastWriteTime.ToString($DateTimeMessageFormat))] [Age: $($LogAge.Days.ToString()) day(s); $($LogAge.Hours.ToString()) hours(s); $($LogAge.Minutes.ToString()) minute(s); $($LogAge.Seconds.ToString()) second(s)]."
+ Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose
+
+ $Null = [System.IO.File]::Delete($Log.FullName)
+ }
+ Catch
+ {
+
+ }
+ }
+ }
+
+ Default
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - There are $($SortedLogList.Count) log file(s) requiring cleanup."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+ }
+ }
+ #endregion
+
+ #region Import Dependency Modules
+ If (($ModulesDirectory.Exists -eq $True) -and ($ModulesDirectory.GetDirectories().Count -gt 0))
+ {
+ $Modules = Get-Module -Name "$($ModulesDirectory.FullName)\*" -ListAvailable -ErrorAction Stop
+
+ $ModuleGroups = $Modules | Group-Object -Property @('Name')
+
+ ForEach ($ModuleGroup In $ModuleGroups)
+ {
+ $LatestModuleVersion = $ModuleGroup.Group | Sort-Object -Property @('Version') -Descending | Select-Object -First 1
+
+ If ($Null -ine $LatestModuleVersion)
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to import dependency powershell module `"$($LatestModuleVersion.Name)`" [Version: $($LatestModuleVersion.Version.ToString())]. Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ Import-Module -Name "$($LatestModuleVersion.Path)" -Global -DisableNameChecking -Force -ErrorAction Stop
+ }
+ }
+ }
+ #endregion
+
+ #region Dot Source Dependency Scripts
+ #Dot source any additional script(s) from the functions directory. This will provide flexibility to add additional functions without adding complexity to the main script and to maintain function consistency.
+ Try
+ {
+ If ($FunctionsDirectory.Exists -eq $True)
+ {
+ $AdditionalFunctionsFilter = New-Object -TypeName 'System.Collections.Generic.List[String]'
+ $AdditionalFunctionsFilter.Add('*.ps1')
+
+ $AdditionalFunctionsToImport = Get-ChildItem -Path "$($FunctionsDirectory.FullName)" -Include ($AdditionalFunctionsFilter) -Recurse -Force | Where-Object {($_ -is [System.IO.FileInfo])}
+
+ $AdditionalFunctionsToImportCount = $AdditionalFunctionsToImport | Measure-Object | Select-Object -ExpandProperty Count
+
+ If ($AdditionalFunctionsToImportCount -gt 0)
+ {
+ ForEach ($AdditionalFunctionToImport In $AdditionalFunctionsToImport)
+ {
+ Try
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to dot source the functions contained within the dependency script `"$($AdditionalFunctionToImport.Name)`". Please Wait... [Script Path: `"$($AdditionalFunctionToImport.FullName)`"]"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ . "$($AdditionalFunctionToImport.FullName)"
+ }
+ Catch
+ {
+ $ErrorHandlingDefinition.Invoke()
+ }
+ }
+ }
+ }
+ }
+ Catch
+ {
+ $ErrorHandlingDefinition.Invoke()
+ }
+ #endregion
+
+ #region Load any required libraries
+ [System.IO.DirectoryInfo]$LibariesDirectory = "$($FunctionsDirectory.FullName)\Libraries"
+
+ Switch ([System.IO.Directory]::Exists($LibariesDirectory.FullName))
+ {
+ {($_ -eq $True)}
+ {
+ $LibraryPatternList = New-Object -TypeName 'System.Collections.Generic.List[String]'
+ #$LibraryPatternList.Add('')
+
+ Switch ($LibraryPatternList.Count -gt 0)
+ {
+ {($_ -eq $True)}
+ {
+ $LibraryList = Get-ChildItem -Path ($LibariesDirectory.FullName) -Include ($LibraryPatternList.ToArray()) -Recurse -Force | Where-Object {($_ -is [System.IO.FileInfo])}
+
+ $LibraryListCount = ($LibraryList | Measure-Object).Count
+
+ Switch ($LibraryListCount -gt 0)
+ {
+ {($_ -eq $True)}
+ {
+ For ($LibraryListIndex = 0; $LibraryListIndex -lt $LibraryListCount; $LibraryListIndex++)
+ {
+ $Library = $LibraryList[$LibraryListIndex]
+
+ [Byte[]]$LibraryBytes = [System.IO.File]::ReadAllBytes($Library.FullName)
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to load assembly `"$($Library.FullName)`". Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $Null = [System.Reflection.Assembly]::Load($LibraryBytes)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ #endregion
+
+ #Perform script action(s)
+ Try
+ {
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Application Definition Path: $($ApplicationDefinitionPath.FullName)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ Switch ([System.IO.File]::Exists($ApplicationDefinitionPath.FullName))
+ {
+ {($_ -eq $True)}
+ {
+ $ApplicationDefinitionContents = [System.IO.File]::ReadAllText($ApplicationDefinitionPath.FullName)
+
+ $ApplicationDefinition = New-Object -TypeName 'System.Xml.XmlDocument'
+ $ApplicationDefinition.LoadXml($ApplicationDefinitionContents)
+
+ $AvailableApplicationList = $ApplicationDefinition.applications.application | Sort-Object -Property @{Expression = {Try {(Get-Date -Date ($AvailableApplication.CreatedTime))} Catch {}}}
+
+ #Starting at 100 provides space to set higher priority application(s) to the lower numbers to ensure they get installed first.
+ $StartingApplicationOrder = 100
+
+ For ($AvailableApplicationListIndex = 0; $AvailableApplicationListIndex -lt $AvailableApplicationList.Count; $AvailableApplicationListIndex++)
+ {
+ $AvailableApplication = $AvailableApplicationList[$AvailableApplicationListIndex]
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to make configuration adjustment(s) to application `"$($AvailableApplication.Name)`". Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $AvailableApplication.Version = $StartingApplicationOrder.ToString()
+ $AvailableApplication.Language = '($OperatingSystem.ProductType -in @(1))'
+
+ $StartingApplicationOrder++
+ }
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to save application configuration changes to `"$($ApplicationDefinitionPath.FullName)`". Please Wait..."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $Null = $ApplicationDefinition.Save($ApplicationDefinitionPath.FullName)
+
+ $Null = Start-Sleep -Seconds 3
+ }
+
+ Default
+ {
+ $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Application definition file `"$($ApplicationDefinitionPath.FullName)`" does not exist."
+ Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose
+ }
+ }
+
+ $Script:LASTEXITCODE = $TerminationCodes.Success[0]
+ }
+ Catch
+ {
+ $ErrorHandlingDefinition.Invoke()
+ }
+ Finally
+ {
+ Try
+ {
+ #Determine the date and time the function completed execution
+ $ScriptEndTime = (Get-Date)
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Script execution of `"$($CmdletName)`" ended on $($ScriptEndTime.ToString($DateTimeLogFormat))"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ #Log the total script execution time
+ $ScriptExecutionTimespan = New-TimeSpan -Start ($ScriptStartTime) -End ($ScriptEndTime)
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Script execution took $($ScriptExecutionTimespan.Hours.ToString()) hour(s), $($ScriptExecutionTimespan.Minutes.ToString()) minute(s), $($ScriptExecutionTimespan.Seconds.ToString()) second(s), and $($ScriptExecutionTimespan.Milliseconds.ToString()) millisecond(s)"
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Exiting script `"$($ScriptPath.FullName)`" with exit code $($Script:LASTEXITCODE)."
+ Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
+
+ Stop-Transcript
+ }
+ Catch
+ {
+
+ }
+ }
+ }
\ No newline at end of file
diff --git a/Update-MDTApplicationXML.vbs b/Update-MDTApplicationXML.vbs
new file mode 100644
index 0000000..b23503e
--- /dev/null
+++ b/Update-MDTApplicationXML.vbs
@@ -0,0 +1,145 @@
+'Set object values
+ Set oArguments = WScript.Arguments.Named
+ Set oFSO = CreateObject("Scripting.FileSystemObject")
+ Set oShell = CreateObject("WScript.Shell")
+ Set oCMD = oFSO.GetFile(oShell.ExpandEnvironmentStrings("%COMSPEC%"))
+ Set oPowershell = oFSO.GetFile(oShell.ExpandEnvironmentStrings("%WINDIR%") & "\System32\WindowsPowershell\v1.0\powershell.exe")
+
+'Define ASCII Characters
+ chrSpace = Chr(32)
+ chrSingleQuote = Chr(39)
+ chrDoubleQuote = Chr(34)
+
+'Define Variable(s)
+ ScriptInterpreter = CreateObject("Scripting.FileSystemObject").GetFileName(WScript.FullName)
+ If (oArguments.Exists("Debug") = True) Then DebugMode = True End If
+
+'Dynamically convert named VBScript arguments to their eqivalent powershell format
+oArgumentCount = oArguments.Count
+
+If (oArgumentCount > 0) Then
+ StringBuilder = ""
+
+ oArgumentCounter = 1
+
+ Set ArgumentNameExpression = New RegExp
+
+ With ArgumentNameExpression
+ .Pattern = "^Debug$"
+ .IgnoreCase = True
+ .Global = False
+ .Multiline = False
+ End With
+
+ Set ArgumentValueExpression = New RegExp
+
+ With ArgumentValueExpression
+ .Pattern = "^.*True|.*False$"
+ .IgnoreCase = True
+ .Global = False
+ .Multiline = False
+ End With
+
+ For Each oArgument In oArguments
+ ArgumentName = Trim(oArgument)
+ ArgumentValue = oArguments.Item(oArgument)
+
+ If (Not(ArgumentNameExpression.Test(ArgumentName))) Then
+ Select Case ((Len(ArgumentValue) > 0) And (Not(ArgumentValueExpression.Test(ArgumentValue))))
+ Case True
+ If (InStr(ArgumentValue, ",") > 0) Then
+ ArgumentValueParts = Split(ArgumentValue, ",")
+
+ ArgumentValuePartsCount = UBound(ArgumentValueParts)
+
+ ArgumentValuePartStringBuilder = ""
+
+ ArgumentValuePartCounter = 0
+
+ For Each ArgumentValuePart In ArgumentValueParts
+ ArgumentValuePartFormat = chrDoubleQuote & ArgumentValuePart & chrDoubleQuote
+
+ ArgumentValuePartStringBuilder = ArgumentValuePartStringBuilder & ArgumentValuePartFormat
+
+ If ((ArgumentValuePartsCount > 0) And (ArgumentValuePartCounter < ArgumentValuePartsCount)) Then
+ ArgumentValuePartStringBuilder = ArgumentValuePartStringBuilder & ","
+ ArgumentValuePartCounter = ArgumentValuePartCounter + 1
+ End If
+ Next
+
+ ParameterFormat = "-" & ArgumentName & chrSpace & ArgumentValuePartStringBuilder
+ ElseIf (IsNumeric(ArgumentValue) = True) Then
+ ParameterFormat = "-" & ArgumentName & chrSpace & ArgumentValue
+ Else
+ ParameterFormat = "-" & ArgumentName & chrSpace & chrDoubleQuote & ArgumentValue & chrDoubleQuote
+ End If
+ Case False
+ ParameterFormat = "-" & ArgumentName
+ End Select
+
+ If (Len(ParameterFormat) > 0) Then
+
+ If ((oArgumentCount > 1) And (oArgumentCounter < oArgumentCount)) Then
+ StringBuilder = StringBuilder & chrSpace
+ End If
+
+ StringBuilder = StringBuilder & ParameterFormat
+
+ ArgumentCounter = oArgumentCounter + 1
+
+ ParameterFormat = Null
+ End If
+ End If
+ Next
+
+ StringBuilderResult = Trim(StringBuilder)
+
+ If (Len(StringBuilderResult) > 0) Then
+ PowershellScriptParameters = StringBuilderResult & ";" & chrSpace & "[System.Environment]::Exit(($LASTEXITCODE -Bor [Int](-Not $? -And -Not $LASTEXITCODE)))"
+ Else
+ If (DebugMode = True) Then
+ WScript.Echo("Debug mode is enabled. The specified command will NOT be executed.")
+ End If
+
+ PowershellScriptParameters = ";" & chrSpace & "[System.Environment]::Exit(($LASTEXITCODE -Bor [Int](-Not $? -And -Not $LASTEXITCODE)))"
+ End If
+
+ Set ArgumentNameExpression = Nothing
+
+ Set ArgumentValueExpression = Nothing
+Else
+ If (DebugMode = True) Then
+ WScript.Echo(oArgumentCount & chrSpace & "arguments were specified.")
+ End If
+End If
+
+'Define Additional Variable(s)
+ Set ScriptPath = oFSO.GetFile(WScript.ScriptFullName)
+ ScriptDirectory = ScriptPath.ParentFolder
+ System32Directory = oShell.ExpandEnvironmentStrings("%WINDIR%") & "\System32"
+ CommandPromptExecutionParameters = oCMD.Name & chrSpace & "/c"
+ PowershellExecutionParameters = chrDoubleQuote & oPowershell.Path & chrDoubleQuote & chrSpace & "-ExecutionPolicy Bypass -NonInteractive -NoProfile -NoLogo -WindowStyle Hidden -Command"
+ PowershellScriptPath = ScriptDirectory & "\" & oFSO.GetBaseName(ScriptPath) & ".ps1"
+
+'Execute Powershell Script
+ If (Len(PowershellScriptParameters) > 0) Then
+ Command = PowershellExecutionParameters & chrSpace & chrDoubleQuote & "&" & chrSpace & chrSingleQuote & PowershellScriptPath & chrSingleQuote & chrSpace & PowershellScriptParameters & chrDoubleQuote
+ Else
+ Command = PowershellExecutionParameters & chrSpace & chrDoubleQuote & "&" & chrSpace & chrSingleQuote & PowershellScriptPath & chrSingleQuote & chrDoubleQuote
+ End If
+
+ If ((ScriptInterpreter = "cscript.exe") Or (DebugMode = True)) Then
+ WScript.Echo("Command:" & chrSpace & Command)
+ End If
+
+ If (DebugMode = False) Then
+ RunCommand = oShell.Run(Command, 0, True)
+ End If
+
+ If ((ScriptInterpreter = "cscript.exe") Or (DebugMode = True)) And (IsEmpty(RunCommand) = False) Then
+ WScript.Echo("Exit Code:" & chrSpace & RunCommand)
+ End If
+
+ If (DebugMode = False) Then
+ WScript.Quit(RunCommand)
+ End If
\ No newline at end of file