diff --git a/Content/ScheduledTasks/Template.xml b/Content/ScheduledTasks/Template.xml new file mode 100644 index 0000000..67bd7b7 Binary files /dev/null and b/Content/ScheduledTasks/Template.xml differ diff --git a/Content/Settings/Settings.xml b/Content/Settings/Settings.xml new file mode 100644 index 0000000..9416716 Binary files /dev/null and b/Content/Settings/Settings.xml differ diff --git a/Content/Settings/Template.xml b/Content/Settings/Template.xml new file mode 100644 index 0000000..5ae4898 --- /dev/null +++ b/Content/Settings/Template.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Functions/Invoke-FileDownload.ps1 b/Functions/Invoke-FileDownload.ps1 index 80fb98d..89ee7ed 100644 --- a/Functions/Invoke-FileDownload.ps1 +++ b/Functions/Invoke-FileDownload.ps1 @@ -63,7 +63,6 @@ Function Invoke-FileDownload ( [Parameter(Mandatory=$True, ValueFromPipelineByPropertyName = $True)] [ValidateNotNullOrEmpty()] - [ValidatePattern('^http(s)\:\/\/.*\/.*\.(.{3,4})$')] [System.URI]$URL, [Parameter(Mandatory=$False, ValueFromPipelineByPropertyName = $True)] @@ -209,18 +208,13 @@ Function Invoke-FileDownload $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Download Size: $($ContentLengthInMB) MegaBytes" Write-Verbose -Message ($LoggingDetails.LogMessage) - - $Null = Measure-Command -Expression {[Byte[]]$DownloadedData = $WebClient.DownloadData($URL.OriginalString)} -OutVariable 'DownloadExecutionTimespan' - - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Stream download took $($DownloadExecutionTimespan.Hours.ToString()) hour(s), $($DownloadExecutionTimespan.Minutes.ToString()) minute(s), $($DownloadExecutionTimespan.Seconds.ToString()) second(s), and $($DownloadExecutionTimespan.Milliseconds.ToString()) millisecond(s)" - Write-Verbose -Message ($LoggingDetails.LogMessage) - - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to flush the downloaded data stream to file `"$($DestinationPath.FullName)`". Please Wait..." - Write-Verbose -Message ($LoggingDetails.LogMessage) - + If ([System.IO.Directory]::Exists($DestinationPath.Directory.FullName) -eq $False) {$Null = [System.IO.Directory]::CreateDirectory($DestinationPath.Directory.FullName)} + + $Null = Measure-Command -Expression {$Null = $WebClient.DownloadFile($URL.OriginalString, $DestinationPath.FullName)} -OutVariable 'DownloadExecutionTimespan' - $Null = [System.IO.File]::WriteAllBytes($DestinationPath.FullName, $DownloadedData) + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - File download took $($Global:DownloadExecutionTimespan.Hours.ToString()) hour(s), $($Global:DownloadExecutionTimespan.Minutes.ToString()) minute(s), $($Global:DownloadExecutionTimespan.Seconds.ToString()) second(s), and $($Global:DownloadExecutionTimespan.Milliseconds.ToString()) millisecond(s)" + Write-Verbose -Message ($LoggingDetails.LogMessage) [Int]$SecondsToWait = 3 @@ -240,7 +234,7 @@ Function Invoke-FileDownload $Null = (Get-Item -Path $DestinationPath.FullName -Force).LastWriteTimeUTC = $WebRequestHeaders.'Last-Modified' - $Null = $WebClient.Dispose() + Try {$Null = $WebClient.Dispose()} Catch {} } Switch ([System.IO.File]::Exists($DestinationPath.FullName)) @@ -268,7 +262,7 @@ Function Invoke-FileDownload $OutputObjectProperties.DownloadRequired = $True - $ExecuteDownload.InvokeReturnAsIs() + $ExecuteDownload.Invoke() } Default @@ -289,7 +283,7 @@ Function Invoke-FileDownload $OutputObjectProperties.DownloadRequired = $True - $ExecuteDownload.InvokeReturnAsIs() + $ExecuteDownload.Invoke() } } } @@ -298,7 +292,7 @@ Function Invoke-FileDownload $ErrorHandlingDefinition.Invoke() } Finally - { + { Try {$Null = $WebRequestResponse.Dispose()} Catch {} } } @@ -333,6 +327,16 @@ Function Invoke-FileDownload $OutputObjectProperties.DownloadPath = $DestinationPathDetails $OutputObjectProperties.URL = $URL $OutputObjectProperties.URLHeaders = $WebRequestHeaders + + $OutputObjectProperties.CompletionTimespan = $Null + + Switch ($True) + { + {($OutputObjectProperties.DownloadRequired -eq $True)} + { + $OutputObjectProperties.CompletionTimespan = $Global:DownloadExecutionTimespan + } + } $OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties) diff --git a/Functions/Invoke-FileDownloadWithProgress.ps1 b/Functions/Invoke-FileDownloadWithProgress.ps1 index 32384e9..bb71a00 100644 --- a/Functions/Invoke-FileDownloadWithProgress.ps1 +++ b/Functions/Invoke-FileDownloadWithProgress.ps1 @@ -64,7 +64,6 @@ Function Invoke-FileDownloadWithProgress ( [Parameter(Mandatory=$True, ValueFromPipelineByPropertyName = $True)] [ValidateNotNullOrEmpty()] - [ValidatePattern('^http(s)\:\/\/.*\/.*\.(.{3,4})$')] [System.URI]$URL, [Parameter(Mandatory=$False, ValueFromPipelineByPropertyName = $True)] @@ -395,6 +394,8 @@ Function Invoke-FileDownloadWithProgress $WriteProgressParameters.CurrentOperation = "Downloaded $($EventDetails.Received.CalculatedSizeStr) of $($EventDetails.TotalToReceive.CalculatedSizeStr) @ $($TransferRate) Mbps" Write-Progress @WriteProgressParameters + + $Null = Start-Sleep -Milliseconds 1500 } } Catch @@ -432,14 +433,18 @@ Function Invoke-FileDownloadWithProgress } } - $Null = $WebClient.Dispose() + Try {$Null = $Downloader.CancelAsync()} Catch {} + + Try {$Null = $WebClient.CancelAsync()} Catch {} + + Try {$Null = $WebClient.Dispose()} Catch {} $Null = $DownloadExecutionStopwatch.Stop() } - $DownloadExecutionTimespan = $DownloadExecutionStopwatch.Elapsed + $Global:DownloadExecutionTimespan = $DownloadExecutionStopwatch.Elapsed - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Download completed in $($DownloadExecutionTimespan.Hours.ToString()) hour(s), $($DownloadExecutionTimespan.Minutes.ToString()) minute(s), $($DownloadExecutionTimespan.Seconds.ToString()) second(s), and $($DownloadExecutionTimespan.Milliseconds.ToString()) millisecond(s)." + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Download completed in $($Global:DownloadExecutionTimespan.Hours.ToString()) hour(s), $($Global:DownloadExecutionTimespan.Minutes.ToString()) minute(s), $($Global:DownloadExecutionTimespan.Seconds.ToString()) second(s), and $($Global:DownloadExecutionTimespan.Milliseconds.ToString()) millisecond(s)." Write-Verbose -Message ($LoggingDetails.LogMessage) $Null = $DownloadExecutionStopwatch.Reset() @@ -490,7 +495,7 @@ Function Invoke-FileDownloadWithProgress $OutputObjectProperties.DownloadRequired = $True - $ExecuteDownload.InvokeReturnAsIs() + $ExecuteDownload.Invoke() } Default @@ -511,7 +516,7 @@ Function Invoke-FileDownloadWithProgress $OutputObjectProperties.DownloadRequired = $True - $ExecuteDownload.InvokeReturnAsIs() + $ExecuteDownload.Invoke() } } } @@ -555,6 +560,15 @@ Function Invoke-FileDownloadWithProgress $OutputObjectProperties.DownloadPath = $DestinationPathDetails $OutputObjectProperties.URL = $URL $OutputObjectProperties.URLHeaders = $WebRequestHeaders + $OutputObjectProperties.CompletionTimespan = $Null + + Switch ($True) + { + {($OutputObjectProperties.DownloadRequired -eq $True)} + { + $OutputObjectProperties.CompletionTimespan = $Global:DownloadExecutionTimespan + } + } $OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties) diff --git a/Functions/Invoke-ScheduledTaskAction.ps1 b/Functions/Invoke-ScheduledTaskAction.ps1 new file mode 100644 index 0000000..36d32c9 --- /dev/null +++ b/Functions/Invoke-ScheduledTaskAction.ps1 @@ -0,0 +1,876 @@ +## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx + +#region Function Invoke-ScheduledTaskAction +Function Invoke-ScheduledTaskAction + { + <# + .SYNOPSIS + A brief overview of what your function does + + .DESCRIPTION + Slightly more detailed description of what your function does + + .PARAMETER Create + Your parameter description + + .PARAMETER ScheduledTaskDefinition + Your parameter description + + .PARAMETER Force + Your parameter description + + .PARAMETER Remove + Your parameter description + + .PARAMETER ScheduledTaskFolder + Your parameter description + + .PARAMETER ScheduledTaskName + Your parameter description + + .PARAMETER Source + Your parameter description + + .PARAMETER Destination + Your parameter description + + .PARAMETER ScriptName + Your parameter description + + .PARAMETER ScriptParameters + Your parameter description + + .PARAMETER Stage + Your parameter description + + .PARAMETER Execute + Your parameter description + + .PARAMETER ContinueOnError + Your parameter description + + .EXAMPLE + [System.IO.FileInfo]$ScheduledTaskDefinitionPath = 'C:\YourPath\YourExportedScheduledTask.xml' + + [String]$ScheduledTaskDefinition = [System.IO.File]::ReadAllText($ScheduledTaskDefinitionPath.FullName) + + $InvokeScheduledTaskActionParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $InvokeScheduledTaskActionParameters.Create = $True + $InvokeScheduledTaskActionParameters.ScheduledTaskDefinition = $ScheduledTaskDefinition + $InvokeScheduledTaskActionParameters.Force = $True + $InvokeScheduledTaskActionParameters.ScheduledTaskFolder = "\YourScheduledTaskFolder" + $InvokeScheduledTaskActionParameters.ScheduledTaskName = "Your Scheduled Task Name" + $InvokeScheduledTaskActionParameters.Source = "\\YourServer\YourShare\YourScriptDirectory" + $InvokeScheduledTaskActionParameters.ScriptName = "YourPowershellScript.ps1" + $InvokeScheduledTaskActionParameters.ScriptParameters = New-Object -TypeName 'System.Collections.Generic.List[String]' + $InvokeScheduledTaskActionParameters.ScriptParameters.Add('-Verbose') + $InvokeScheduledTaskActionParameters.ScriptParameters = $InvokeScheduledTaskActionParameters.ScriptParameters.ToArray() + $InvokeScheduledTaskActionParameters.Destination = "$($Env:ProgramData)\ScheduledTasks\$([System.IO.Path]::GetFileNameWithoutExtension($InvokeScheduledTaskActionParameters.ScriptName))" + $InvokeScheduledTaskActionParameters.Stage = $True + $InvokeScheduledTaskActionParameters.Execute = $False + $InvokeScheduledTaskActionParameters.ContinueOnError = $False + $InvokeScheduledTaskActionParameters.Verbose = $True + + $InvokeScheduledTaskActionResult = Invoke-ScheduledTaskAction @InvokeScheduledTaskActionParameters + + Write-Output -InputObject ($InvokeScheduledTaskActionResult) + + .EXAMPLE + Invoke-ScheduledTaskAction -Remove -ScheduledTaskFolder '\Custom' -ScheduledTaskName 'Perform Dynamic Software Removal' -Source "$($Env:ProgramData)\ScheduledTasks\Invoke-SoftwareRemoval" -Verbose + + .NOTES + This function uses an older, but more compatible method of creating scheduled tasks. + + .LINK + https://learn.microsoft.com/en-us/windows/win32/taskschd/schtasks + + .LINK + https://ss64.com/nt/schtasks.html + #> + + [CmdletBinding(ConfirmImpact = 'Low', DefaultParameterSetName = 'Create', HelpURI = '', SupportsShouldProcess = $True)] + + Param + ( + [Parameter(Mandatory=$True, ParameterSetName = 'Create')] + [Alias('C')] + [Switch]$Create, + + [Parameter(Mandatory=$True, ParameterSetName = 'Create')] + [ValidateNotNullOrEmpty()] + [Alias('STD')] + [String]$ScheduledTaskDefinition, + + [Parameter(Mandatory=$False, ParameterSetName = 'Create')] + [Alias('F')] + [Switch]$Force, + + [Parameter(Mandatory=$True, ParameterSetName = 'Remove')] + [Alias('R')] + [Switch]$Remove, + + [Parameter(Mandatory=$False, ParameterSetName = 'Create')] + [Parameter(Mandatory=$False, ParameterSetName = 'Remove')] + [ValidateNotNullOrEmpty()] + [ValidateScript({$_.StartsWith('\')})] + [Alias('STF')] + [String]$ScheduledTaskFolder, + + [Parameter(Mandatory=$True, ParameterSetName = 'Create')] + [Parameter(Mandatory=$True, ParameterSetName = 'Remove')] + [ValidateNotNullOrEmpty()] + [Alias('STN')] + [String]$ScheduledTaskName, + + [Parameter(Mandatory=$False, ParameterSetName = 'Create')] + [Parameter(Mandatory=$False, ParameterSetName = 'Remove')] + [ValidateNotNullOrEmpty()] + [Alias('SD')] + [System.IO.DirectoryInfo]$Source, + + [Parameter(Mandatory=$False, ParameterSetName = 'Create')] + [ValidateNotNullOrEmpty()] + [Alias('DD')] + [System.IO.DirectoryInfo]$Destination, + + [Parameter(Mandatory=$True, ParameterSetName = 'Create')] + [ValidateNotNullOrEmpty()] + [Alias('SN')] + [ValidateScript({$_ -imatch '^.*\.(bat|cmd|ps1|vbs|wsf)$'})] + [String]$ScriptName, + + [Parameter(Mandatory=$False, ParameterSetName = 'Create')] + [AllowEmptyCollection()] + [AllowNull()] + [Alias('SP')] + [String[]]$ScriptParameters, + + [Parameter(Mandatory=$False, ParameterSetName = 'Create')] + [Alias('S')] + [Switch]$Stage, + + [Parameter(Mandatory=$False, ParameterSetName = 'Create')] + [Alias('E')] + [Switch]$Execute, + + [Parameter(Mandatory=$False)] + [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) + $ParameterSetName = $PSCmdlet.ParameterSetName + + [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 + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Parameter Set Name: $($ParameterSetName)" + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + #Create an object that will contain the functions output. + $OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + + #Define additional variable(s) + [System.IO.DirectoryInfo]$DefaultStagingDirectory = "$($Env:ProgramData)\ScheduledTasks\$([System.IO.Path]::GetFileNameWithoutExtension($ScriptName))" + + #Define default parameter value(s) + Switch ($True) + { + {([String]::IsNullOrEmpty($ScheduledTaskFolder) -eq $True) -or ([String]::IsNullOrWhiteSpace($ScheduledTaskFolder) -eq $True)} + { + $ScheduledTaskFolder = '\' + } + + {([String]::IsNullOrEmpty($Destination) -eq $True) -or ([String]::IsNullOrWhiteSpace($Destination) -eq $True)} + { + [System.IO.DirectoryInfo]$Destination = $DefaultStagingDirectory.FullName + } + + {($ParameterSetName -iin @('Remove')) -and ([String]::IsNullOrEmpty($Source) -eq $True) -or ([String]::IsNullOrWhiteSpace($Source) -eq $True)} + { + [System.IO.DirectoryInfo]$Source = $DefaultStagingDirectory.FullName + } + } + } + Catch + { + $ErrorHandlingDefinition.Invoke() + } + Finally + { + + } + } + + Process + { + Try + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to retrieve the list of scheduled task(s). Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $GetScheduledTaskListResult = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + + $Process = New-Object -TypeName 'System.Diagnostics.Process' + $Process.StartInfo.FileName = "$([System.Environment]::SystemDirectory)\schtasks.exe" + $Process.StartInfo.UseShellExecute = $False + $Process.StartInfo.RedirectStandardOutput = $True + $Process.StartInfo.RedirectStandardError = $True + $Process.StartInfo.CreateNoWindow = $True + $Process.StartInfo.Arguments = "/Query /FO CSV" + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to execute command: `"$($Process.StartInfo.FileName)`" $($Process.StartInfo.Arguments)" + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $Null = $Process.Start() + + $GetScheduledTaskListResult.StandardOutput = $Process.StandardOutput.ReadToEnd() + $GetScheduledTaskListResult.StandardError = $Process.StandardError.ReadToEnd() + + $Null = $Process.WaitForExit() + + $GetScheduledTaskListResult.ExitCode = $Process.ExitCode + + Switch ($GetScheduledTaskListResult.ExitCode -iin @(0)) + { + {($_ -eq $True)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The command execution was successful. [Exit Code: $($GetScheduledTaskListResult.ExitCode)]" + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $ScheduledTaskObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]' + + $ScheduledTaskList = $GetScheduledTaskListResult.StandardOutput | ConvertFrom-CSV -Delimiter ',' | Where-Object {($_.TaskName -inotmatch '(^TaskName$)')} | Sort-Object -Property @('TaskName') -Unique + + ForEach ($ScheduledTask In $ScheduledTaskList) + { + $ScheduledTaskObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $ScheduledTaskObjectProperties.TaskFolder = Split-Path -Path $ScheduledTask.TaskName -Parent + $ScheduledTaskObjectProperties.TaskName = Split-Path -Path $ScheduledTask.TaskName -Leaf + $ScheduledTaskObjectProperties.TaskSchedulerPath = $Null + $ScheduledTaskObjectProperties.Status = $ScheduledTask.Status + $ScheduledTaskObjectProperties.NextRunTime = $Null + + Switch (($ScheduledTaskObjectProperties.TaskFolder -ieq '\')) + { + {($_ -eq $True)} + { + $ScheduledTaskObjectProperties.TaskFolder = '\' + + $ScheduledTaskObjectProperties.TaskSchedulerPath = "$($ScheduledTaskObjectProperties.TaskFolder)$($ScheduledTaskObjectProperties.TaskName)" + } + + Default + { + $ScheduledTaskObjectProperties.TaskFolder = $ScheduledTaskObjectProperties.TaskFolder.TrimStart('\').TrimEnd('\') + + $ScheduledTaskObjectProperties.TaskSchedulerPath = "\$($ScheduledTaskObjectProperties.TaskFolder)\$($ScheduledTaskObjectProperties.TaskName)" + } + } + + $DateTime = New-Object -TypeName 'DateTime' + + $DateTimeProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $DateTimeProperties.Input = $ScheduledTask.'Next Run Time' + $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]::AllowWhiteSpaces) + $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 ($DateTimeProperties.Successful) + { + {($_ -eq $True)} + { + $ScheduledTaskObjectProperties.NextRunTime = $DateTimeObject.DateTime + } + } + + $ScheduledTaskObject = New-Object -TypeName 'PSObject' -Property ($ScheduledTaskObjectProperties) + + $ScheduledTaskObjectList.Add($ScheduledTaskObject) + } + + $ScheduledTaskObjectList = $ScheduledTaskObjectList | Sort-Object -Property @('TaskFolder', 'TaskName') + + $OutputObjectProperties.ScheduledTaskList = $ScheduledTaskObjectList + + $ExistingScheduledTask = $ScheduledTaskObjectList | Where-Object {($_.TaskFolder -ieq $ScheduledTaskFolder.TrimStart('\')) -and ($_.TaskName -ieq $ScheduledTaskName)} + + $ExistingScheduledTaskCount = ($ExistingScheduledTask | Measure-Object).Count + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Located $($ExistingScheduledTaskCount) scheduled task(s) located within the folder of `"$($ScheduledTaskFolder)`" with a task name of `"$($ScheduledTaskName)`"." + Write-Verbose -Message ($LoggingDetails.LogMessage) + + [String]$ScheduledTaskLocation = "$($ScheduledTaskFolder)\$($ScheduledTaskName)" + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Desired Scheduled Task Location: $($ScheduledTaskLocation)" + Write-Verbose -Message ($LoggingDetails.LogMessage) + + Switch ($ParameterSetName) + { + {($_ -iin @('Create'))} + { + [System.IO.FileInfo]$ScriptSourcePath = "$($Source.FullName)\$($ScriptName)" + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Script Source Path: $($ScriptSourcePath.FullName)" + Write-Verbose -Message ($LoggingDetails.LogMessage) + + [System.IO.FileInfo]$ScriptDestinationPath = "$($Destination.FullName)\$($ScriptName)" + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Script Destination Path: $($ScriptDestinationPath.FullName)" + Write-Verbose -Message ($LoggingDetails.LogMessage) + + Switch (($ExistingScheduledTaskCount -eq 0) -or ($Force.IsPresent -eq $True)) + { + {($_ -eq $True)} + { + $XMLConfigurationTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $XMLConfigurationTable.Content = $ScheduledTaskDefinition + $XMLConfigurationTable.Document = New-Object -TypeName 'System.XML.XMLDocument' + $XMLConfigurationTable.Document.LoadXML($XMLConfigurationTable.Content) + + $CommandExecutionObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]' + + Switch ($Stage.IsPresent) + { + {($_ -eq $True)} + { + $ArgumentsNodeValueList = New-Object -TypeName 'System.Collections.Generic.List[String]' + + Switch ($ScriptSourcePath.Extension) + { + {($_ -iin @('.bat', '.cmd'))} + { + $CommandNodeValue = "`"$([System.Environment]::SystemDirectory)\cmd.exe`"" + + $ArgumentsNodeValueList.Add('/c') + $ArgumentsNodeValueList.Add("`"$($ScriptDestinationPath.FullName)`"") + + Switch ($ScriptParameters.Count -gt 0) + { + {($_ -eq $True)} + { + ForEach ($ScriptParameter In $ScriptParameters) + { + $ArgumentsNodeValueList.Add($ScriptParameter) + } + } + } + } + + {($_ -iin @('.ps1'))} + { + $CommandNodeValue = "`"$([System.Environment]::SystemDirectory)\WindowsPowerShell\v1.0\powershell.exe`"" + + $ArgumentsNodeValueList.Add('-ExecutionPolicy Bypass') + $ArgumentsNodeValueList.Add('-NonInteractive') + $ArgumentsNodeValueList.Add('-NoProfile') + $ArgumentsNodeValueList.Add('-NoLogo') + $ArgumentsNodeValueList.Add('-WindowStyle Hidden') + $ArgumentsNodeValueList.Add('-Command') + $ArgumentsNodeValueList.Add("`"& '$($ScriptDestinationPath.FullName)'") + + Switch ($ScriptParameters.Count -gt 0) + { + {($_ -eq $True)} + { + ForEach ($ScriptParameter In $ScriptParameters) + { + $ArgumentsNodeValueList.Add($ScriptParameter) + } + } + } + + $ArgumentsNodeValueListTargetIndex = $ArgumentsNodeValueList.Count - 1 + + $ArgumentsNodeValueListIndexItem = $ArgumentsNodeValueList[$ArgumentsNodeValueListTargetIndex] + + $Null = $ArgumentsNodeValueList.RemoveAt($ArgumentsNodeValueListTargetIndex) + + $Null = $ArgumentsNodeValueList.Insert($ArgumentsNodeValueListTargetIndex, ($ArgumentsNodeValueListIndexItem + ';')) + + $ArgumentsNodeValueList.Add("[System.Environment]::Exit((`$LASTEXITCODE -Bor [Int](-Not `$? -And -Not `$LASTEXITCODE)))`"") + } + + {($_ -iin @('.vbs', '.wsf'))} + { + $CommandNodeValue = "`"$([System.Environment]::SystemDirectory)\cscript.exe`"" + + $ArgumentsNodeValueList.Add('//nologo') + $ArgumentsNodeValueList.Add('//B') + $ArgumentsNodeValueList.Add("`"$($ScriptDestinationPath.FullName)`"") + + Switch ($ScriptParameters.Count -gt 0) + { + {($_ -eq $True)} + { + ForEach ($ScriptParameter In $ScriptParameters) + { + $ArgumentsNodeValueList.Add($ScriptParameter) + } + } + } + } + } + + Switch (([String]::IsNullOrEmpty($CommandNodeValue) -eq $False) -and ([String]::IsNullOrWhiteSpace($CommandNodeValue) -eq $False)) + { + {($_ -eq $True)} + { + Switch ($ArgumentsNodeValueList.Count -gt 0) + { + {($_ -eq $True)} + { + $ArgumentsNodeValue = $ArgumentsNodeValueList -Join ' ' + + $ScheduledTaskNamespaceURI = $XMLConfigurationTable.Document.Task.NamespaceURI + + $ActionsNodeList = $XMLConfigurationTable.Document.Task.ChildNodes | Where-Object {($_.Name -iin @('Actions'))} + + Switch ($Null -ieq $ActionsNodeList) + { + {($_ -eq $True)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to add the `"Actions`" node. Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $ActionsNode = $XMLConfigurationTable.Document.Task.AppendChild($XMLConfigurationTable.Document.CreateElement('Actions', $ScheduledTaskNamespaceURI)) + + $Null = $ActionsNode.SetAttribute('Context', 'Author') + } + + Default + { + $ActionsNode = $XMLConfigurationTable.Document.Task.Actions + } + } + + $ExecutionNodeList = $ActionsNode.Exec + + $ExecutionNodeListCount = ($ExecutionNodeList | Measure-Object).Count + + Switch ($ExecutionNodeListCount) + { + {($_ -gt 0)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to remove all $($ActionsNode.ChildNodes.Count) child node(s) from underneath of the `"Actions`" node. Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $Null = $ActionsNode.RemoveAll() + } + } + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to add an `"Exec`" node to the scheduled task definition to initiate script execution. Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Command: $($CommandNodeValue)" + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Arguments: $($ArgumentsNodeValue)" + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $ExecutionNode = $ActionsNode.AppendChild($XMLConfigurationTable.Document.CreateElement('Exec', $ScheduledTaskNamespaceURI)) + + $CommandNode = $ExecutionNode.AppendChild($XMLConfigurationTable.Document.CreateElement('Command', $ScheduledTaskNamespaceURI)) + $Null = $CommandNode.AppendChild($XMLConfigurationTable.Document.CreateTextNode($CommandNodeValue)) + + $ArgumentsNode = $ExecutionNode.AppendChild($XMLConfigurationTable.Document.CreateElement('Arguments', $ScheduledTaskNamespaceURI)) + $Null = $ArgumentsNode.AppendChild($XMLConfigurationTable.Document.CreateTextNode($ArgumentsNodeValue)) + } + + Default + { + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The argument list could not be determined for the `"$($ScriptName)`" script." + Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose + } + } + } + + Default + { + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The command could not be determined for the `"$($ScriptName)`" script." + Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose + } + } + } + } + + [System.IO.FileInfo]$ScheduledTaskDefinitionPath = "$($Env:Temp.TrimEnd('\'))\$($FunctionName).xml" + + Switch ([System.IO.Directory]::Exists($ScheduledTaskDefinitionPath.Directory.FullName)) + { + {($_ -eq $False)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to create the scheduled task definition export directory of `"$($ScheduledTaskDefinitionPath.Directory.FullName)`". Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $Null = [System.IO.Directory]::CreateDirectory($ScheduledTaskDefinitionPath.Directory.FullName) + } + } + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to export the scheduled task definition of `"$($ScheduledTaskDefinitionPath.FullName)`". Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $Null = $XMLConfigurationTable.Document.Save($ScheduledTaskDefinitionPath.FullName) + + $Null = Start-Sleep -Seconds 2 + + $CommandExecutionObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]' + + $CommandExecutionProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $CommandExecutionProperties.Condition = ($Stage.IsPresent -eq $True) -and ([System.IO.Directory]::Exists($Source.FullName)) + $CommandExecutionProperties.Command = "$([System.Environment]::SystemDirectory)\robocopy.exe" + $CommandExecutionProperties.ArgumentList = New-Object -TypeName 'System.Collections.Generic.List[String]' + $CommandExecutionProperties.ArgumentList.Add("`"$($ScriptSourcePath.Directory.FullName)`"") + $CommandExecutionProperties.ArgumentList.Add("`"$($ScriptDestinationPath.Directory.FullName)`"") + $CommandExecutionProperties.ArgumentList.Add('/E') + $CommandExecutionProperties.ArgumentList.Add('/PURGE') + $CommandExecutionProperties.ArgumentList.Add('/Z') + $CommandExecutionProperties.ArgumentList.Add('/ZB') + $CommandExecutionProperties.ArgumentList.Add('/W:5') + $CommandExecutionProperties.ArgumentList.Add('/R:3') + $CommandExecutionProperties.ArgumentList.Add('/J') + $CommandExecutionProperties.ArgumentList.Add('/NP') + $CommandExecutionProperties.ArgumentList.Add('/FP') + $CommandExecutionProperties.ArgumentList.Add('/TS') + $CommandExecutionProperties.ArgumentList.Add('/NDL') + $CommandExecutionProperties.ArgumentList.Add('/TEE') + $CommandExecutionProperties.ArgumentList.Add('/MT:8') + $CommandExecutionProperties.AcceptableExitCodes = @(0, 1, 2, 3, 4, 5, 6, 7, 8) + $CommandExecutionEntry = New-Object -TypeName 'PSObject' -Property ($CommandExecutionProperties) + $CommandExecutionObjectList.Add($CommandExecutionEntry) + + $CommandExecutionProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $CommandExecutionProperties.Condition = $Create.IsPresent + $CommandExecutionProperties.Command = "$([System.Environment]::SystemDirectory)\schtasks.exe" + $CommandExecutionProperties.ArgumentList = New-Object -TypeName 'System.Collections.Generic.List[String]' + $CommandExecutionProperties.ArgumentList.Add('/Create') + $CommandExecutionProperties.ArgumentList.Add('/XML') + $CommandExecutionProperties.ArgumentList.Add("`"$($ScheduledTaskDefinitionPath.FullName)`"") + $CommandExecutionProperties.ArgumentList.Add('/TN') + $CommandExecutionProperties.ArgumentList.Add("`"$($ScheduledTaskLocation)`"") + $CommandExecutionProperties.ArgumentList.Add('/F') + $CommandExecutionProperties.AcceptableExitCodes = @(0) + $CommandExecutionEntry = New-Object -TypeName 'PSObject' -Property ($CommandExecutionProperties) + $CommandExecutionObjectList.Add($CommandExecutionEntry) + + $CommandExecutionProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $CommandExecutionProperties.Condition = $Execute.IsPresent + $CommandExecutionProperties.Command = "$([System.Environment]::SystemDirectory)\schtasks.exe" + $CommandExecutionProperties.ArgumentList = New-Object -TypeName 'System.Collections.Generic.List[String]' + $CommandExecutionProperties.ArgumentList.Add('/Run') + $CommandExecutionProperties.ArgumentList.Add('/TN') + $CommandExecutionProperties.ArgumentList.Add("`"$($ScheduledTaskLocation)`"") + $CommandExecutionProperties.ArgumentList.Add('/I') + $CommandExecutionProperties.AcceptableExitCodes = @(0) + $CommandExecutionEntry = New-Object -TypeName 'PSObject' -Property ($CommandExecutionProperties) + $CommandExecutionObjectList.Add($CommandExecutionEntry) + + ForEach ($CommandExecutionObject In $CommandExecutionObjectList) + { + Switch ($CommandExecutionObject.Condition) + { + {($_ -eq $True)} + { + $Process = New-Object -TypeName 'System.Diagnostics.Process' + $Process.StartInfo.FileName = "$($CommandExecutionObject.Command)" + $Process.StartInfo.UseShellExecute = $False + $Process.StartInfo.RedirectStandardOutput = $False + $Process.StartInfo.RedirectStandardError = $False + $Process.StartInfo.CreateNoWindow = $True + $Process.StartInfo.Arguments = "$($CommandExecutionObject.ArgumentList -Join ' ')" + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to execute command: `"$($Process.StartInfo.FileName)`" $($Process.StartInfo.Arguments)" + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $Null = $Process.Start() + + $Null = $Process.WaitForExit() + + Switch ($Process.ExitCode -in $CommandExecutionObject.AcceptableExitCodes) + { + {($_ -eq $True)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The command execution was successful. [Exit Code: $($Process.ExitCode)]" + Write-Verbose -Message ($LoggingDetails.LogMessage) + } + + Default + { + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The command execution was unsuccessful. [Exit Code: $($Process.ExitCode)]" + 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) + } + } + } + + Default + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Skipping the command execution of `"$($CommandExecutionObject.Command)`" $($CommandExecutionObject.ArgumentList -Join ' ')" + Write-Verbose -Message ($LoggingDetails.LogMessage) + } + } + } + + $Null = Start-Sleep -Seconds 2 + + Switch ([System.IO.File]::Exists($ScheduledTaskDefinitionPath.FullName)) + { + {($_ -eq $True)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to delete the exported scheduled task definition of `"$($ScheduledTaskDefinitionPath.FullName)`". Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $Null = [System.IO.File]::Delete($ScheduledTaskDefinitionPath.FullName) + } + } + } + + Default + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The specified scheduled task already exist(s)." + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Scheduled Task Folder: $($ScheduledTaskFolder)" + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Scheduled Task Name: $($ScheduledTaskName)" + Write-Verbose -Message ($LoggingDetails.LogMessage) + } + } + } + + {($_ -iin @('Remove'))} + { + Switch ($ExistingScheduledTaskCount -gt 0) + { + {($_ -eq $True)} + { + $CommandExecutionObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]' + + $CommandExecutionProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $CommandExecutionProperties.Condition = $Remove.IsPresent + $CommandExecutionProperties.Command = "$([System.Environment]::SystemDirectory)\schtasks.exe" + $CommandExecutionProperties.ArgumentList = New-Object -TypeName 'System.Collections.Generic.List[String]' + $CommandExecutionProperties.ArgumentList.Add('/Delete') + $CommandExecutionProperties.ArgumentList.Add('/TN') + $CommandExecutionProperties.ArgumentList.Add("`"$($ScheduledTaskLocation)`"") + $CommandExecutionProperties.ArgumentList.Add('/F') + $CommandExecutionProperties.AcceptableExitCodes = @(0) + $CommandExecutionEntry = New-Object -TypeName 'PSObject' -Property ($CommandExecutionProperties) + $CommandExecutionObjectList.Add($CommandExecutionEntry) + + ForEach ($CommandExecutionObject In $CommandExecutionObjectList) + { + Switch ($CommandExecutionObject.Condition) + { + {($_ -eq $True)} + { + $Process = New-Object -TypeName 'System.Diagnostics.Process' + $Process.StartInfo.FileName = "$($CommandExecutionObject.Command)" + $Process.StartInfo.UseShellExecute = $False + $Process.StartInfo.RedirectStandardOutput = $False + $Process.StartInfo.RedirectStandardError = $False + $Process.StartInfo.CreateNoWindow = $True + $Process.StartInfo.Arguments = "$($CommandExecutionObject.ArgumentList -Join ' ')" + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to execute command: `"$($Process.StartInfo.FileName)`" $($Process.StartInfo.Arguments)" + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $Null = $Process.Start() + + $Null = $Process.WaitForExit() + + Switch ($Process.ExitCode -in $CommandExecutionObject.AcceptableExitCodes) + { + {($_ -eq $True)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The command execution was successful. [Exit Code: $($Process.ExitCode)]" + Write-Verbose -Message ($LoggingDetails.LogMessage) + } + + Default + { + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The command execution was unsuccessful. [Exit Code: $($Process.ExitCode)]" + 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) + } + } + } + + Default + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Skipping the command execution of `"$($CommandExecutionObject.Command)`" $($CommandExecutionObject.ArgumentList -Join ' ')" + Write-Verbose -Message ($LoggingDetails.LogMessage) + } + } + } + + $Null = Start-Sleep -Seconds 2 + + Switch ([System.IO.Directory]::Exists($Source.FullName)) + { + {($_ -eq $True)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Script Source Path: $($Source.FullName)" + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to remove scheduled task content directory `"$($Source.FullName)`". Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) + + $Null = [System.IO.Directory]::Delete($Source.FullName, $True) + } + } + } + + Default + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The scheduled task of `"$($ScheduledTaskLocation)`" does not exist. No further action will be taken." + Write-Verbose -Message ($LoggingDetails.LogMessage) + } + } + } + } + } + + {($_ -eq $False)} + { + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The command execution was unsuccessful. [Exit Code: $($GetScheduledTaskListResult.ExitCode)]" + 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) + } + } + } + Catch + { + $ErrorHandlingDefinition.Invoke() + } + Finally + { + + } + } + + End + { + Try + { + #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 + $OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties) + + Write-Output -InputObject ($OutputObject) + } + } + } +#endregion \ No newline at end of file diff --git a/Invoke-ConfigurationGenerator.ps1 b/Invoke-ConfigurationGenerator.ps1 index 24eb5d8..c97d498 100644 --- a/Invoke-ConfigurationGenerator.ps1 +++ b/Invoke-ConfigurationGenerator.ps1 @@ -25,15 +25,15 @@ .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%" + cscript.exe /nologo "%FolderPathContainingScript%\%ScriptName%.vbs" /Boolean /ScriptParameter:"%ScriptParameterValue%" /ScriptParameterArray:"%ScriptParameterValue1%,%ScriptParameterValue2%" - wscript.exe /nologo "%FolderPathContainingScript%\%ScriptName%.vbs" /SwitchParameter /ScriptParameter:"%ScriptParameterValue%" /ScriptParameterArray:"%ScriptParameterValue1%,%ScriptParameterValue2%" + wscript.exe /nologo "%FolderPathContainingScript%\%ScriptName%.vbs" /Boolean /ScriptParameter:"%ScriptParameterValue%" /ScriptParameterArray:"%ScriptParameterValue1%,%ScriptParameterValue2%" .EXAMPLE - powershell.exe -ExecutionPolicy Bypass -NoProfile -NoLogo -File "%FolderPathContainingScript%\%ScriptName%.ps1" -SwitchParameter -ScriptParameter "%ScriptParameterValue%" + powershell.exe -ExecutionPolicy Bypass -NoProfile -NoLogo -File "%FolderPathContainingScript%\%ScriptName%.ps1" -Boolean -ScriptParameter "%ScriptParameterValue%" .EXAMPLE - powershell.exe -ExecutionPolicy Bypass -NonInteractive -NoProfile -NoLogo -WindowStyle Hidden -Command "& '%FolderPathContainingScript%\%ScriptName%.ps1' -ScriptParameter1 '%ScriptParameter1Value%' -ScriptParameter2 %ScriptParameter2Value% -SwitchParameter" + powershell.exe -ExecutionPolicy Bypass -NonInteractive -NoProfile -NoLogo -WindowStyle Hidden -Command "& '%FolderPathContainingScript%\%ScriptName%.ps1' -ScriptParameter1 '%ScriptParameter1Value%' -ScriptParameter2 %ScriptParameter2Value% -Boolean" .NOTES If using the database query functionality to get the model list, just ensure that the following columns are returned in order for the XML schema to be generated correctly. @@ -511,7 +511,7 @@ Else } $ManufacturerListObject = New-Object -TypeName 'PSObject' -Property ($ManufacturerListEntry) - $ManufacturerList.Add($ManufacturerListEntry) + $ManufacturerList.Add($ManufacturerListEntry) $ManufacturerListEntry = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' $ManufacturerListEntry.Enabled = $True @@ -530,7 +530,7 @@ Else } $ManufacturerListObject = New-Object -TypeName 'PSObject' -Property ($ManufacturerListEntry) - $ManufacturerList.Add($ManufacturerListEntry) + $ManufacturerList.Add($ManufacturerListEntry) $ManufacturerListEntry = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' $ManufacturerListEntry.Enabled = $True @@ -549,7 +549,7 @@ Else } $ManufacturerListObject = New-Object -TypeName 'PSObject' -Property ($ManufacturerListEntry) - $ManufacturerList.Add($ManufacturerListObject) + $ManufacturerList.Add($ManufacturerListObject) Switch ($QuerySQLDatabase.IsPresent) { @@ -648,7 +648,7 @@ Else $XMLWriterSettings = New-Object -TypeName 'System.XML.XMLWriterSettings' $XMLWriterSettings.Indent = $True $XMLWriterSettings.IndentChars = "`t" * 1 - $XMLWriterSettings.Encoding = [System.Text.Encoding]::Default + $XMLWriterSettings.Encoding = [System.Text.Encoding]::UTF8 $XMLWriterSettings.NewLineHandling = [System.XML.NewLineHandling]::None $XMLWriterSettings.ConformanceLevel = [System.XML.ConformanceLevel]::Auto @@ -737,10 +737,40 @@ SystemVersion : $XMLWriter.WriteStartElement('Settings') - $XMLWriter.WriteElementString('GeneratedBy', [System.Security.Principal.WindowsIdentity]::GetCurrent().Name) - $XMLWriter.WriteElementString('GeneratedOn', $Env:ComputerName.ToUpper()) - $XMLWriter.WriteElementString('GeneratedDate', $GetXMLDateCreated.InvokeReturnAsIs()) + $TargetScriptParameterList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]' + $TargetScriptParameterList.Add((New-Object -TypeName 'PSObject' -Property ([Ordered]@{Name = 'ApplicationDataRootDirectory'; Value = '$($Env:Windir)\Temp\$($ScriptPath.BaseName)'; Type = 'System.IO.DirectoryInfo'}))) + $TargetScriptParameterList.Add((New-Object -TypeName 'PSObject' -Property ([Ordered]@{Name = 'StagingDirectory'; Value = '$($ApplicationDataRootDirectory.FullName)'; Type = 'System.IO.DirectoryInfo'}))) + $TargetScriptParameterList.Add((New-Object -TypeName 'PSObject' -Property ([Ordered]@{Name = 'DownloadDirectory'; Value = '$($StagingDirectory.FullName)\Downloads'; Type = 'System.IO.DirectoryInfo'}))) + $TargetScriptParameterList.Add((New-Object -TypeName 'PSObject' -Property ([Ordered]@{Name = 'DriverPackageDirectory'; Value = '$($ApplicationDataRootDirectory.FullName)\Out-Of-Box-Driver-Packages'; Type = 'System.IO.DirectoryInfo'}))) + $TargetScriptParameterList.Add((New-Object -TypeName 'PSObject' -Property ([Ordered]@{Name = 'DisableDownload'; Value = $False; Type = 'Boolean'}))) + $TargetScriptParameterList.Add((New-Object -TypeName 'PSObject' -Property ([Ordered]@{Name = 'EnableRobocopyIPG'; Value = $False; Type = 'Boolean'}))) + $TargetScriptParameterList.Add((New-Object -TypeName 'PSObject' -Property ([Ordered]@{Name = 'Force'; Value = $False; Type = 'Boolean'}))) + $TargetScriptParameterList.Add((New-Object -TypeName 'PSObject' -Property ([Ordered]@{Name = 'ContinueOnError'; Value = $False; Type = 'Boolean'}))) + Switch ($TargetScriptParameterList.Count -gt 0) + { + {($_ -eq $True)} + { + $XMLWriter.WriteStartElement('ParameterList') + + For ($TargetScriptParameterListIndex = 0; $TargetScriptParameterListIndex -lt $TargetScriptParameterList.Count; $TargetScriptParameterListIndex++) + { + $TargetScriptParameterListItem = $TargetScriptParameterList[$TargetScriptParameterListIndex] + + $XMLWriter.WriteStartElement('Parameter') + + ForEach ($Property In $TargetScriptParameterListItem.PSObject.Properties) + { + $XMLWriter.WriteAttributeString($Property.Name, $Property.Value) + } + + $XMLWriter.WriteEndElement() + } + + $XMLWriter.WriteEndElement() + } + } + $XMLWriter.WriteStartElement('OperatingSystemList') $OperatingSystemList = Get-WindowsReleaseHistory | Sort-Object -Property @('Name') -Unique @@ -822,7 +852,7 @@ SystemVersion : $DriverPackageCreationXMLContents = $XMLStringBuilder.ToString() - [System.IO.FileInfo]$DriverPackageCreationXMLExportPath = "$($ContentDirectory.FullName)\Templates\SettingsTemplate.xml" + [System.IO.FileInfo]$DriverPackageCreationXMLExportPath = "$($ContentDirectory.FullName)\Settings\Template.xml" [Scriptblock]$ExportDriverPackageCreationXML = { $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to export the driver package settings XML to `"$($DriverPackageCreationXMLExportPath.FullName)`". Please Wait..." @@ -838,22 +868,23 @@ SystemVersion : {($_ -eq $True)} { $MemoryStream = New-Object -TypeName 'System.IO.MemoryStream' + $StreamWriter = New-Object -TypeName 'System.IO.StreamWriter' -ArgumentList ($MemoryStream) - $Null = $StreamWriter.Write($DriverPackageCreationXMLContents) - $Null = $StreamWriter.Flush() - $Null = $MemoryStream.Position = 0 + $Null = $StreamWriter.Write($DriverPackageCreationXMLContents) + $Null = $StreamWriter.Flush() + $Null = $MemoryStream.Position = 0 $DriverPackageCreationXMLContentHash = Get-FileHash -InputStream $MemoryStream -Algorithm ($HashAlgorithm) - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - New Driver Package Settings XML Hash: $($DriverPackageCreationXMLContentHash.Hash)" + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - New Driver Package Settings XML Hash: $($DriverPackageCreationXMLContentHash.Hash.ToUpper())" Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose $DriverPackageCreationXMLExportPathHash = Get-FileHash -Path ($DriverPackageCreationXMLExportPath.FullName) -Algorithm ($HashAlgorithm) - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Current Driver Package Settings XML Hash: $($DriverPackageCreationXMLExportPathHash.Hash)" + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Current Driver Package Settings XML Hash: $($DriverPackageCreationXMLExportPathHash.Hash.ToUpper())" Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - Switch ($DriverPackageCreationXMLContentHash.Hash -ne $DriverPackageCreationXMLExportPathHash.Hash) + Switch ($DriverPackageCreationXMLContentHash.Hash.ToUpper() -ne $DriverPackageCreationXMLExportPathHash.Hash.ToUpper()) { {($_ -eq $True)} { diff --git a/Invoke-ConfigurationGenerator.vbs b/Invoke-ConfigurationGenerator.vbs deleted file mode 100644 index 2190820..0000000 --- a/Invoke-ConfigurationGenerator.vbs +++ /dev/null @@ -1,145 +0,0 @@ -'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/Invoke-DriverPackageCreator.ps1 b/Invoke-DriverPackageCreator.ps1 index 050928f..de6632e 100644 --- a/Invoke-DriverPackageCreator.ps1 +++ b/Invoke-DriverPackageCreator.ps1 @@ -38,44 +38,8 @@ ( [Parameter(Mandatory=$False)] [ValidateNotNullOrEmpty()] - [ValidateScript({Test-Path -Path $_})] - [Alias('SP')] - [System.IO.FileInfo]$SettingsPath, - - [Parameter(Mandatory=$False)] - [ValidateNotNullOrEmpty()] - [Alias('CatalogRoot', 'CD', 'CDR')] - [System.IO.DirectoryInfo]$CatalogDirectory, - - [Parameter(Mandatory=$False)] - [ValidateNotNullOrEmpty()] - [Alias('DLD')] - [System.IO.DirectoryInfo]$DownloadDirectory, - - [Parameter(Mandatory=$False)] - [ValidateNotNullOrEmpty()] - [Alias('DPD')] - [System.IO.DirectoryInfo]$DriverPackageDirectory, - - [Parameter(Mandatory=$False)] - [Alias('DD', 'DDL')] - [Switch]$DisableDownload, - - [Parameter(Mandatory=$False)] - [Alias('ERI')] - [Switch]$EnableRobocopyIPG, - - [Parameter(Mandatory=$False)] - [Alias('F')] - [Switch]$Force, - - [Parameter(Mandatory=$False)] - [ValidateNotNullOrEmpty()] - [Alias('LogDir', 'LogPath')] - [System.IO.DirectoryInfo]$LogDirectory, - - [Parameter(Mandatory=$False)] - [Switch]$ContinueOnError + [Alias('AXN')] + [String[]]$AdditionalXMLNodes ) Function Get-AdministrativePrivilege @@ -195,7 +159,7 @@ Else Write-Warning -Message ($LoggingDetails.ErrorMessage) -Verbose } - Switch (($ContinueOnError.IsPresent -eq $False) -or ($ContinueOnError -eq $False)) + Switch (($ContinueOnError -eq $False) -or ($ContinueOnError -eq $False)) { {($_ -eq $True)} { @@ -205,64 +169,11 @@ Else } #Determine default parameter value(s) - [System.IO.DirectoryInfo]$ApplicationDataRootDirectory = "$($Env:ProgramData)\$($ScriptPath.BaseName)" - - [System.IO.DirectoryInfo]$StagingDirectory = "$($Env:Windir)\Temp\$($ScriptPath.BaseName)" - - [System.IO.DirectoryInfo]$LocalDriverPackageDirectory = "$($StagingDirectory.FullName)\Packages" - Switch ($True) - { - {([String]::IsNullOrEmpty($SettingsPath) -eq $True) -or ([String]::IsNullOrWhiteSpace($SettingsPath) -eq $True)} - { - [System.IO.FileInfo]$SettingsTemplate = "$($ContentDirectory.FullName)\Templates\SettingsTemplate.xml" - - [System.IO.FileInfo]$SettingsPath = "$($ApplicationDataRootDirectory.FullName)\Settings\$($ScriptPath.BaseName.Split('-')[1])Settings.xml" - - Switch ([System.IO.File]::Exists($SettingsPath.FullName)) - { - {($_ -eq $True)} - { - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The settings XML configuration file `"$($SettingsPath.FullName)`" already exists." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - } - - {($_ -eq $False)} - { - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to create settings XML configuration file `"$($SettingsPath.FullName)`" from the settings XML template file `"$($SettingsTemplate.FullName)`". Please Wait..." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - Switch ([System.IO.Directory]::Exists($SettingsPath.Directory.FullName)) - { - {($_ -eq $False)} - { - $Null = [System.IO.Directory]::CreateDirectory($SettingsPath.Directory.FullName) - } - } - - $Null = Copy-Item -Path ($SettingsTemplate.FullName) -Destination ($SettingsPath.FullName) -Force - } - } - } - - {([String]::IsNullOrEmpty($CatalogDirectory) -eq $True) -or ([String]::IsNullOrWhiteSpace($CatalogDirectory) -eq $True)} - { - [System.IO.DirectoryInfo]$CatalogDirectory = "$($ApplicationDataRootDirectory.FullName)\Catalogs" - } - - {([String]::IsNullOrEmpty($DownloadDirectory) -eq $True) -or ([String]::IsNullOrWhiteSpace($DownloadDirectory) -eq $True)} - { - [System.IO.DirectoryInfo]$DownloadDirectory = "$($StagingDirectory.FullName)\Downloads" - } - - {([String]::IsNullOrEmpty($DriverPackageDirectory) -eq $True) -or ([String]::IsNullOrWhiteSpace($DriverPackageDirectory) -eq $True)} - { - [System.IO.DirectoryInfo]$DriverPackageDirectory = "$($ApplicationDataRootDirectory.FullName)\Out-Of-Box-Driver-Packages" - } - + { {([String]::IsNullOrEmpty($LogDirectory) -eq $True) -or ([String]::IsNullOrWhiteSpace($LogDirectory) -eq $True)} { - [System.IO.DirectoryInfo]$LogDirectory = "$($ApplicationDataRootDirectory.FullName)\Logs" + [System.IO.DirectoryInfo]$LogDirectory = "$($Env:Windir)\Logs\Software\$($ScriptPath.BaseName)" } } @@ -572,6 +483,41 @@ Else $ProcessExecutionTable.Is64BitOperatingSystem = [System.Environment]::Is64BitOperatingSystem -As [Boolean] $ProcessExecutionTable.Is64BitProcess = [System.Environment]::Is64BitProcess -As [Boolean] $ProcessExecutionTable.CommandLine = [System.Environment]::CommandLine -As [String] + + [System.IO.FileInfo]$SettingsTemplate = "$($ContentDirectory.FullName)\Settings\Template.xml" + + [System.IO.FileInfo]$SettingsPath = "$($SettingsTemplate.Directory.FullName)\Settings.xml" + + Switch ([System.IO.File]::Exists($SettingsPath.FullName)) + { + {($_ -eq $True)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The settings XML configuration file `"$($SettingsPath.FullName)`" already exists." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + } + + {($_ -eq $False)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The settings XML configuration file `"$($SettingsPath.FullName)`" does not exist and will be created." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to create settings XML configuration file `"$($SettingsPath.FullName)`" from the settings XML template file `"$($SettingsTemplate.FullName)`". Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + Switch ([System.IO.Directory]::Exists($SettingsPath.Directory.FullName)) + { + {($_ -eq $False)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to create non-existent directory `"$($SettingsPath.Directory.FullName)`". Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $Null = [System.IO.Directory]::CreateDirectory($SettingsPath.Directory.FullName) + } + } + + $Null = Copy-Item -Path ($SettingsTemplate.FullName) -Destination ($SettingsPath.FullName) -Force + } + } $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Settings Path: $($SettingsPath.FullName)" Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose @@ -590,15 +536,246 @@ Else $Script:SettingsXMLObject.PreserveWhitespace = $True $Null = $Script:SettingsXMLObject.LoadXml($Script:SettingsXMLContent) - + $Script:SettingsTable.OperatingSytemList = $Script:SettingsXMLObject.SelectNodes('/Settings/OperatingSystemList//OperatingSystem') | Where-Object {($_.Enabled -eq $True)} $Script:SettingsTable.ManufacturerList = $Script:SettingsXMLObject.SelectNodes('/Settings/ManufacturerList//Manufacturer') + } $Null = $ReadXMLContent.InvokeReturnAsIs() + #Create variable(s) for script parameters stored within the XML + $XMLParameterObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]' + + $XMLParameterNodeList = $Script:SettingsXMLObject.SelectNodes('/Settings/ParameterList//Parameter') + + ForEach ($XMLParameterNode In $XMLParameterNodeList) + { + $XMLParameterObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $XMLParameterObjectProperties.Name = $XMLParameterNode.Name + $XMLParameterObjectProperties.Type = $XMLParameterNode.Type + $XMLParameterObjectProperties.OriginalValue = $XMLParameterNode.Value + $XMLParameterObjectProperties.ExpandedValue = $ExecutionContext.InvokeCommand.ExpandString([System.Environment]::ExpandEnvironmentVariables($XMLParameterObjectProperties.OriginalValue)) + + Switch ($XMLParameterObjectProperties.Type) + { + {($_ -iin @('Switch'))} + { + $XMLParameterObjectProperties.TypeCastedValue = New-Object -TypeName 'System.Management.Automation.SwitchParameter' -ArgumentList @($XMLParameterObjectProperties.ExpandedValue) + } + + {($_ -iin @('Boolean'))} + { + $XMLParameterObjectProperties.TypeCastedValue = [Boolean]::Parse($XMLParameterObjectProperties.ExpandedValue) + } + + Default + { + $XMLParameterObjectProperties.TypeCastedValue = $XMLParameterObjectProperties.ExpandedValue -As "$($XMLParameterObjectProperties.Type)" + } + } + + $SetVariableParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $SetVariableParameters.Name = $XMLParameterObjectProperties.Name + $SetVariableParameters.Value = $XMLParameterObjectProperties.TypeCastedValue + $SetVariableParameters.Force = $True + $SetVariableParameters.Scope = 'Script' + $SetVariableParameters.Verbose = $False + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to create the $($SetVariableParameters.Scope.ToLower()) scope powershell variable `"`$$($SetVariableParameters.Name)`" of type `"[$($XMLParameterObjectProperties.Type)]`" with a value of `"$($SetVariableParameters.Value)`". Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $Null = Set-Variable @SetVariableParameters + + $XMLParameterObject = New-Object -TypeName 'PSObject' -Property ($XMLParameterObjectProperties) + + $XMLParameterObjectList.Add($XMLParameterObject) + } + + [System.IO.DirectoryInfo]$LocalDriverPackageDirectory = "$($StagingDirectory.FullName)\Packages" + + [System.IO.DirectoryInfo]$CatalogDirectory = "$($ApplicationDataRootDirectory.FullName)\Catalogs" + $WindowsReleaseHistory = Get-WindowsReleaseHistory -Verbose + #Attempt to type cast the additional models that were provided within the additional XML node list parameter + $AdditionalXMLNodeList = New-Object -TypeName 'System.Collections.Generic.List[String]' + + Switch ($AdditionalXMLNodes.Count -gt 0) + { + {($_ -eq $True)} + { + ForEach ($AdditionalXMLNode In $AdditionalXMLNodes) + { + $AdditionalXMLNodeList.Add($AdditionalXMLNode) + } + } + } + + $AdditionalXMLNodeList.Add('') + $AdditionalXMLNodeList.Add('') + $AdditionalXMLNodeList.Add('') + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($AdditionalXMLNodeList.Count) additional XML model nodes were specified." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + Switch ($AdditionalXMLNodeList.Count -gt 0) + { + {($_ -eq $True)} + { + $ValidAdditionalXMLNodeList = New-Object -TypeName 'System.Collections.Generic.List[System.XML.XMLNode]' + + For ($AdditionalXMLNodeListIndex = 0; $AdditionalXMLNodeListIndex -lt $AdditionalXMLNodeList.Count; $AdditionalXMLNodeListIndex++) + { + $AdditionalXMLNodeListItem = $AdditionalXMLNodeList[$AdditionalXMLNodeListIndex] + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to validate additional XML node `"$($AdditionalXMLNodeListItem)`". Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $XMLNodeConverter = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $XMLNodeConverter.XMLTextReaderArguments = New-Object -TypeName 'System.Collections.Generic.List[Object]' + $XMLNodeConverter.XMLTextReaderArguments.Add((New-Object -TypeName 'System.IO.StringReader' -ArgumentList $AdditionalXMLNodeListItem)) + $XMLNodeConverter.XMLTextReader = New-Object -TypeName 'System.XML.XMLTextReader' -ArgumentList ($XMLNodeConverter.XMLTextReaderArguments.ToArray()) + $XMLNodeConverter.XMLDocument = New-Object -TypeName 'System.XML.XMLDocument' + $XMLNodeConverter.XMLNodeError = $Null + $XMLNodeConverter.XMLNode = Try {$XMLNodeConverter.XMLDocument.ReadNode($XMLNodeConverter.XMLTextReader) -As [System.XML.XMLNode]} Catch {$Null; $XMLNodeConverter.XMLNodeError = $_.Exception.Message} + $XMLNodeConverter.XMLNodeIsValid = $XMLNodeConverter.XMLNode -is [System.XML.XMLNode] + + Switch ($XMLNodeConverter.XMLNodeIsValid) + { + {($_ -eq $True)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The provided XML node is valid." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $ValidAdditionalXMLNodeList.Add($XMLNodeConverter.XMLNode) + } + + Default + { + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The provided XML node is invalid. [Error: $($XMLNodeConverter.XMLNodeError)]" + Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose + } + } + } + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($ValidAdditionalXMLNodeList.Count) of $($AdditionalXMLNodeList.Count) XML nodes were successfully type casted and added to the list of valid XML node objects." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + } + } + + + Try + { + ForEach ($Manufacturer In $SettingsTable.ManufacturerList) + { + Switch ($Manufacturer.Enabled) + { + {($_ -eq $True)} + { + $ManufacturerSettingsTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $ManufacturerSettingsTable.ModelList = ($Script:SettingsTable.ManufacturerList | Where-Object {($_.Name -ieq $Manufacturer.Name)}).ModelList.Model + + $AdditionalModelNodeList = $ValidAdditionalXMLNodeList | Where-Object {($_.SystemManufacturer -imatch $Manufacturer.EligibilityExpression)} + + $AdditionalModelListCount = ($AdditionalModelNodeList | Measure-Object).Count + + Switch ($AdditionalModelListCount -gt 0) + { + {($_ -eq $True)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($AdditionalModelListCount) additional model(s) whose system manufacturer matches `"$($Manufacturer.EligibilityExpression)`" need to be added to the model list for `"$($Manufacturer.Name)`"." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + [Int]$XMLModificationCount = 0 + + ForEach ($AdditionalModelNode In $AdditionalModelNodeList) + { + Switch ($ManufacturerSettingsTable.ModelList.ProductID -inotcontains $AdditionalModelNode.ProductID) + { + {($_ -eq $True)} + { + Try + { + $OneTabNode = $Script:SettingsXMLObject.CreateTextNode("`t") + $ThreeTabNode = $Script:SettingsXMLObject.CreateTextNode("`t`t`t") + $WhitespaceNode = $Script:SettingsXMLObject.CreateTextNode("`r`n") + + $ImportedAdditionalModelNode = $Script:SettingsXMLObject.ImportNode($AdditionalModelNode, $True) + + $ModelListNode = ($Script:SettingsTable.ManufacturerList | Where-Object {($_.Name -ieq $Manufacturer.Name)}).ModelList + + $Null = $ModelListNode.AppendChild($OneTabNode) + + $Null = $ModelListNode.AppendChild($ImportedAdditionalModelNode) + + $Null = $ModelListNode.AppendChild($WhitespaceNode) + + $Null = $ModelListNode.AppendChild($ThreeTabNode) + + $XMLModificationCount = $XMLModificationCount + 1 + } + Catch + { + $ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $ErrorMessageList.Add('Message', $_.Exception.Message) + $ErrorMessageList.Add('Category', $_.Exception.ErrorRecord.FullyQualifiedErrorID) + $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 + } + } + Finally + { + + } + } + + Default + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - XML node already exists! [Content: $($AdditionalModelNode.OuterXml)]" + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + } + } + } + } + } + } + } + } + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($XMLModificationCount) change(s) need to be committed into `"$($SettingsPath.FullName)`"." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + Switch ($XMLModificationCount -gt 0) + { + {($_ -eq $True)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to save `"$($SettingsPath.FullName)`". Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $Null = $Script:SettingsXMLObject.Save($SettingsPath.FullName) + + $Null = Start-Sleep -Seconds 3 + + $Null = $ReadXMLContent.InvokeReturnAsIs() + } + } + } + Catch + { + + } + Finally + { + + } + $DriverPackDownloadList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]' ForEach ($Manufacturer In $SettingsTable.ManufacturerList) @@ -615,7 +792,7 @@ Else $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to process the driver pack catalog for `"$($Manufacturer.Name)`". Please Wait..." Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose - $DownloadDriverPackCatalog = Invoke-FileDownload -URL ($Manufacturer.URLs.DriverPackCatalog) -Destination "$($CatalogDirectory.FullName)\$($Manufacturer.Name)" -Verbose + $DownloadDriverPackCatalog = Invoke-FileDownloadWithProgress -URL ($Manufacturer.URLs.DriverPackCatalog) -Destination "$($CatalogDirectory.FullName)\$($Manufacturer.Name)" -Verbose Switch ($DownloadDriverPackCatalog.DownloadPath.Extension -imatch '\.(cab)') { @@ -918,8 +1095,8 @@ Else { {($_ -eq $True)} { - $DateTimeFormatList = New-Object -TypeName 'System.Collections.Generic.List[String]' - $Null = $DateTimeFormatList.Add('yyyyMM') + $DateTimeFormatList = New-Object -TypeName 'System.Collections.Generic.List[String]' + $DateTimeFormatList.Add('yyyyMM') $DateTime = New-Object -TypeName 'DateTime' @@ -927,7 +1104,7 @@ Else $DateTimeTryParseExactProperties.Input = $CatalogSearchMetadataCaptureGroup.Value $DateTimeTryParseExactProperties.FormatList = $DateTimeFormatList.ToArray() $DateTimeTryParseExactProperties.Styles = New-Object -TypeName 'System.Collections.Generic.List[System.Globalization.DateTimeStyles]' - $DateTimeTryParseExactProperties.Styles.Add([System.Globalization.DateTimeStyles]::AdjustToUniversal) + $DateTimeTryParseExactProperties.Styles.Add([System.Globalization.DateTimeStyles]::AssumeUniversal) $DateTimeTryParseExactProperties.Styles.Add([System.Globalization.DateTimeStyles]::AllowWhiteSpaces) $DateTimeTryParseExactProperties.DateTime = $Null $DateTimeTryParseExactProperties.Successful = [DateTime]::TryParseExact($DateTimeTryParseExactProperties.Input, $DateTimeTryParseExactProperties.FormatList, $DateTimeTryParseExactProperties.Culture, $DateTimeTryParseExactProperties.Styles, [Ref]$DateTime) @@ -1157,7 +1334,7 @@ Else } } - Switch ($DisableDownload.IsPresent) + Switch ($DisableDownload) { {($_ -eq $True)} { @@ -1208,326 +1385,344 @@ Else $NewWindowsImageDetails.ImageFinalPath = $NewWindowsImageDetails.ImageStagingPath.FullName.Replace($LocalDriverPackageDirectory.FullName, $DriverPackageDirectory.FullName) -As [System.IO.FileInfo] $NewWindowsImageDetails.LogPath = "$($LogDirectory.FullName)\DISM\$($ManufacturerGroup.Name)\$($ProductGroupMember.$($ProductGroupProperty))\$($NewWindowsImageDetails.ImageStagingPath.BaseName).log" -As [System.IO.FileInfo] - Switch (([System.IO.File]::Exists($NewWindowsImageDetails.ImageFinalPath.FullName) -eq $False) -or ($Force.IsPresent -eq $True)) + Switch (([System.IO.File]::Exists($NewWindowsImageDetails.ImageFinalPath.FullName) -eq $False) -or ($Force -eq $True)) { {($_ -eq $True)} { - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to process the `"$($ProductGroupMember.OSName) $($ProductGroupMember.OSArchitecture)`" download list for product ID `"$($ProductGroup.Name)`" [Model: $($ProductGroupMember.$($ProductGroupAliasProperty))] manufactured by `"$($ManufacturerGroup.Name)`". Please Wait..." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - :ProductGroupMemberDownloadLoop ForEach ($ProductGroupMemberDownload In $ProductGroupMember.DownloadLinkList.GetEnumerator()) + Switch (([System.IO.File]::Exists($NewWindowsImageDetails.ImageStagingPath.FullName) -eq $False) -or ($Force -eq $True)) { - Switch (([String]::IsNullOrEmpty($ProductGroupMemberDownload.Value) -eq $False) -and ([String]::IsNullOrWhiteSpace($ProductGroupMemberDownload.Value) -eq $False)) + {($_ -eq $True)} { - {($_ -eq $True)} + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to process the `"$($ProductGroupMember.OSName) $($ProductGroupMember.OSArchitecture)`" download list for product ID `"$($ProductGroup.Name)`" [Model: $($ProductGroupMember.$($ProductGroupAliasProperty))] manufactured by `"$($ManufacturerGroup.Name)`". Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + :ProductGroupMemberDownloadLoop ForEach ($ProductGroupMemberDownload In $ProductGroupMember.DownloadLinkList.GetEnumerator()) { - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to process the URL for `"$($ProductGroupMemberDownload.Key)`". Please Wait..." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - Switch ($ProductGroupMemberDownload.Key) + Switch (([String]::IsNullOrEmpty($ProductGroupMemberDownload.Value) -eq $False) -and ([String]::IsNullOrWhiteSpace($ProductGroupMemberDownload.Value) -eq $False)) { - {($_ -iin @('DriverPack'))} + {($_ -eq $True)} { - $InvokeFileDownloadParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' - $InvokeFileDownloadParameters.URL = $ProductGroupMemberDownload.Value - $InvokeFileDownloadParameters.Destination = "$($DownloadDirectory.FullName)\$($ProductGroupMember.Manufacturer)\$($ProductGroupMember.$($ProductGroupProperty))" - $InvokeFileDownloadParameters.ContinueOnError = $False - $InvokeFileDownloadParameters.Verbose = $True - - $InvokeFileDownloadResult = Invoke-FileDownloadWithProgress @InvokeFileDownloadParameters - - $FileDownloadExtractionParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' - $FileDownloadExtractionParameters.ExtractionPath = "$($DownloadDirectory.FullName)\$($ProductGroupMember.Manufacturer)\$($ProductGroupMember.$($ProductGroupProperty))\$($ProductGroupMember.OSAlias)-$($ProductGroupMember.OSArchitecture)-$($ProductGroupMember.DriverPackReleaseID)" -As [System.IO.DirectoryInfo] - $FileDownloadExtractionParameters.ArgumentList = New-Object -TypeName 'System.Collections.Generic.List[String]' - $FileDownloadExtractionParameters.CopyDriverPackMetadata = $True - $FileDownloadExtractionParameters.CreateWindowsImageDriverPack = $True - - Switch ($ProductGroupMember.Manufacturer) - { - {($_ -iin @('Lenovo'))} - { - $FileDownloadExtractionParameters.FilePath = $InvokeFileDownloadResult.DownloadPath.FullName -As [System.IO.FileInfo] - - $FileDownloadExtractionParameters.ArgumentList.Add("/VERYSILENT") - $FileDownloadExtractionParameters.ArgumentList.Add("/DIR=`"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`"") - $FileDownloadExtractionParameters.ArgumentList.Add("/EXTRACT=`"YES`"") - } - - Default - { - $FileDownloadExtractionParameters.FilePath = $7ZipPath.FullName -As [System.IO.FileInfo] - - $FileDownloadExtractionParameters.ArgumentList.Add("x") - $FileDownloadExtractionParameters.ArgumentList.Add("`"$($InvokeFileDownloadResult.DownloadPath.FullName)`"") - $FileDownloadExtractionParameters.ArgumentList.Add("-o`"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`"") - $FileDownloadExtractionParameters.ArgumentList.Add("*") - $FileDownloadExtractionParameters.ArgumentList.Add("-r") - } - } - - Switch ([System.IO.Directory]::Exists($FileDownloadExtractionParameters.ExtractionPath.FullName)) - { - {($_ -eq $True)} - { - $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to remove existing directory `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`" prior to extraction. Please Wait..." - Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose - - [String]$DeletionPath = $FileDownloadExtractionParameters.ExtractionPath.FullName - - $Null = [Alphaleonis.Win32.Filesystem.Directory]::Delete($DeletionPath, $True, $True) - } - - Default - { - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to create non-existent directory `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`" prior to extraction. Please Wait..." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - $Null = [System.IO.Directory]::CreateDirectory($FileDownloadExtractionParameters.ExtractionPath.FullName) - } - } - - $StartProcessWithOutputParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' - $StartProcessWithOutputParameters.FilePath = $FileDownloadExtractionParameters.FilePath.FullName - $StartProcessWithOutputParameters.ArgumentList = $FileDownloadExtractionParameters.ArgumentList - $StartProcessWithOutputParameters.AcceptableExitCodeList = @(0, 3010) - $StartProcessWithOutputParameters.CreateNoWindow = $True - $StartProcessWithOutputParameters.LogOutput = $False - $StartProcessWithOutputParameters.Verbose = $True - - $FileDownloadExtractionResult = Start-ProcessWithOutput @StartProcessWithOutputParameters - - Switch ($FileDownloadExtractionParameters.ExtractionPath.GetDirectories().Count -gt 2) - { - {($_ -eq $True)} - { - $WindowsImageRootFolder = $FileDownloadExtractionParameters.ExtractionPath - } - - Default - { - $WindowsImageRootFolderList = Get-ChildItem -Path ($FileDownloadExtractionParameters.ExtractionPath.FullName) -Recurse | Where-Object {($_ -is [System.IO.DirectoryInfo]) -and ($_.GetDirectories().Count -gt 2)} - - Switch ($Null -ine $WindowsImageRootFolderList) - { - {($_ -eq $True)} - { - $WindowsImageRootFolder = $WindowsImageRootFolderList | Sort-Object -Property @{Expression = {($_.FullName.Length)}} | Select-Object -First 1 - } - - {($_ -eq $False)} - { - $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The windows image root folder could not located within folder `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`"." - Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose - - $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Cleaning up and moving to the next driver pack. Please Wait..." - Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose - - $FileDownloadExtractionParameters.CopyDriverPackMetadata = $False - - $FileDownloadExtractionParameters.CreateWindowsImageDriverPack = $False - - $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to remove driver pack extraction directory `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`". Please Wait..." - Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose - - #Cleanup the extracted driver package content (If necessary) - If ([System.IO.Directory]::Exists($FileDownloadExtractionParameters.ExtractionPath.FullName) -eq $True) - { - $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to remove driver pack extraction directory `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`". Please Wait..." - Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose - - [String]$DeletionPath = $FileDownloadExtractionParameters.ExtractionPath.FullName - - $Null = [Alphaleonis.Win32.Filesystem.Directory]::Delete($DeletionPath, $True, $True) - } - - Break ProductGroupMemberLoop - } - } - } - } - } - - {($_ -iin @('DriverPackMetaData'))} - { - Switch ($FileDownloadExtractionParameters.CopyDriverPackMetadata) + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to process the URL for `"$($ProductGroupMemberDownload.Key)`". Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + Switch ($ProductGroupMemberDownload.Key) { - {($_ -eq $True)} + {($_ -iin @('DriverPack'))} { - $DriverPackMetaDataFileList = New-Object -TypeName 'System.Collections.Generic.List[System.IO.FileInfo]' + $InvokeFileDownloadParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $InvokeFileDownloadParameters.URL = $ProductGroupMemberDownload.Value + $InvokeFileDownloadParameters.Destination = "$($DownloadDirectory.FullName)\$($ProductGroupMember.Manufacturer)\$($ProductGroupMember.$($ProductGroupProperty))" + $InvokeFileDownloadParameters.ContinueOnError = $False + $InvokeFileDownloadParameters.Verbose = $True + + $InvokeFileDownloadResult = Invoke-FileDownloadWithProgress @InvokeFileDownloadParameters + + $FileDownloadExtractionParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $FileDownloadExtractionParameters.ExtractionPath = "$($DownloadDirectory.FullName)\$($ProductGroupMember.Manufacturer)\$($ProductGroupMember.$($ProductGroupProperty))\$($ProductGroupMember.OSAlias)-$($ProductGroupMember.OSArchitecture)-$($ProductGroupMember.DriverPackReleaseID)" -As [System.IO.DirectoryInfo] + $FileDownloadExtractionParameters.ArgumentList = New-Object -TypeName 'System.Collections.Generic.List[String]' + $FileDownloadExtractionParameters.CopyDriverPackMetadata = $True + $FileDownloadExtractionParameters.CreateWindowsImageDriverPack = $True + + Switch ($ProductGroupMember.Manufacturer) + { + {($_ -iin @('Lenovo'))} + { + $FileDownloadExtractionParameters.FilePath = $InvokeFileDownloadResult.DownloadPath.FullName -As [System.IO.FileInfo] + + $FileDownloadExtractionParameters.ArgumentList.Add("/VERYSILENT") + $FileDownloadExtractionParameters.ArgumentList.Add("/DIR=`"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`"") + $FileDownloadExtractionParameters.ArgumentList.Add("/EXTRACT=`"YES`"") + } + + Default + { + $FileDownloadExtractionParameters.FilePath = $7ZipPath.FullName -As [System.IO.FileInfo] + + $FileDownloadExtractionParameters.ArgumentList.Add("x") + $FileDownloadExtractionParameters.ArgumentList.Add("`"$($InvokeFileDownloadResult.DownloadPath.FullName)`"") + $FileDownloadExtractionParameters.ArgumentList.Add("-o`"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`"") + $FileDownloadExtractionParameters.ArgumentList.Add("*") + $FileDownloadExtractionParameters.ArgumentList.Add("-r") + } + } + + Switch ([System.IO.Directory]::Exists($FileDownloadExtractionParameters.ExtractionPath.FullName)) + { + {($_ -eq $True)} + { + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to remove existing directory `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`" prior to extraction. Please Wait..." + Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose + + [String]$DeletionPath = $FileDownloadExtractionParameters.ExtractionPath.FullName + + $Null = [Alphaleonis.Win32.Filesystem.Directory]::Delete($DeletionPath, $True, $True) + } + } + + Switch ($ProductGroupMember.Manufacturer) + { + {($_ -inotin @('Lenovo'))} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to create non-existent directory `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`" prior to extraction. Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $Null = [System.IO.Directory]::CreateDirectory($FileDownloadExtractionParameters.ExtractionPath.FullName) + } + } + + $StartProcessWithOutputParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $StartProcessWithOutputParameters.FilePath = $FileDownloadExtractionParameters.FilePath.FullName + $StartProcessWithOutputParameters.ArgumentList = $FileDownloadExtractionParameters.ArgumentList + $StartProcessWithOutputParameters.AcceptableExitCodeList = @(0, 3010) + $StartProcessWithOutputParameters.CreateNoWindow = $True + $StartProcessWithOutputParameters.LogOutput = $False + $StartProcessWithOutputParameters.Verbose = $True + + $FileDownloadExtractionResult = Start-ProcessWithOutput @StartProcessWithOutputParameters + + Switch ($FileDownloadExtractionParameters.ExtractionPath.GetDirectories().Count -gt 2) + { + {($_ -eq $True)} + { + $WindowsImageRootFolder = $FileDownloadExtractionParameters.ExtractionPath + } + + Default + { + $WindowsImageRootFolderList = Get-ChildItem -Path ($FileDownloadExtractionParameters.ExtractionPath.FullName) -Recurse | Where-Object {($_ -is [System.IO.DirectoryInfo]) -and ($_.GetDirectories().Count -gt 2)} + + Switch ($Null -ine $WindowsImageRootFolderList) + { + {($_ -eq $True)} + { + $WindowsImageRootFolder = $WindowsImageRootFolderList | Sort-Object -Property @{Expression = {($_.FullName.Length)}} | Select-Object -First 1 + } + + {($_ -eq $False)} + { + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The windows image root folder could not located within folder `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`"." + Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose + + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Cleaning up and moving to the next driver pack. Please Wait..." + Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose + + $FileDownloadExtractionParameters.CopyDriverPackMetadata = $False + + $FileDownloadExtractionParameters.CreateWindowsImageDriverPack = $False + + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to remove driver pack extraction directory `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`". Please Wait..." + Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose + + #Cleanup the extracted driver package content (If necessary) + If ([System.IO.Directory]::Exists($FileDownloadExtractionParameters.ExtractionPath.FullName) -eq $True) + { + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to remove driver pack extraction directory `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`". Please Wait..." + Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose + + [String]$DeletionPath = $FileDownloadExtractionParameters.ExtractionPath.FullName - $DriverPackMetaDataExtensionList = New-Object -TypeName 'System.Collections.Generic.List[String]' - $DriverPackMetaDataExtensionList.Add('.xml') - $DriverPackMetaDataExtensionList.Add('.html') - $DriverPackMetaDataExtensionList.Add('.cva') - $DriverPackMetaDataExtensionList.Add('.json') - $DriverPackMetaDataExtensionList.Add('.txt') - - $DriverPackMetaDataFiles = Get-ChildItem -Path "$($FileDownloadExtractionParameters.ExtractionPath.FullName)\" -Depth 1 -Force -ErrorAction SilentlyContinue | Where-Object {($_ -is [System.IO.FileInfo]) -and ($_.Extension -iin $DriverPackMetaDataExtensionList.ToArray())} - - $DriverPackMetaDataFileCount = ($DriverPackMetaDataFiles | Measure-Object).Count - - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($DriverPackMetaDataFileCount) metadata file(s) matching `"$($DriverPackMetaDataExtensionList -Join ' | ')`" were found in directory `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`"." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - Switch ($DriverPackMetaDataFileCount -gt 0) - { - {($_ -eq $True)} - { - $DriverPackMetaDataFiles | ForEach-Object {$DriverPackMetaDataFileList.Add($_.FullName)} - } - } - - [System.IO.DirectoryInfo]$DriverPackMetaDataDirectory = "$($WindowsImageRootFolder.FullName)\Metadata" - - If ([System.IO.Directory]::Exists($DriverPackMetaDataDirectory.FullName) -eq $False) {$Null = [System.IO.Directory]::CreateDirectory($DriverPackMetaDataDirectory.FullName)} - - ForEach ($DriverPackMetaDataFile In $DriverPackMetaDataFileList) - { - [System.IO.FileInfo]$DriverPackMetaDataFileDestination = "$($DriverPackMetaDataDirectory.FullName)\$($DriverPackMetaDataFile.Name)" - - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to copy metadata file `"$($DriverPackMetaDataFile.FullName)`" to `"$($DriverPackMetaDataFileDestination.FullName)`". Please Wait..." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - $Null = [System.IO.File]::Copy($DriverPackMetaDataFile.FullName, $DriverPackMetaDataFileDestination.FullName, $True) - } - - $InvokeFileDownloadParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' - $InvokeFileDownloadParameters.URL = $ProductGroupMemberDownload.Value - $InvokeFileDownloadParameters.Destination = "$($DownloadDirectory.FullName)\$($ProductGroupMember.Manufacturer)\$($ProductGroupMember.$($ProductGroupProperty))" - $InvokeFileDownloadParameters.ContinueOnError = $False - $InvokeFileDownloadParameters.Verbose = $True - - $InvokeFileDownloadResult = Invoke-FileDownloadWithProgress @InvokeFileDownloadParameters - - $Null = [System.IO.File]::Copy($InvokeFileDownloadResult.DownloadPath.FullName, "$($DriverPackMetaDataFileDestination.Directory.FullName)\$($InvokeFileDownloadResult.DownloadPath.Name)", $True) + $Null = [Alphaleonis.Win32.Filesystem.Directory]::Delete($DeletionPath, $True, $True) + } + + Break ProductGroupMemberLoop + } + } + } + } + } + + {($_ -iin @('DriverPackMetaData'))} + { + Switch ($FileDownloadExtractionParameters.CopyDriverPackMetadata) + { + {($_ -eq $True)} + { + $DriverPackMetaDataFileList = New-Object -TypeName 'System.Collections.Generic.List[System.IO.FileInfo]' + + $DriverPackMetaDataExtensionList = New-Object -TypeName 'System.Collections.Generic.List[String]' + $DriverPackMetaDataExtensionList.Add('.xml') + $DriverPackMetaDataExtensionList.Add('.html') + $DriverPackMetaDataExtensionList.Add('.cva') + $DriverPackMetaDataExtensionList.Add('.json') + $DriverPackMetaDataExtensionList.Add('.txt') + + $DriverPackMetaDataFiles = Get-ChildItem -Path "$($FileDownloadExtractionParameters.ExtractionPath.FullName)\" -Depth 1 -Force -ErrorAction SilentlyContinue | Where-Object {($_ -is [System.IO.FileInfo]) -and ($_.Extension -iin $DriverPackMetaDataExtensionList.ToArray())} + + $DriverPackMetaDataFileCount = ($DriverPackMetaDataFiles | Measure-Object).Count + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($DriverPackMetaDataFileCount) metadata file(s) matching `"$($DriverPackMetaDataExtensionList -Join ' | ')`" were found in directory `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`"." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + Switch ($DriverPackMetaDataFileCount -gt 0) + { + {($_ -eq $True)} + { + $DriverPackMetaDataFiles | ForEach-Object {$DriverPackMetaDataFileList.Add($_.FullName)} + } + } + + [System.IO.DirectoryInfo]$DriverPackMetaDataDirectory = "$($WindowsImageRootFolder.FullName)\Metadata" + + If ([System.IO.Directory]::Exists($DriverPackMetaDataDirectory.FullName) -eq $False) {$Null = [System.IO.Directory]::CreateDirectory($DriverPackMetaDataDirectory.FullName)} + + ForEach ($DriverPackMetaDataFile In $DriverPackMetaDataFileList) + { + [System.IO.FileInfo]$DriverPackMetaDataFileDestination = "$($DriverPackMetaDataDirectory.FullName)\$($DriverPackMetaDataFile.Name)" + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to copy metadata file `"$($DriverPackMetaDataFile.FullName)`" to `"$($DriverPackMetaDataFileDestination.FullName)`". Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $Null = [System.IO.File]::Copy($DriverPackMetaDataFile.FullName, $DriverPackMetaDataFileDestination.FullName, $True) + } + + $InvokeFileDownloadParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $InvokeFileDownloadParameters.URL = $ProductGroupMemberDownload.Value + $InvokeFileDownloadParameters.Destination = "$($DownloadDirectory.FullName)\$($ProductGroupMember.Manufacturer)\$($ProductGroupMember.$($ProductGroupProperty))" + $InvokeFileDownloadParameters.ContinueOnError = $False + $InvokeFileDownloadParameters.Verbose = $True + + $InvokeFileDownloadResult = Invoke-FileDownloadWithProgress @InvokeFileDownloadParameters + + $Null = [System.IO.File]::Copy($InvokeFileDownloadResult.DownloadPath.FullName, "$($DriverPackMetaDataFileDestination.Directory.FullName)\$($InvokeFileDownloadResult.DownloadPath.Name)", $True) + } + } + } + + Default + { + $InvokeFileDownloadParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $InvokeFileDownloadParameters.URL = $ProductGroupMemberDownload.Value + $InvokeFileDownloadParameters.Destination = $FileDownloadExtractionParameters.ExtractionPath.FullName + $InvokeFileDownloadParameters.ContinueOnError = $False + $InvokeFileDownloadParameters.Verbose = $True + + $InvokeFileDownloadResult = Invoke-FileDownloadWithProgress @InvokeFileDownloadParameters } } } - + Default { - $InvokeFileDownloadParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' - $InvokeFileDownloadParameters.URL = $ProductGroupMemberDownload.Value - $InvokeFileDownloadParameters.Destination = $FileDownloadExtractionParameters.ExtractionPath.FullName - $InvokeFileDownloadParameters.ContinueOnError = $False - $InvokeFileDownloadParameters.Verbose = $True - - $InvokeFileDownloadResult = Invoke-FileDownloadWithProgress @InvokeFileDownloadParameters + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The `"$($ProductGroupMemberDownload.Key)`" URL will not be processed because the value does not contain any data. Please Wait..." + Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose } } } + + #Create a windows image from the driver content if one does not already exist + Switch ([System.IO.File]::Exists($NewWindowsImageDetails.ImageStagingPath.FullName)) + { + {($_ -eq $True)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The windows image file `"$($NewWindowsImageDetails.ImageStagingPath.FullName)`" already exists and will not be created. Skipping." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + } + + {($_ -eq $False)} + { + Switch ($True) + { + {([System.IO.Directory]::Exists($NewWindowsImageDetails.ImageStagingPath.Directory.FullName) -eq $False)} + { + $Null = [System.IO.Directory]::CreateDirectory($NewWindowsImageDetails.ImageStagingPath.Directory.FullName) + } + + {([System.IO.Directory]::Exists($NewWindowsImageDetails.LogPath.Directory.FullName) -eq $False)} + { + $Null = [System.IO.Directory]::CreateDirectory($NewWindowsImageDetails.LogPath.Directory.FullName) + } + } + + $NewWindowsImageParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $NewWindowsImageParameters.CapturePath = $WindowsImageRootFolder.FullName + $NewWindowsImageParameters.ImagePath = $NewWindowsImageDetails.ImageStagingPath.FullName + $NewWindowsImageParameters.Name = $ProductGroupMember.FileBaseName + $NewWindowsImageParameters.Description = $ProductGroupMember | Select-Object -Property @('*') -ExcludeProperty @('Enabled') | ConvertTo-JSON -Depth 10 -Compress:$True + $NewWindowsImageParameters.CompressionType = 'Max' + $NewWindowsImageParameters.Verify = $False + $NewWindowsImageParameters.LogPath = $NewWindowsImageDetails.LogPath.FullName + $NewWindowsImageParameters.LogLevel = 'WarningsInfo' + $NewWindowsImageParameters.Verbose = $False + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to compress the extracted content for the `"$($ProductGroupMember.OSName) $($ProductGroupMember.OSArchitecture)`" driver pack `"$($ProductGroupMember.DriverPackReleaseID)`" for product ID `"$($ProductGroupMember.BaseboardProduct)`" [Model: $($ProductGroupMember.$($ProductGroupAliasProperty))] manufactured by `"$($ManufacturerGroup.Name)`" into the windows image format. Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Windows Image Capture Path: $($NewWindowsImageParameters.CapturePath)" + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Windows Image Export Path: $($NewWindowsImageParameters.ImagePath)" + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Windows Image Log Path: $($NewWindowsImageParameters.LogPath)" + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $CommandExecutionTimespan = Measure-Command -Expression {$Null = New-WindowsImage @NewWindowsImageParameters} + + If ($? -eq $True) + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Extracted content compression completed in $($CommandExecutionTimespan.Hours.ToString()) hour(s), $($CommandExecutionTimespan.Minutes.ToString()) minute(s), $($CommandExecutionTimespan.Seconds.ToString()) second(s), and $($CommandExecutionTimespan.Milliseconds.ToString()) millisecond(s)." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $NewWindowsImageDetails.HashDetails = Get-FileHash -Path ($NewWindowsImageParameters.ImagePath) -Algorithm ($HashAlgorithm) + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Windows Image Hash: $($NewWindowsImageDetails.HashDetails.Hash) [Algorithm: $($NewWindowsImageDetails.HashDetails.Algorithm)]" + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $ExtractedContentSize = Get-ChildItem -Path "$($NewWindowsImageParameters.CapturePath)\*" -Recurse | Where-Object {($_ -is [System.IO.FileInfo])} | Measure-Object -Property @('Length') -Sum | Select-Object -ExpandProperty 'Sum' + $ExtractedContentSizeDetails = Convert-FileSize -Size ($ExtractedContentSize) -DecimalPlaces 2 + + $WindowsImageDetails = Get-Item -Path ($NewWindowsImageParameters.ImagePath) -Force + $WindowsImageDetailsSizeDetails = Convert-FileSize -Size ($WindowsImageDetails.Length) -DecimalPlaces 2 + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The extracted content was reduced from its original size of $($ExtractedContentSizeDetails.CalculatedSizeStr) to its compressed size of $($WindowsImageDetailsSizeDetails.CalculatedSizeStr)." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + #Export the Windows image metadata + $WindowsImageJSONTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $WindowsImageJSONTable.Cryptography = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $WindowsImageJSONTable.Cryptography.Hash = $NewWindowsImageDetails.HashDetails.Hash + $WindowsImageJSONTable.Cryptography.Algorithm = $NewWindowsImageDetails.HashDetails.Algorithm + $WindowsImageJSONTable.Content = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $WindowsImageJSONTable.Content.OriginalSize = $ExtractedContentSize + $WindowsImageJSONTable.Content.CompressedSize = $WindowsImageDetails.Length + $WindowsImageJSONTable.Metadata = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $WindowsImageJSONTable.Metadata = $ProductGroupMember | Select-Object -Property @('*') -ExcludeProperty @('Enabled', 'BaseboardProduct', 'SystemFamily', 'SystemManufacturer', 'SystemProductName', 'SystemSKU', 'SystemVersion', 'DirectoryPath', 'FileBaseName', 'FileName', 'MetadataFileName') - Default - { - $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The `"$($ProductGroupMemberDownload.Key)`" URL will not be processed because the value does not contain any data. Please Wait..." - Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose - } + $WindowsImageJSONContents = $WindowsImageJSONTable | ConvertTo-JSON -Depth 10 -Compress:$False + + [System.IO.FileInfo]$WindowsImageJSONExportPath = "$($NewWindowsImageDetails.ImageStagingPath.Directory.FullName)\$($NewWindowsImageDetails.ImageStagingPath.BaseName).json" + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to export the driver package metadata to `"$($WindowsImageJSONExportPath.FullName)`". Please Wait..." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + If ([System.IO.Directory]::Exists($WindowsImageExportPath.Directory.FullName) -eq $False) {$Null = [System.IO.Directory]::CreateDirectory($WindowsImageJSONExportPath.Directory.FullName)} + + $Null = [System.IO.File]::WriteAllText($WindowsImageJSONExportPath.FullName, $WindowsImageJSONContents, [System.Text.Encoding]::Default) + } + } + } + + #Cleanup the extracted driver package content (If necessary) + If ([System.IO.Directory]::Exists($FileDownloadExtractionParameters.ExtractionPath.FullName) -eq $True) + { + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to remove driver pack extraction directory `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`". Please Wait..." + Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose + + [String]$DeletionPath = $FileDownloadExtractionParameters.ExtractionPath.FullName + + $Null = [Alphaleonis.Win32.Filesystem.Directory]::Delete($DeletionPath, $True, $True) + } } - } - - #Create a windows image from the driver content if one does not already exist - Switch ([System.IO.File]::Exists($NewWindowsImageDetails.ImageStagingPath.FullName)) - { - {($_ -eq $True)} - { - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The windows image file `"$($NewWindowsImageDetails.ImageStagingPath.FullName)`" already exists and will not be created. Skipping." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - } - - {($_ -eq $False)} - { - Switch ($True) - { - {([System.IO.Directory]::Exists($NewWindowsImageDetails.ImageStagingPath.Directory.FullName) -eq $False)} - { - $Null = [System.IO.Directory]::CreateDirectory($NewWindowsImageDetails.ImageStagingPath.Directory.FullName) - } - - {([System.IO.Directory]::Exists($NewWindowsImageDetails.LogPath.Directory.FullName) -eq $False)} - { - $Null = [System.IO.Directory]::CreateDirectory($NewWindowsImageDetails.LogPath.Directory.FullName) - } - } - - $NewWindowsImageParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' - $NewWindowsImageParameters.CapturePath = $WindowsImageRootFolder.FullName - $NewWindowsImageParameters.ImagePath = $NewWindowsImageDetails.ImageStagingPath.FullName - $NewWindowsImageParameters.Name = $ProductGroupMember.FileBaseName - $NewWindowsImageParameters.Description = $ProductGroupMember | Select-Object -Property @('*') -ExcludeProperty @('Enabled') | ConvertTo-JSON -Depth 10 -Compress:$True - $NewWindowsImageParameters.CompressionType = 'Max' - $NewWindowsImageParameters.Verify = $False - $NewWindowsImageParameters.LogPath = $NewWindowsImageDetails.LogPath.FullName - $NewWindowsImageParameters.LogLevel = 'WarningsInfo' - $NewWindowsImageParameters.Verbose = $False - - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to compress the extracted content for the `"$($ProductGroupMember.OSName) $($ProductGroupMember.OSArchitecture)`" driver pack `"$($ProductGroupMember.DriverPackReleaseID)`" for product ID `"$($ProductGroupMember.BaseboardProduct)`" [Model: $($ProductGroupMember.$($ProductGroupAliasProperty))] manufactured by `"$($ManufacturerGroup.Name)`" into the windows image format. Please Wait..." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Windows Image Capture Path: $($NewWindowsImageParameters.CapturePath)" - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Windows Image Export Path: $($NewWindowsImageParameters.ImagePath)" - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Windows Image Log Path: $($NewWindowsImageParameters.LogPath)" - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - $CommandExecutionTimespan = Measure-Command -Expression {$Null = New-WindowsImage @NewWindowsImageParameters} - - If ($? -eq $True) - { - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Extracted content compression completed in $($CommandExecutionTimespan.Hours.ToString()) hour(s), $($CommandExecutionTimespan.Minutes.ToString()) minute(s), $($CommandExecutionTimespan.Seconds.ToString()) second(s), and $($CommandExecutionTimespan.Milliseconds.ToString()) millisecond(s)." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - $NewWindowsImageDetails.HashDetails = Get-FileHash -Path ($NewWindowsImageParameters.ImagePath) -Algorithm ($HashAlgorithm) - - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Windows Image Hash: $($NewWindowsImageDetails.HashDetails.Hash) [Algorithm: $($NewWindowsImageDetails.HashDetails.Algorithm)]" - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - $ExtractedContentSize = Get-ChildItem -Path "$($NewWindowsImageParameters.CapturePath)\*" -Recurse | Where-Object {($_ -is [System.IO.FileInfo])} | Measure-Object -Property @('Length') -Sum | Select-Object -ExpandProperty 'Sum' - $ExtractedContentSizeDetails = Convert-FileSize -Size ($ExtractedContentSize) -DecimalPlaces 2 - - $WindowsImageDetails = Get-Item -Path ($NewWindowsImageParameters.ImagePath) -Force - $WindowsImageDetailsSizeDetails = Convert-FileSize -Size ($WindowsImageDetails.Length) -DecimalPlaces 2 - - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The extracted content was reduced from its original size of $($ExtractedContentSizeDetails.CalculatedSizeStr) to its compressed size of $($WindowsImageDetailsSizeDetails.CalculatedSizeStr)." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - #Export the Windows image metadata - $WindowsImageJSONTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' - $WindowsImageJSONTable.Cryptography = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' - $WindowsImageJSONTable.Cryptography.Hash = $NewWindowsImageDetails.HashDetails.Hash - $WindowsImageJSONTable.Cryptography.Algorithm = $NewWindowsImageDetails.HashDetails.Algorithm - $WindowsImageJSONTable.Content = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' - $WindowsImageJSONTable.Content.OriginalSize = $ExtractedContentSize - $WindowsImageJSONTable.Content.CompressedSize = $WindowsImageDetails.Length - $WindowsImageJSONTable.Metadata = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' - $WindowsImageJSONTable.Metadata = $ProductGroupMember | Select-Object -Property @('*') -ExcludeProperty @('Enabled', 'BaseboardProduct', 'SystemFamily', 'SystemManufacturer', 'SystemProductName', 'SystemSKU', 'SystemVersion', 'DirectoryPath', 'FileBaseName', 'FileName', 'MetadataFileName') - $WindowsImageJSONContents = $WindowsImageJSONTable | ConvertTo-JSON -Depth 10 -Compress:$False - - [System.IO.FileInfo]$WindowsImageJSONExportPath = "$($NewWindowsImageDetails.ImageStagingPath.Directory.FullName)\$($NewWindowsImageDetails.ImageStagingPath.BaseName).json" - - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to export the driver package metadata to `"$($WindowsImageJSONExportPath.FullName)`". Please Wait..." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - If ([System.IO.Directory]::Exists($WindowsImageExportPath.Directory.FullName) -eq $False) {$Null = [System.IO.Directory]::CreateDirectory($WindowsImageJSONExportPath.Directory.FullName)} - - $Null = [System.IO.File]::WriteAllText($WindowsImageJSONExportPath.FullName, $WindowsImageJSONContents, [System.Text.Encoding]::Default) - } - } - } - - #Cleanup the extracted driver package content (If necessary) - If ([System.IO.Directory]::Exists($FileDownloadExtractionParameters.ExtractionPath.FullName) -eq $True) - { - $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to remove driver pack extraction directory `"$($FileDownloadExtractionParameters.ExtractionPath.FullName)`". Please Wait..." - Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose - - [String]$DeletionPath = $FileDownloadExtractionParameters.ExtractionPath.FullName - - $Null = [Alphaleonis.Win32.Filesystem.Directory]::Delete($DeletionPath, $True, $True) - } + Default + { + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A driver pack staging windows image already exists for `"$($ProductGroupMember.OSName) $($ProductGroupMember.OSArchitecture)`" for product ID `"$($ProductGroup.Name)`" [Model: $($ProductGroupMember.$($ProductGroupAliasProperty))] manufactured by `"$($ManufacturerGroup.Name)`". Skipping..." + Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose + + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Windows Image Staging Path: $($NewWindowsImageDetails.ImageStagingPath.FullName)" + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + } + } } Default @@ -1638,7 +1833,7 @@ Else $StartProcessParameters.ArgumentList.Add("/TEE") $StartProcessParameters.ArgumentList.Add("/XX") $StartProcessParameters.ArgumentList.Add("/MT:16") - If ($EnableRobocopyIPG.IsPresent) {$StartProcessParameters.ArgumentList.Add("/IPG:125")} + If ($EnableRobocopyIPG) {$StartProcessParameters.ArgumentList.Add("/IPG:125")} $StartProcessParameters.ArgumentList.Add("/LOG:`"$($CopyDriverPackagesLogPath.FullName)`"") $StartProcessParameters.PassThru = $True $StartProcessParameters.Wait = $True @@ -1655,7 +1850,7 @@ Else Default { - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Session 0 was not detected [User: $($ProcessExecutionTable.ProcessNTAccount)]. The command window will be show." + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Session 0 was not detected [User: $($ProcessExecutionTable.ProcessNTAccount)]. The command window will be shown." Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose $StartProcessParameters.WindowStyle = [System.Diagnostics.Processwindowstyle]::Normal diff --git a/Invoke-DriverPackageCreator.vbs b/Invoke-DriverPackageCreator.vbs deleted file mode 100644 index 2190820..0000000 --- a/Invoke-DriverPackageCreator.vbs +++ /dev/null @@ -1,145 +0,0 @@ -'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/Invoke-DriverPackageDownload.ps1 b/Invoke-DriverPackageDownload.ps1 index 1f53681..e2bacf9 100644 --- a/Invoke-DriverPackageDownload.ps1 +++ b/Invoke-DriverPackageDownload.ps1 @@ -46,14 +46,14 @@ ( [Parameter(Mandatory=$False)] [ValidateNotNullOrEmpty()] - [ValidateScript({[System.IO.Directory]::Exists($_) -eq $True})] + [ValidateScript({Test-Path -Path $_})] [Alias('DPRD')] [System.IO.DirectoryInfo]$DriverPackageRootDirectory, [Parameter(Mandatory=$False)] [ValidateNotNullOrEmpty()] [ValidatePattern('^.+\.(xml)$')] - [ValidateScript({[System.IO.File]::Exists($_) -eq $True})] + [ValidateScript({Test-Path -Path $_})] [Alias('DPMDP')] [System.IO.FileInfo]$DriverPackageMetadataPath, @@ -317,9 +317,7 @@ Else {($_ -eq $False)} { - [System.IO.DirectoryInfo]$ApplicationDataRootDirectory = "$($Env:ProgramData)\Invoke-DriverPackageCreator" - - [System.IO.DirectoryInfo]$LogDirectory = "$($ApplicationDataRootDirectory.FullName)\Logs" + [System.IO.DirectoryInfo]$LogDirectory = "$($Env:Windir)\Logs\Software\$($ScriptPath.BaseName)" } } } @@ -419,7 +417,7 @@ Else Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose } - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Powershell Version: $($PSVersionTable.PSVersion.ToString())" + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Powershell Version: $($PSVersionTable.PSVersion)" Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose $ExecutionPolicyList = Get-ExecutionPolicy -List @@ -428,7 +426,7 @@ Else { $ExecutionPolicy = $ExecutionPolicyList[$ExecutionPolicyListIndex] - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The powershell execution policy is currently set to `"$($ExecutionPolicy.ExecutionPolicy.ToString())`" for the `"$($ExecutionPolicy.Scope.ToString())`" scope." + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The powershell execution policy is currently set to `"$($ExecutionPolicy.ExecutionPolicy)`" for the `"$($ExecutionPolicy.Scope)`" scope." Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose } @@ -487,7 +485,7 @@ Else $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)]." + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to cleanup log file `"$($Log.FullName)`". Please Wait... [Last Modified: $($Log.LastWriteTime.ToString($DateTimeMessageFormat))] [Age: $($LogAge.Days) day(s); $($LogAge.Hours) hours(s); $($LogAge.Minutes) minute(s); $($LogAge.Seconds) second(s)]." Write-Verbose -Message ($LoggingDetails.WarningMessage) -Verbose $Null = [System.IO.File]::Delete($Log.FullName) @@ -520,7 +518,7 @@ Else If ($Null -ine $LatestModuleVersion) { - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to import dependency powershell module `"$($LatestModuleVersion.Name)`" [Version: $($LatestModuleVersion.Version.ToString())]. Please Wait..." + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to import dependency powershell module `"$($LatestModuleVersion.Name)`" [Version: $($LatestModuleVersion.Version)]. Please Wait..." Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose Try {$Null = Import-Module -Name "$($LatestModuleVersion.Path)" -Global -DisableNameChecking -Force -Verbose:$False} Catch {} @@ -690,28 +688,77 @@ Else } } } - - Default - { - Switch ($True) - { - {([String]::IsNullOrEmpty($DriverPackageRootDirectory) -eq $True) -or ([String]::IsNullOrWhiteSpace($DriverPackageRootDirectory) -eq $True)} - { - [System.IO.DirectoryInfo]$DriverPackageRootDirectory = "C:\ProgramData\Invoke-DriverPackageCreator\DriverPackages" - } - - {([String]::IsNullOrEmpty($DriverPackageMetadataPath) -eq $True) -or ([String]::IsNullOrWhiteSpace($DriverPackageMetadataPath) -eq $True)} - { - [System.IO.FileInfo]$DriverPackageMetadataPath = "$($DriverPackageRootDirectory.FullName)\Metadata\DriverPackageList.xml" - } - } - } } #Determine which driver package(s) are applicable to the deployed operating system and product ID $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A task sequence is currently running." Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + #Get the deployed operating system details + $InvokeRegistryHiveActionParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + + $FixedVolumeList = [System.IO.DriveInfo]::GetDrives() | Where-Object {($_.DriveType -iin @('Fixed')) -and ($_.IsReady -eq $True) -and ($_.Name.TrimEnd('\') -inotin @($Env:SystemDrive)) -and (([String]::IsNullOrEmpty($_.Name) -eq $False) -or ([String]::IsNullOrWhiteSpace($_.Name) -eq $False))} | Sort-Object -Property @('TotalSize') + + :FixedVolumeLoop ForEach ($FixedVolume In $FixedVolumeList) + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to check fixed volume `"$($FixedVolume.Name.TrimEnd('\'))`" for a valid installation of Windows." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + [System.IO.DirectoryInfo]$WindowsDirectory = "$($FixedVolume.Name.TrimEnd('\'))\Windows" + + Switch ([System.IO.Directory]::Exists($WindowsDirectory.FullName)) + { + {($_ -eq $True)} + { + $WindowsDirectoryItemList = Get-ChildItem -Path ($WindowsDirectory.FullName) -ErrorAction SilentlyContinue + + $WindowsDirectoryItemListCount = ($WindowsDirectoryItemList | Measure-Object).Count + + Switch (($WindowsDirectoryItemListCount -ge 2) -and ($WindowsDirectoryItemList | Where-Object {($_.Name -ieq 'explorer.exe')})) + { + {($_ -eq $True)} + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Fixed volume `"$($FixedVolume.Name.TrimEnd('\'))`" contains a valid installation of Windows." + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + + $WindowsImageDriveInfo = New-Object -TypeName 'System.IO.DriveInfo' -ArgumentList "$($FixedVolume.Name.TrimEnd('\'))" + + $InvokeRegistryHiveActionParameters.HivePath = "$($WindowsImageDriveInfo.Name.TrimEnd('\').Toupper())\Windows\System32\Config\SOFTWARE" + + Break FixedVolumeLoop + } + } + } + } + } + + [System.IO.DirectoryInfo]$DriverPackageDownloadDirectory = "$($WindowsImageDriveInfo.Name.TrimEnd('\').Toupper())\Downloads" + + $InvokeRegistryHiveActionParameters.KeyPath = New-Object -TypeName 'System.Collections.Generic.List[String]' + $InvokeRegistryHiveActionParameters.KeyPath.Add('Root\Microsoft\Windows NT\CurrentVersion') + $InvokeRegistryHiveActionParameters.ValueNameExpression = New-Object -TypeName 'System.Collections.Generic.List[Regex]' + $InvokeRegistryHiveActionParameters.ValueNameExpression.Add('.*') + $InvokeRegistryHiveActionParameters.ContinueOnError = $False + $InvokeRegistryHiveActionParameters.Verbose = $True + + $InvokeRegistryHiveActionResult = Invoke-RegistryHiveAction @InvokeRegistryHiveActionParameters + + $WindowsImageDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $WindowsImageDetails.MajorVersionNumber = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'CurrentMajorVersionNumber')}).Value + $WindowsImageDetails.MinorVersionNumber = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'CurrentMinorVersionNumber')}).Value + $WindowsImageDetails.BuildNumber = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'CurrentBuildNumber')}).Value + $WindowsImageDetails.RevisionNumber = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'UBR')}).Value + $WindowsImageDetails.Version = New-Object -TypeName 'System.Version' -ArgumentList @($WindowsImageDetails.MajorVersionNumber, $WindowsImageDetails.MinorVersionNumber, $WindowsImageDetails.BuildNumber, $WindowsImageDetails.RevisionNumber) + $WindowsImageDetails.ReleaseNumber = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'ReleaseID')}).Value + $WindowsImageDetails.ReleaseID = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'DisplayVersion')}).Value + $WindowsImageDetails.BuildLabEX = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'BuildLabEX')}).Value + + ForEach ($WindowsImageDetail In $WindowsImageDetails.GetEnumerator()) + { + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Deployed Operating System - $($WindowsImageDetail.Key): $($WindowsImageDetail.Value)" + Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose + } + $DriverPackageDownloadList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]' $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to read the contents of `"$($DriverPackageMetadataPath.FullName)`". Please Wait..." @@ -769,74 +816,6 @@ Else $OperatingSystemList = $ModelDetails.OperatingSystemList.OperatingSystem | Select-Object -Property ($OperatingSystemPropertyList) -ExcludeProperty @('MinimumVersion') - $InvokeRegistryHiveActionParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' - - $FixedVolumeList = [System.IO.DriveInfo]::GetDrives() | Where-Object {($_.DriveType -iin @('Fixed')) -and ($_.IsReady -eq $True) -and ($_.Name.TrimEnd('\') -inotin @($Env:SystemDrive)) -and (([String]::IsNullOrEmpty($_.Name) -eq $False) -or ([String]::IsNullOrWhiteSpace($_.Name) -eq $False))} | Sort-Object -Property @('TotalSize') - - :FixedVolumeLoop ForEach ($FixedVolume In $FixedVolumeList) - { - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to check fixed volume `"$($FixedVolume.Name.TrimEnd('\'))`" for a valid installation of Windows." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - [System.IO.DirectoryInfo]$WindowsDirectory = "$($FixedVolume.Name.TrimEnd('\'))\Windows" - - Switch ([System.IO.Directory]::Exists($WindowsDirectory.FullName)) - { - {($_ -eq $True)} - { - $WindowsDirectoryItemList = Get-ChildItem -Path ($WindowsDirectory.FullName) -ErrorAction SilentlyContinue - - $WindowsDirectoryItemListCount = ($WindowsDirectoryItemList | Measure-Object).Count - - Switch (($WindowsDirectoryItemListCount -ge 2) -and ($WindowsDirectoryItemList | Where-Object {($_.Name -ieq 'explorer.exe')})) - { - {($_ -eq $True)} - { - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Fixed volume `"$($FixedVolume.Name.TrimEnd('\'))`" contains a valid installation of Windows." - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - - $WindowsImageDriveInfo = New-Object -TypeName 'System.IO.DriveInfo' -ArgumentList "$($FixedVolume.Name.TrimEnd('\'))" - - $InvokeRegistryHiveActionParameters.HivePath = "$($WindowsImageDriveInfo.Name.TrimEnd('\').Toupper())\Windows\System32\Config\SOFTWARE" - - Break FixedVolumeLoop - } - } - } - } - } - - #$SecondLargestVolume = ($FixedVolumeList | Sort-Object -Property 'TotalSize' -Descending)[1] - - #[System.IO.DirectoryInfo]$DriverPackageDownloadDirectory = "$($SecondLargestVolume.Name.TrimEnd('\'))\Downloads" - - [System.IO.DirectoryInfo]$DriverPackageDownloadDirectory = "$($WindowsImageDriveInfo.Name.TrimEnd('\').Toupper())\Downloads" - - $InvokeRegistryHiveActionParameters.KeyPath = New-Object -TypeName 'System.Collections.Generic.List[String]' - $InvokeRegistryHiveActionParameters.KeyPath.Add('Root\Microsoft\Windows NT\CurrentVersion') - $InvokeRegistryHiveActionParameters.ValueNameExpression = New-Object -TypeName 'System.Collections.Generic.List[Regex]' - $InvokeRegistryHiveActionParameters.ValueNameExpression.Add('.*') - $InvokeRegistryHiveActionParameters.ContinueOnError = $False - $InvokeRegistryHiveActionParameters.Verbose = $True - - $InvokeRegistryHiveActionResult = Invoke-RegistryHiveAction @InvokeRegistryHiveActionParameters - - $WindowsImageDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' - $WindowsImageDetails.MajorVersionNumber = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'CurrentMajorVersionNumber')}).Value - $WindowsImageDetails.MinorVersionNumber = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'CurrentMinorVersionNumber')}).Value - $WindowsImageDetails.BuildNumber = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'CurrentBuildNumber')}).Value - $WindowsImageDetails.RevisionNumber = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'UBR')}).Value - $WindowsImageDetails.Version = New-Object -TypeName 'System.Version' -ArgumentList @($WindowsImageDetails.MajorVersionNumber, $WindowsImageDetails.MinorVersionNumber, $WindowsImageDetails.BuildNumber, $WindowsImageDetails.RevisionNumber) - $WindowsImageDetails.ReleaseNumber = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'ReleaseID')}).Value - $WindowsImageDetails.ReleaseID = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'DisplayVersion')}).Value - $WindowsImageDetails.BuildLabEX = ($InvokeRegistryHiveActionResult[0].ValueList | Where-Object {($_.Name -ieq 'BuildLabEX')}).Value - - ForEach ($WindowsImageDetail In $WindowsImageDetails.GetEnumerator()) - { - $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Deployed Operating System - $($WindowsImageDetail.Key): $($WindowsImageDetail.Value)" - Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose - } - $OperatingSystemCriteria = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' Switch ($WindowsImageDetails.BuildLabEX) @@ -1085,7 +1064,7 @@ Else Default { - $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The generic driver package of `"$($GenericDriverPackageDetails.Metadata.Name)`" is excluded because the minimum required operating system version of `"$($GenericDriverPackageOSVersion.ToString())`" is not less than or equal to the deployed operating system version of `"$($OperatingSystemCriteria.Version.ToString())`". Skipping..." + $LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The generic driver package of `"$($GenericDriverPackageDetails.Metadata.Name)`" is excluded because the minimum required operating system version of `"$($GenericDriverPackageOSVersion)`" is not less than or equal to the deployed operating system version of `"$($OperatingSystemCriteria.Version)`". Skipping..." Write-Verbose -Message ($LoggingDetails.WarningMessage) -Verbose } } @@ -1372,7 +1351,7 @@ Else #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)" + $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Script execution took $($ScriptExecutionTimespan.Hours) hour(s), $($ScriptExecutionTimespan.Minutes) minute(s), $($ScriptExecutionTimespan.Seconds) second(s), and $($ScriptExecutionTimespan.Milliseconds) millisecond(s)" Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Exiting script `"$($ScriptPath.FullName)`" with exit code $($Script:LASTEXITCODE)." diff --git a/Invoke-DriverPackageDownload.vbs b/Invoke-DriverPackageDownload.vbs deleted file mode 100644 index 2190820..0000000 --- a/Invoke-DriverPackageDownload.vbs +++ /dev/null @@ -1,145 +0,0 @@ -'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