Initial Upload

This commit is contained in:
freedbygrace
2022-12-01 11:40:57 -05:00
committed by GitHub
commit 3fcf06990c
25 changed files with 7931 additions and 0 deletions
+118
View File
@@ -0,0 +1,118 @@
## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx
#region Function Convert-FileSize
Function Convert-FileSize
{
<#
.SYSNOPSIS
Converts a size in bytes to its upper most value.
.PARAMETER Size
The size in bytes to convert
.EXAMPLE
$ConvertFileSizeParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$ConvertFileSizeParameters.Size = 4294964
$ConvertFileSizeParameters.DecimalPlaces = 2
$ConvertFileSizeResult = Convert-FileSize @ConvertFileSizeParameters
Write-Output -InputObject ($ConvertFileSizeResult)
.EXAMPLE
$ConvertFileSizeResult = Convert-FileSize -Size 4294964
Write-Output -InputObject ($ConvertFileSizeResult)
.NOTES
Size : 429496456565656
DecimalPlaces : 0
Divisor : 1099511627776
SizeUnit : TB
SizeUnitAlias : Terabytes
CalculatedSize : 391
CalculatedSizeStr : 391 TB
#>
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[Alias("Length")]
$Size,
[Parameter(Mandatory=$False)]
[ValidateNotNullOrEmpty()]
[Alias("DP")]
[Int]$DecimalPlaces
)
Try
{
Switch ($True)
{
{([String]::IsNullOrEmpty($DecimalPlaces) -eq $True) -or ([String]::IsNullOrWhiteSpace($DecimalPlaces) -eq $True)}
{
[Int]$DecimalPlaces = 2
}
}
$OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$OutputObjectProperties.Size = $Size
$OutputObjectProperties.DecimalPlaces = $DecimalPlaces
Switch ($Size)
{
{($_ -lt 1MB)}
{
$OutputObjectProperties.Divisor = 1KB
$OutputObjectProperties.SizeUnit = 'KB'
$OutputObjectProperties.SizeUnitAlias = 'Kilobytes'
Break
}
{($_ -lt 1GB)}
{
$OutputObjectProperties.Divisor = 1MB
$OutputObjectProperties.SizeUnit = 'MB'
$OutputObjectProperties.SizeUnitAlias = 'Megabytes'
Break
}
{($_ -lt 1TB)}
{
$OutputObjectProperties.Divisor = 1GB
$OutputObjectProperties.SizeUnit = 'GB'
$OutputObjectProperties.SizeUnitAlias = 'Gigabytes'
Break
}
{($_ -ge 1TB)}
{
$OutputObjectProperties.Divisor = 1TB
$OutputObjectProperties.SizeUnit = 'TB'
$OutputObjectProperties.SizeUnitAlias = 'Terabytes'
Break
}
}
$OutputObjectProperties.CalculatedSize = [System.Math]::Round(($Size / $OutputObjectProperties.Divisor), $OutputObjectProperties.DecimalPlaces)
$OutputObjectProperties.CalculatedSizeStr = "$($OutputObjectProperties.CalculatedSize) $($OutputObjectProperties.SizeUnit)"
}
Catch
{
Write-Error -Exception $_
}
Finally
{
$OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties)
Write-Output -InputObject ($OutputObject)
}
}
#endregion
+621
View File
@@ -0,0 +1,621 @@
## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx
#region Function Copy-ItemWithProgress
Function Copy-ItemWithProgress
{
<#
.SYNOPSIS
Copies file(s) from a valid path in segments.
.DESCRIPTION
Supports the copying of files from a valid location in segments either directly or recursively.
Supports the usage of filters and exclusions exactly the way that the Get-ChildItem or Copy-Item cmdlets work.
.PARAMETER Path
A valid file or folder location.
.PARAMETER Destination
The destination directory where the content will be copied.
.PARAMETER Include
One or more filter(s) to implicitly copy what is specified.
.PARAMETER Exclude
One or more filter(s) to implicitly skip the copying of what is specified.
.PARAMETER Recurse
Recurse through the specified directories.
.PARAMETER Force
Overwrite file(s) that have already been copied. The default behavior is to skip the copying of the file.
.PARAMETER SegmentSize
The segment size in megabytes that each file will be transferred with.
.PARAMETER RandomDelay
Adds a pulse in between the transfer of each segment.
.PARAMETER ContinueOnError
Continues processing even if an error has occured.
.EXAMPLE
Copy-ItemWithProgress -Path 'FileOrDirectoryPath' -Destination 'YourDestinationDirectory' -Verbose
.EXAMPLE
$CopyItemWithProgressParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$CopyItemWithProgressParameters.Path = "FileOrDirectoryPath"
$CopyItemWithProgressParameters.Destination = "YourDestinationDirectory"
$CopyItemWithProgressParameters.Include = New-Object -TypeName 'System.Collections.Generic.List[String]'
$CopyItemWithProgressParameters.Include.Add('*.*')
$CopyItemWithProgressParameters.Exclude = New-Object -TypeName 'System.Collections.Generic.List[String]'
$CopyItemWithProgressParameters.Exclude.Add('*.ini')
$CopyItemWithProgressParameters.Recurse = $True
$CopyItemWithProgressParameters.Force = $False
$CopyItemWithProgressParameters.SegmentSize = 4096
$CopyItemWithProgressParameters.RandomDelay = $False
$CopyItemWithProgressParameters.ContinueOnError = $False
$CopyItemWithProgressParameters.Verbose = $True
$CopyItemWithProgressResult = Copy-ItemWithProgress @CopyItemWithProgressParameters
Write-Output -InputObject ($CopyItemWithProgressResult)
.NOTES
A progress bar is displayed and can be useful for scripts where the copying of large file(s) is taking place.
.LINK
http://stackoverflow.com/questions/2434133/progress-during-large-file-copy-copy-item-write-progress
.LINK
https://stackoverflow.com/questions/13883404/custom-robocopy-progress-bar-in-powershell
#>
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[ValidateScript({Test-Path -Path $_})]
[Alias('P')]
[String]$Path,
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[Alias('D')]
[System.IO.DirectoryInfo]$Destination,
[Parameter(Mandatory=$False)]
[Alias('I')]
[String[]]$Include,
[Parameter(Mandatory=$False)]
[Alias('E')]
[String[]]$Exclude,
[Parameter(Mandatory=$False)]
[Alias('R')]
[Switch]$Recurse,
[Parameter(Mandatory=$False)]
[Alias('Overwrite')]
[Switch]$Force,
[Parameter(Mandatory=$False)]
[ValidateNotNullOrEmpty()]
[Alias('SS', 'BufferInMegabytes')]
[Int]$SegmentSize,
[Parameter(Mandatory=$False)]
[Alias('RD')]
[Switch]$RandomDelay,
[Parameter(Mandatory=$False)]
[Alias('COE')]
[Switch]$ContinueOnError
)
Begin
{
Try
{
$DateTimeLogFormat = 'dddd, MMMM dd, yyyy @ hh:mm:ss.FFF tt' ###Monday, January 01, 2019 @ 10:15:34.000 AM###
[ScriptBlock]$GetCurrentDateTimeLogFormat = {(Get-Date).ToString($DateTimeLogFormat)}
$DateTimeMessageFormat = 'MM/dd/yyyy HH:mm:ss.FFF' ###03/23/2022 11:12:48.347###
[ScriptBlock]$GetCurrentDateTimeMessageFormat = {(Get-Date).ToString($DateTimeMessageFormat)}
$DateFileFormat = 'yyyyMMdd' ###20190403###
[ScriptBlock]$GetCurrentDateFileFormat = {(Get-Date).ToString($DateFileFormat)}
$DateTimeFileFormat = 'yyyyMMdd_HHmmss' ###20190403_115354###
[ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)}
$TextInfo = (Get-Culture).TextInfo
$LoggingDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$LoggingDetails.Add('LogMessage', $Null)
$LoggingDetails.Add('WarningMessage', $Null)
$LoggingDetails.Add('ErrorMessage', $Null)
$CommonParameterList = New-Object -TypeName 'System.Collections.Generic.List[String]'
$CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::CommonParameters)
$CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::OptionalCommonParameters)
$FileSystemObject = New-Object -ComObject 'Scripting.FileSystemObject'
[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)
#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)
[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)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($FunctionName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
#region Load any required libraries
[System.IO.DirectoryInfo]$LibariesDirectory = "$($FunctionDirectory.FullName)\Libraries"
Switch ([System.IO.Directory]::Exists($LibariesDirectory.FullName))
{
{($_ -eq $True)}
{
$LibraryPatternList = New-Object -TypeName 'System.Collections.Generic.List[String]'
#$LibraryPatternList.Add('')
Switch ($LibraryPatternList.Count -gt 0)
{
{($_ -eq $True)}
{
$LibraryList = Get-ChildItem -Path ($LibariesDirectory.FullName) -Include ($LibraryPatternList.ToArray()) -Recurse -Force | Where-Object {($_ -is [System.IO.FileInfo])}
$LibraryListCount = ($LibraryList | Measure-Object).Count
Switch ($LibraryListCount -gt 0)
{
{($_ -eq $True)}
{
For ($LibraryListIndex = 0; $LibraryListIndex -lt $LibraryListCount; $LibraryListIndex++)
{
$Library = $LibraryList[$LibraryListIndex]
[Byte[]]$LibraryBytes = [System.IO.File]::ReadAllBytes($Library.FullName)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to load assembly `"$($Library.FullName)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$Null = [System.Reflection.Assembly]::Load($LibraryBytes)
}
}
}
}
}
}
}
#endregion
#region Set Default Parameter Values
Switch ($True)
{
{($Null -ieq $SegmentSize) -or ($SegmentSize -eq 0)}
{
[Int]$SegmentSize = 8192
}
}
#endregion
#Create an object that will contain the functions output.
$OutputObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
}
}
Process
{
Try
{
Switch ($Null -ine $Path)
{
{($_ -eq $True)}
{
$GetChildItemParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$GetChildItemParameters.Path = $Path
$GetChildItemParameters.Force = $True
$GetChildItemParameters.ErrorAction = [System.Management.Automation.Actionpreference]::SilentlyContinue
Switch ($True)
{
{([String]::IsNullOrEmpty($Include) -eq $False) -and ([String]::IsNullOrWhiteSpace($Include) -eq $False)}
{
$GetChildItemParameters.Include = $Include
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - File(s) matching $($GetChildItemParameters.Include -Join ', ') will be included."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
{([String]::IsNullOrEmpty($Exclude) -eq $False) -and ([String]::IsNullOrWhiteSpace($Exclude) -eq $False)}
{
$GetChildItemParameters.Exclude = $Exclude
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - File(s) matching $($GetChildItemParameters.Exclude -Join ', ') will be excluded."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
{($Recurse.IsPresent -eq $True)}
{
$GetChildItemParameters.Recurse = $True
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The search will be performed recursively."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
}
$FileList = Get-ChildItem @GetChildItemParameters | Where-Object {($_ -is [System.IO.FileInfo])}
$FileListDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$FileListDetails.Count = ($FileList | Measure-Object).Count
Switch ($FileListDetails.Count -gt 0)
{
{($_ -eq $True)}
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($FileListDetails.Count) file(s) will be copied in $($SegmentSize) MB segments to the destination directory of `"$($Destination.FullName)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$FileListDetails.TotalBytes = ($FileList | Measure-Object -Sum 'Length').Sum
$FileListDetails.TransferredBytes = 0
$FileListDetails.PercentComplete = 0
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A total of $([System.Math]::Round(($FileListDetails.TotalBytes / 1MB), 2)) MB needs to be transferred."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$StopWatchTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$StopWatchTable.Primary = New-Object -TypeName 'System.Diagnostics.Stopwatch'
$StopWatchTable.Secondary = New-Object -TypeName 'System.Diagnostics.Stopwatch'
$Null = $StopWatchTable.Primary.Start()
For ($FileListIndex = 0; $FileListIndex -lt $FileListDetails.Count; $FileListIndex++)
{
Try
{
$FileObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$FileObjectProperties.Source = ($FileList[$FileListIndex]) -As [System.IO.FileInfo]
Switch ($Recurse.IsPresent)
{
{($_ -eq $True)}
{
$FileObjectProperties.SourceSegmentList = $FileObjectProperties.Source.FullName.Replace($Path, '').Split('\', [System.StringSplitOptions]::RemoveEmptyEntries) -As [System.Collections.Generic.List[String]]
$FileObjectProperties.Destination = (Join-Path -Path ($Destination.FullName) -ChildPath ($FileObjectProperties.SourceSegmentList -Join '\')) -As [System.IO.FileInfo]
$FileObjectProperties.Remove('SourceSegmentList')
}
Default
{
$FileObjectProperties.Destination = "$($Destination.FullName)\$($FileObjectProperties.Source.Name)" -As [System.IO.FileInfo]
}
}
Switch ($True)
{
{([System.IO.Directory]::Exists($FileObjectProperties.Destination.Directory.FullName) -eq $False)}
{
$Null = [System.IO.Directory]::CreateDirectory($FileObjectProperties.Destination.Directory.FullName)
}
}
Switch (([System.IO.File]::Exists($FileObjectProperties.Destination.FullName) -eq $False) -or ($Force.IsPresent -eq $True))
{
{($_ -eq $True)}
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to copy `"$($FileObjectProperties.Source.FullName)`" to `"$($FileObjectProperties.Destination.FullName)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$FileDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$FileDetails.Source = [System.IO.File]::OpenRead($FileObjectProperties.Source.FullName)
$FileDetails.Destination = [System.IO.File]::Create($FileObjectProperties.Destination.FullName)
$FileDetails.Buffer = New-Object -TypeName 'Byte[]' -ArgumentList ($SegmentSize * 1024)
$FileDetails.SegmentBytes = 0
$FileDetails.TransferredBytes = 0
$FileDetails.Number = $FileListIndex + 1
$Null = $StopWatchTable.Secondary.Start()
Do
{
$FileDetails.SegmentBytes = $FileDetails.Source.Read($FileDetails.Buffer, 0, $FileDetails.Buffer.Length)
$FileDetails.Destination.Write($FileDetails.Buffer, 0, $FileDetails.SegmentBytes)
$FileDetails.TransferredBytes = $FileDetails.TransferredBytes + $FileDetails.SegmentBytes
$FileListDetails.TransferredBytes = $FileListDetails.TransferredBytes + $FileDetails.SegmentBytes
Switch ($FileDetails.Source.Length -gt 1)
{
{($_ -eq $True)}
{
$FileDetails.PercentComplete = (($FileDetails.TransferredBytes / $FileDetails.Source.Length) * 100) -As [Int]
}
Default
{
$FileDetails.PercentComplete = (100) -As [Int]
}
}
$FileDetails.PercentComplete = [System.Math]::Round($FileDetails.PercentComplete, 2)
$FileDetails.TotalSecondsElasped = $StopWatchTable.Secondary.Elapsed.TotalSeconds -As [Int]
Switch ($FileDetails.TotalSecondsElasped -ne 0)
{
{($_ -eq $True)}
{
$FileDetails.TransferRate = ($FileDetails.TransferredBytes / $FileDetails.TotalSecondsElasped / 1MB) -As [Single]
}
Default
{
$FileDetails.TransferRate = (0.0) -As [Single]
}
}
$FileDetails.TransferRate = [System.Math]::Round($FileDetails.TransferRate, 2)
Switch (($Total % 1MB) -eq 0)
{
{($_ -eq $True)}
{
Switch ($FileDetails.PercentComplete -gt 0)
{
{($_ -eq $True)}
{
$FileDetails.SecondsRemaining = ((($FileDetails.TotalSecondsElasped / $FileDetails.PercentComplete) * 100) - $FileDetails.TotalSecondsElasped) -As [Int]
}
Default
{
$FileDetails.SecondsRemaining = (0) -As [Int]
}
}
$FileListDetails.PercentComplete = [System.Math]::Round((($FileListDetails.TransferredBytes / $FileListDetails.TotalBytes) * 100), 2)
$FileListDetails.TotalSecondsElasped = $StopWatchTable.Primary.Elapsed.TotalSeconds -As [Int]
Switch ($FileListDetails.PercentComplete -gt 0)
{
{($_ -eq $True)}
{
$FileListDetails.SecondsRemaining = ((($FileListDetails.TotalSecondsElasped / $FileListDetails.PercentComplete) * 100) - $FileListDetails.TotalSecondsElasped) -As [Int]
}
Default
{
$FileListDetails.SecondsRemaining = ((($FileListDetails.TotalSecondsElasped / $FileListDetails.PercentComplete) * 100) - $FileListDetails.TotalSecondsElasped) -As [Int]
}
}
$TaskSequence = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$TaskSequence.Environment = Try {New-Object -ComObject 'Microsoft.SMS.TSEnvironment'} Catch {$Null}
$TaskSequence.IsRunning = $Null -ine $TaskSequence.Environment
Switch ($TaskSequence.IsRunning)
{
{($_ -eq $True)}
{
$FileProgressParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$FileProgressParameters.ID = 1
$FileProgressParameters.Activity = "$($FileDetails.PercentComplete)% - Downloading $($FileSystemObject.GetFile($FileObjectProperties.Destination.FullName).ShortName) @ $($FileDetails.TransferRate) Mbps ($($FileDetails.Number) of $($FileListDetails.Count))"
$FileProgressParameters.Status = "$($FileDetails.PercentComplete)% - Downloading $($FileSystemObject.GetFile($FileObjectProperties.Destination.FullName).ShortName) @ $($FileDetails.TransferRate) Mbps ($($FileDetails.Number) of $($FileListDetails.Count))"
$FileProgressParameters.PercentComplete = $FileDetails.PercentComplete
$FileProgressParameters.SecondsRemaining = $FileDetails.SecondsRemaining
Write-Progress @FileProgressParameters
}
Default
{
$TotalProgressParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$TotalProgressParameters.ID = 1
$TotalProgressParameters.Activity = "$($FileListDetails.PercentComplete)% - Copying file $($FileDetails.Number) of $($FileListDetails.Count) ($($FileListDetails.Count - $($FileListIndex)) left)"
$TotalProgressParameters.Status = $FileObjectProperties.Source.FullName
$TotalProgressParameters.PercentComplete = $FileListDetails.PercentComplete
$TotalProgressParameters.SecondsRemaining = $FileListDetails.SecondsRemaining
Write-Progress @TotalProgressParameters
$FileProgressParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$FileProgressParameters.ParentID = $TotalProgressParameters.ID
$FileProgressParameters.ID = $TotalProgressParameters.ID + 1
$FileProgressParameters.Activity = "$($FileDetails.PercentComplete)% - Copying @ $($FileDetails.TransferRate) Mbps"
$FileProgressParameters.Status = $FileObjectProperties.Destination.FullName
$FileProgressParameters.PercentComplete = $FileDetails.PercentComplete
$FileProgressParameters.SecondsRemaining = $FileDetails.SecondsRemaining
Write-Progress @FileProgressParameters
}
}
}
}
Switch ($RandomDelay.IsPresent)
{
{($_ -eq $True)}
{
$Delay = Get-Random -Minimum 1 -Maximum 1500
$Null = Start-Sleep -Milliseconds ($Delay)
}
}
}
While ($FileDetails.SegmentBytes -gt 0)
$Null = $FileDetails.Source.Close()
$Null = $FileDetails.Destination.Close()
$Null = $StopWatchTable.Secondary.Stop()
$FileDetails = Get-Item -Path $FileObjectProperties.Destination.FullName -Force
$FileAttributeList = $FileDetails.PSObject.Properties | Where-Object {($_.MemberType -iin @('NoteProperty', 'Property')) -and ($_.TypeNameOfValue -ieq 'System.DateTime') -and ($_.IsSettable -eq $True) -and ($_.Name -inotmatch '.*UTC.*')}
ForEach ($FileAttribute In $FileAttributeList)
{
#$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to update file attribute `"$($FileAttribute.Name)`" on file `"$($FileDetails.FullName)`" from `"$($FileDetails.$($FileAttribute.Name))`" to `"$($FileObjectProperties.Source.$($FileAttribute.Name))`". Please Wait..."
#Write-Verbose -Message ($LoggingDetails.LogMessage)
$FileDetails.$($FileAttribute.Name) = $FileObjectProperties.Source.$($FileAttribute.Name)
}
$FileObjectProperties.Destination = $FileDetails
$FileObjectProperties.Status = 'Successful'
}
Default
{
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - File `"$($FileObjectProperties.Destination.FullName)`" already exists. Skipping."
Write-Warning -Message ($LoggingDetails.WarningMessage)
$FileObjectProperties.Status = 'Skipped'
}
}
}
Catch
{
$FileObjectProperties.Status = 'Error'
$ErrorHandlingDefinition.Invoke()
}
Finally
{
$FileObjectProperties.TimeToTransfer = $StopWatchTable.Secondary.Elapsed
$Null = $StopWatchTable.Secondary.Reset()
$FileObject = New-Object -TypeName 'PSObject' -Property ($FileObjectProperties)
$OutputObjectList.Add($FileObject)
}
}
$Null = $StopWatchTable.Primary.Stop()
$Null = $StopWatchTable.Primary.Reset()
$FileListStatusGroups = $OutputObjectList | Group-Object -Property 'Status' | Sort-Object -Property @('Name')
ForEach ($FileListStatusGroup In $FileListStatusGroups)
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($FileListStatusGroup.Count) of $($FileListDetails.Count) file(s) have a status of `"$($FileListStatusGroup.Name)`"."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
}
Default
{
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - There are $($FileListDetails.Count) file(s) to copy to `"$($Destination.FullName)`". No further action will be taken."
Write-Warning -Message ($LoggingDetails.WarningMessage)
}
}
}
Default
{
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - There were 0 paths specified to search. No further action will be taken."
Write-Warning -Message ($LoggingDetails.WarningMessage)
}
}
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
$Null = Start-Sleep -Seconds 3
}
}
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)
#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)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is completed."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
#Write the object to the powershell pipeline
$OutputObjectList = $OutputObjectList.ToArray()
Write-Output -InputObject ($OutputObjectList)
}
}
}
#endregion
+300
View File
@@ -0,0 +1,300 @@
## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx
#region Function Get-WindowsReleaseHistory
Function Get-WindowsReleaseHistory
{
<#
.SYNOPSIS
Retrieves the Windows release history by scraping the release information from the internet
.DESCRIPTION
Slightly more detailed description of what your function does
.EXAMPLE
Get-WindowsReleaseHistory -Verbose
.EXAMPLE
Get-WindowsReleaseHistory -Force -Verbose
.NOTES
a global variable named 'WindowsReleaseHistory' will be created that will store the release details. To keep web request traffic to a minimum, repeat executions of this function will return cached data unless the '-Force' parameter is specified.
$Global:WindowsReleaseHistory
.LINK
https://learn.microsoft.com/en-us/windows/release-health/release-information
.LINK
https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information
#>
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$False)]
[Switch]$Force,
[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)
[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]$FunctionPath = $PSCommandPath
[System.IO.DirectoryInfo]$FunctionDirectory = "$($FunctionPath.Directory.FullName)"
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is beginning. Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
#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)
[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)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($FunctionName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
#region Load any required libraries
[System.IO.DirectoryInfo]$LibariesDirectory = "$($FunctionDirectory.FullName)\Libraries"
Switch ([System.IO.Directory]::Exists($LibariesDirectory.FullName))
{
{($_ -eq $True)}
{
$LibraryPatternList = New-Object -TypeName 'System.Collections.Generic.List[String]'
$LibraryPatternList.Add('HtmlAgilityPack.dll')
Switch ($LibraryPatternList.Count -gt 0)
{
{($_ -eq $True)}
{
$LibraryList = Get-ChildItem -Path ($LibariesDirectory.FullName) -Include ($LibraryPatternList.ToArray()) -Recurse -Force | Where-Object {($_ -is [System.IO.FileInfo])}
$LibraryListCount = ($LibraryList | Measure-Object).Count
Switch ($LibraryListCount -gt 0)
{
{($_ -eq $True)}
{
For ($LibraryListIndex = 0; $LibraryListIndex -lt $LibraryListCount; $LibraryListIndex++)
{
$Library = $LibraryList[$LibraryListIndex]
[Byte[]]$LibraryBytes = [System.IO.File]::ReadAllBytes($Library.FullName)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to load assembly `"$($Library.FullName)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
$Null = [System.Reflection.Assembly]::Load($LibraryBytes)
}
}
}
}
}
}
}
#endregion
#Create an object that will contain the functions output.
$OutputObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
}
}
Process
{
Try
{
Switch (($Null -ieq $Global:WindowsReleaseHistory) -or ($Force.IsPresent -eq $True))
{
{($_ -eq $True)}
{
$URLList = New-Object -TypeName 'System.Collections.Generic.List[System.URI]'
$URLList.Add('https://learn.microsoft.com/en-us/windows/release-health/release-information')
$URLList.Add('https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information')
For ($URLListIndex = 0; $URLListIndex -lt $URLList.Count; $URLListIndex++)
{
$URL = $URLList[$URLListIndex]
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to retrieve data from `"$($URL.OriginalString)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$HTMLWebRequest = New-Object -TypeName 'HtmlAgilityPack.HtmlWeb'
$HTMLWebRequestObject = $HTMLWebRequest.Load($URL.OriginalString)
$HTMLDocumentObject = $HTMLWebRequestObject.DocumentNode
$MetadataList = $HTMLDocumentObject.SelectNodes('/html/head//meta') | Where-Object {($_.OuterHTML -imatch '.*og\:title.*')}
$OGTitle = ($MetadataList[0].Attributes | Where-Object {($_.Name -ieq 'Content')}).Value
$HistoryTableList = $HTMLDocumentObject.SelectNodes('//table') | Where-Object {($_.ID -imatch '(^HistoryTable_\d+$)')}
$RootNodeList = $HTMLDocumentObject.SelectNodes('//strong')
For ($RootNodeListIndex = 0; $RootNodeListIndex -lt $RootNodeList.Count; $RootNodeListIndex++)
{
$RootNode = $RootNodeList[$RootNodeListIndex]
$RootNodeRegexData = [Regex]::Match($RootNode.InnerText, '(?:.*Version\s+)(?<OSReleaseID>\w{4,4})(?:.*)(?:\s+\(OS\s+build\s+)(?<OSBuild>\d{5,5})(?:.+)')
Switch ($RootNodeRegexData.Success)
{
{($_ -eq $True)}
{
$OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$OutputObjectProperties.Vendor = 'Microsoft'
$OutputObjectProperties.Name = [Regex]::Match($OGTitle, 'W.+\d+').Value
$OutputObjectProperties.ReleaseID = ($RootNodeRegexData.Groups | Where-Object {($_.Name -ieq 'OSReleaseID')}).Value
$OutputObjectProperties.Build = ($RootNodeRegexData.Groups | Where-Object {($_.Name -ieq 'OSBuild')}).Value
$OutputObjectProperties.Version = "10.0.$($OutputObjectProperties.Build)" -As [System.Version]
$OutputObjectProperties.ReleaseHistory = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
<#
$HistoryTableChildNodeList = ($HistoryTableList | Where-Object {($_.InnerText -imatch ".*$($OutputObjectProperties.Build).*")}).ChildNodes | Where-Object {([String]::IsNullOrEmpty($_.InnerText) -eq $False) -and ([String]::IsNullOrWhiteSpace($_.InnerText) -eq $False)} | Sort-Object -Property @('InnerText') -Unique
For ($HistoryTableChildNodeIndex = 0; $HistoryTableChildNodeIndex -lt $HistoryTableChildNodeList.Count; $HistoryTableChildNodeIndex++)
{
$HistoryTableChildNode = $HistoryTableChildNodeList[$HistoryTableChildNodeIndex]
$InnerTextLines = $HistoryTableChildNode.InnerText.Split("`n", [System.StringSplitOptions]::RemoveEmptyEntries).Trim()
For ($InnerTextLineIndex = 0; $InnerTextLineIndex -lt $InnerTextLines.Count; $InnerTextLineIndex++)
{
$InnerTextLine = $InnerTextLines[$InnerTextLineIndex]
#$InnerTextLine
}
}
#>
$OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties)
$OutputObjectList.Add($OutputObject)
}
}
}
}
#Write the object to the powershell pipeline
$OutputObjectList = $OutputObjectList.ToArray()
$Global:WindowsReleaseHistory = $OutputObjectList | Sort-Object -Property @('Version')
}
Default
{
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The Windows release history has already been retrieved. Returning cached results in order to reduce web request traffic."
Write-Warning -Message ($LoggingDetails.WarningMessage)
}
}
}
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)
#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)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is completed."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
Write-Output -InputObject ($Global:WindowsReleaseHistory)
}
}
}
#endregion
<#
Get-WindowsReleaseHistory -Force:$False -Verbose
#>
+343
View File
@@ -0,0 +1,343 @@
## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx
#region Function Invoke-FileDownload
Function Invoke-FileDownload
{
<#
.SYNOPSIS
Downloads the specified URL.
.DESCRIPTION
The file will only be downloaded if the last modified date of the source URL is different from the last modified date of the file that has already been downloaded or if the file have not already been downloaded.
.PARAMETER URL
The URL where the file is located.
.PARAMETER Destination
The full file path where the cabinet will be downloaded to. If not specified, a default value will be used.
.EXAMPLE
Invoke-FileDownload -URL 'https://dl.dell.com/catalog/DriverPackCatalog.cab' -Destination "$($Env:ProgramData)\Dell\DriverPackCatalog\DriverPackCatalog.cab" -Verbose
.EXAMPLE
$DownloadDetails = Invoke-FileDownload -URL 'https://dl.dell.com/catalog/DriverPackCatalog.cab' -Destination "$($Env:ProgramData)\Dell\DriverPackCatalog\DriverPackCatalog.cab" -Verbose
Write-Output -InputObject ($DownloadDetails)
.EXAMPLE
$InvokeFileDownloadParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$InvokeFileDownloadParameters.URL = 'https://dl.dell.com/catalog/DriverPackCatalog.cab' -As [System.URI]
$InvokeFileDownloadParameters.Destination = "$($Env:ProgramData)\Dell\DriverPackCatalog\DriverPackCatalog.cab" -As [System.IO.FileInfo]
$InvokeFileDownloadParameters.ContinueOnError = $False
$InvokeFileDownloadParameters.Verbose = $True
$InvokeFileDownloadResult = Invoke-FileDownload @InvokeFileDownloadParameters
Write-Output -InputObject ($InvokeFileDownloadResult)
.NOTES
NEL : {"report_to":"network-errors","max_age":3600}
Report-To : {"group":"network-errors","max_age":3600,"endpoints":[{"url":"https://www.dell.com/support/onlineapi/nellogger/log"}]}
Accept-Ranges : bytes
Content-Type : application/vnd.ms-cab-compressed
ETag : "8043933683ddd81:0"
Last-Modified : Tue, 11 Oct 2022 15:07:43 GMT
Server : Microsoft-IIS/10.0
X-Powered-By : ASP.NET
x-arr-set : arr4
Content-Length : 270867
Date : Thu, 20 Oct 2022 15:51:44 GMT
Connection : keep-alive
Akamai-Request-BC : [a=23.207.199.174,b=78861523,c=g,n=US_VA_STERLING,o=20940]
.LINK
https://learn.microsoft.com/en-us/dotnet/api/system.net.webrequest?view=netframework-4.8
.LINK
https://learn.microsoft.com/en-us/dotnet/api/system.net.webclient.downloaddata?view=netframework-4.8#system-net-webclient-downloaddata(system-uri)
#>
[CmdletBinding(ConfirmImpact = 'Low', SupportsShouldProcess = $True)]
Param
(
[Parameter(Mandatory=$True, ValueFromPipelineByPropertyName = $True)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('^http(s)\:\/\/.*\/.*\.(.{3,4})$')]
[System.URI]$URL,
[Parameter(Mandatory=$False, ValueFromPipelineByPropertyName = $True)]
[ValidateNotNullOrEmpty()]
[System.IO.DirectoryInfo]$Destination,
[Parameter(Mandatory=$False, ValueFromPipelineByPropertyName = $True)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('^.*\.(.*)$')]
[String]$FileName,
[Parameter(Mandatory=$False)]
[Switch]$ContinueOnError
)
Begin
{
Try
{
Switch ($True)
{
{([String]::IsNullOrEmpty($Destination) -eq $True) -or ([String]::IsNullOrWhiteSpace($Destination) -eq $True)}
{
[System.IO.DirectoryInfo]$Destination = "$($Env:Windir)\Temp"
}
{([String]::IsNullOrEmpty($FileName) -eq $True) -or ([String]::IsNullOrWhiteSpace($FileName) -eq $True)}
{
[String]$FileName = [System.IO.Path]::GetFileName($URL.OriginalString)
}
}
[System.IO.FileInfo]$DestinationPath = "$($Destination.FullName)\$($FileName)"
$DateTimeLogFormat = 'dddd, MMMM dd, yyyy @ hh:mm:ss tt' ###Monday, January 01, 2019 @ 10:15:34 AM###
[ScriptBlock]$GetCurrentDateTimeLogFormat = {(Get-Date).ToString($DateTimeLogFormat)}
$DateTimeMessageFormat = 'MM/dd/yyyy HH:mm:ss.FFF' ###03/23/2022 11:12:48.347###
[ScriptBlock]$GetCurrentDateTimeMessageFormat = {(Get-Date).ToString($DateTimeMessageFormat)}
$DateFileFormat = 'yyyyMMdd' ###20190403###
[ScriptBlock]$GetCurrentDateFileFormat = {(Get-Date).ToString($DateFileFormat)}
$DateTimeFileFormat = 'yyyyMMdd_HHmmss' ###20190403_115354###
[ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)}
$TextInfo = (Get-Culture).TextInfo
$LoggingDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$LoggingDetails.Add('LogMessage', $Null)
$LoggingDetails.Add('WarningMessage', $Null)
$LoggingDetails.Add('ErrorMessage', $Null)
$CommonParameterList = New-Object -TypeName 'System.Collections.Generic.List[String]'
$CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::CommonParameters)
$CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::OptionalCommonParameters)
[ScriptBlock]$ErrorHandlingDefinition = {
$ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$ErrorMessageList.Add('Message', $_.Exception.Message)
$ErrorMessageList.Add('Category', $_.Exception.ErrorRecord.FullyQualifiedErrorID)
$ErrorMessageList.Add('Script', $_.InvocationInfo.ScriptName)
$ErrorMessageList.Add('LineNumber', $_.InvocationInfo.ScriptLineNumber)
$ErrorMessageList.Add('LinePosition', $_.InvocationInfo.OffsetInLine)
$ErrorMessageList.Add('Code', $_.InvocationInfo.Line.Trim())
ForEach ($ErrorMessage In $ErrorMessageList.GetEnumerator())
{
$LoggingDetails.ErrorMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - ERROR: $($ErrorMessage.Key): $($ErrorMessage.Value)"
Write-Warning -Message ($LoggingDetails.ErrorMessage)
}
Switch (($ContinueOnError.IsPresent -eq $False) -or ($ContinueOnError -eq $False))
{
{($_ -eq $True)}
{
Throw
}
}
}
#Determine the date and time we executed the function
$FunctionStartTime = (Get-Date)
[String]$CmdletName = $MyInvocation.MyCommand.Name
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($CmdletName)`' is beginning. Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
#Define Default Action Preferences
$ErrorActionPreference = 'Stop'
[String[]]$AvailableScriptParameters = (Get-Command -Name ($CmdletName)).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)
[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)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($CmdletName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
$OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$OutputObjectProperties.DownloadRequired = $False
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
}
}
Process
{
Try
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to create a web request for `"$($URL.OriginalString)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$WebRequest = [System.Net.WebRequest]::Create($URL.OriginalString)
$WebRequestResponse = $WebRequest.GetResponse()
$WebRequestResponseHeaders = $WebRequestResponse.Headers
$WebRequestHeaderProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
ForEach ($WebRequestResponseHeader In $WebRequestResponseHeaders.AllKeys)
{
$WebRequestHeaderProperties."$($WebRequestResponseHeader)" = ($WebRequestResponseHeaders.GetValues($WebRequestResponseHeader))[0]
}
$WebRequestHeaders = New-Object -TypeName 'PSObject' -Property ($WebRequestHeaderProperties)
$WebRequestHeaders.'Last-Modified' = (Get-Date -Date $WebRequestHeaders.'Last-Modified').ToUniversalTime()
$ContentLengthInMB = [System.Math]::Round(($WebRequestHeaders.'Content-Length' / 1MB), 2)
[ScriptBlock]$ExecuteDownload = {
$WebClient = New-Object -TypeName 'System.Net.WebClient'
$WebClient.UseDefaultCredentials = $True
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to download data stream from `"$($URL.OriginalString)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$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 = [System.IO.File]::WriteAllBytes($DestinationPath.FullName, $DownloadedData)
[Int]$SecondsToWait = 3
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Pausing script execution for $($SecondsToWait) second(s). Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$Null = Start-Sleep -Seconds ($SecondsToWait)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to update the last modified date of `"$($DestinationPath.FullName)`" to match `"$($URL.OriginalString)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Last Modified Date (Local): $($DestinationPath.LastWriteTimeUTC.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Last Modified Date (Source): $($WebRequestHeaders.'Last-Modified'.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
$Null = (Get-Item -Path $DestinationPath.FullName -Force).LastWriteTimeUTC = $WebRequestHeaders.'Last-Modified'
$Null = $WebClient.Dispose()
}
Switch ([System.IO.File]::Exists($DestinationPath.FullName))
{
{($_ -eq $True)}
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Destination path `"$($DestinationPath.FullName)`" already exists."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to check the last modified date of `"$($DestinationPath.FullName)`" to see if a download is necessary."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Last Modified Date (Source): $($WebRequestHeaders.'Last-Modified'.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Last Modified Date (Local): $($DestinationPath.LastWriteTimeUTC.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
Switch (($DestinationPath.LastWriteTimeUTC -ine $WebRequestHeaders.'Last-Modified'))
{
{($_ -eq $True)}
{
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A redownload of `"$($URL.OriginalString)`" is necessary."
Write-Warning -Message ($LoggingDetails.WarningMessage)
$OutputObjectProperties.DownloadRequired = $True
$ExecuteDownload.InvokeReturnAsIs()
}
Default
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A redownload of `"$($URL.OriginalString)`" is not necessary."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
}
}
Default
{
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Destination path `"$($DestinationPath.FullName)`" does not exist."
Write-Warning -Message ($LoggingDetails.WarningMessage)
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A download of `"$($URL.OriginalString)`" is necessary."
Write-Warning -Message ($LoggingDetails.WarningMessage)
$OutputObjectProperties.DownloadRequired = $True
$ExecuteDownload.InvokeReturnAsIs()
}
}
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
Try {$Null = $WebRequestResponse.Dispose()} Catch {}
}
}
End
{
Try
{
#Determine the date and time the function completed execution
$FunctionEndTime = (Get-Date)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($CmdletName) ended on $($FunctionEndTime.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
#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)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($CmdletName)`' is completed."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
$DestinationPathDetails = Get-Item -Path $DestinationPath.FullName -Force
$OutputObjectProperties.DownloadPath = $DestinationPathDetails
$OutputObjectProperties.URL = $URL
$OutputObjectProperties.URLHeaders = $WebRequestHeaders
$OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties)
Write-Output -InputObject ($OutputObject)
}
}
}
#endregion
@@ -0,0 +1,565 @@
## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx
#region Function Invoke-FileDownloadWithProgress
Function Invoke-FileDownloadWithProgress
{
<#
.SYNOPSIS
Downloads the specified URL.
.DESCRIPTION
The file will only be downloaded if the last modified date of the source URL is different from the last modified date of the file that has already been downloaded or if the file have not already been downloaded.
.PARAMETER URL
The URL where the file is located.
.PARAMETER Destination
The directory path where the URL will be downloaded to. If not specified, a default value will be used.
.EXAMPLE
Invoke-FileDownloadWithProgress -URL 'https://dl.dell.com/catalog/DriverPackCatalog.cab' -Destination "$($Env:ProgramData)\Dell\DriverPackCatalog" -FileName "DriverPackCatalog.cab" -Verbose
.EXAMPLE
$DownloadDetails = Invoke-FileDownloadWithProgress -URL 'https://dl.dell.com/catalog/DriverPackCatalog.cab' -Destination "$($Env:ProgramData)\Dell\DriverPackCatalog" -Verbose
Write-Output -InputObject ($DownloadDetails)
.EXAMPLE
$InvokeFileDownloadWithProgressParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$InvokeFileDownloadWithProgressParameters.URL = 'https://dl.dell.com/catalog/DriverPackCatalog.cab' -As [System.URI]
$InvokeFileDownloadWithProgressParameters.Destination = "$($Env:ProgramData)\Dell\DriverPackCatalog" -As [System.IO.DirectoryInfo]
$InvokeFileDownloadWithProgressParameters.FileName = "DriverPackCatalog.cab"
$InvokeFileDownloadWithProgressParameters.ContinueOnError = $False
$InvokeFileDownloadWithProgressParameters.Verbose = $True
$InvokeFileDownloadWithProgressResult = Invoke-FileDownloadWithProgress @InvokeFileDownloadWithProgressParameters
Write-Output -InputObject ($InvokeFileDownloadWithProgressResult)
.NOTES
NEL : {"report_to":"network-errors","max_age":3600}
Report-To : {"group":"network-errors","max_age":3600,"endpoints":[{"url":"https://www.dell.com/support/onlineapi/nellogger/log"}]}
Accept-Ranges : bytes
Content-Type : application/vnd.ms-cab-compressed
ETag : "8043933683ddd81:0"
Last-Modified : Tue, 11 Oct 2022 15:07:43 GMT
Server : Microsoft-IIS/10.0
X-Powered-By : ASP.NET
x-arr-set : arr4
Content-Length : 270867
Date : Thu, 20 Oct 2022 15:51:44 GMT
Connection : keep-alive
Akamai-Request-BC : [a=23.207.199.174,b=78861523,c=g,n=US_VA_STERLING,o=20940]
.LINK
https://learn.microsoft.com/en-us/dotnet/api/system.net.webrequest?view=netframework-4.8
.LINK
https://learn.microsoft.com/en-us/dotnet/api/system.net.webclient.downloadfiletaskasync?view=netframework-4.8
#>
[CmdletBinding(ConfirmImpact = 'Low', SupportsShouldProcess = $True)]
Param
(
[Parameter(Mandatory=$True, ValueFromPipelineByPropertyName = $True)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('^http(s)\:\/\/.*\/.*\.(.{3,4})$')]
[System.URI]$URL,
[Parameter(Mandatory=$False, ValueFromPipelineByPropertyName = $True)]
[ValidateNotNullOrEmpty()]
[System.IO.DirectoryInfo]$Destination,
[Parameter(Mandatory=$False, ValueFromPipelineByPropertyName = $True)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('^.*\.(.*)$')]
[String]$FileName,
[Parameter(Mandatory=$False)]
[Switch]$ContinueOnError
)
Begin
{
Try
{
Switch ($True)
{
{([String]::IsNullOrEmpty($Destination) -eq $True) -or ([String]::IsNullOrWhiteSpace($Destination) -eq $True)}
{
[System.IO.DirectoryInfo]$Destination = "$($Env:Windir)\Temp"
}
{([String]::IsNullOrEmpty($FileName) -eq $True) -or ([String]::IsNullOrWhiteSpace($FileName) -eq $True)}
{
[String]$FileName = [System.IO.Path]::GetFileName($URL.OriginalString)
}
}
[System.IO.FileInfo]$DestinationPath = "$($Destination.FullName)\$($FileName)"
$DateTimeLogFormat = 'dddd, MMMM dd, yyyy @ hh:mm:ss tt' ###Monday, January 01, 2019 @ 10:15:34 AM###
[ScriptBlock]$GetCurrentDateTimeLogFormat = {(Get-Date).ToString($DateTimeLogFormat)}
$DateTimeMessageFormat = 'MM/dd/yyyy HH:mm:ss.FFF' ###03/23/2022 11:12:48.347###
[ScriptBlock]$GetCurrentDateTimeMessageFormat = {(Get-Date).ToString($DateTimeMessageFormat)}
$DateFileFormat = 'yyyyMMdd' ###20190403###
[ScriptBlock]$GetCurrentDateFileFormat = {(Get-Date).ToString($DateFileFormat)}
$DateTimeFileFormat = 'yyyyMMdd_HHmmss' ###20190403_115354###
[ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)}
$TextInfo = (Get-Culture).TextInfo
$LoggingDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$LoggingDetails.Add('LogMessage', $Null)
$LoggingDetails.Add('WarningMessage', $Null)
$LoggingDetails.Add('ErrorMessage', $Null)
$CommonParameterList = New-Object -TypeName 'System.Collections.Generic.List[String]'
$CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::CommonParameters)
$CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::OptionalCommonParameters)
[ScriptBlock]$ErrorHandlingDefinition = {
$ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$ErrorMessageList.Add('Message', $_.Exception.Message)
$ErrorMessageList.Add('Category', $_.Exception.ErrorRecord.FullyQualifiedErrorID)
$ErrorMessageList.Add('Script', $_.InvocationInfo.ScriptName)
$ErrorMessageList.Add('LineNumber', $_.InvocationInfo.ScriptLineNumber)
$ErrorMessageList.Add('LinePosition', $_.InvocationInfo.OffsetInLine)
$ErrorMessageList.Add('Code', $_.InvocationInfo.Line.Trim())
ForEach ($ErrorMessage In $ErrorMessageList.GetEnumerator())
{
$LoggingDetails.ErrorMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - ERROR: $($ErrorMessage.Key): $($ErrorMessage.Value)"
Write-Warning -Message ($LoggingDetails.ErrorMessage)
}
Switch (($ContinueOnError.IsPresent -eq $False) -or ($ContinueOnError -eq $False))
{
{($_ -eq $True)}
{
Throw
}
}
}
#Determine the date and time we executed the function
$FunctionStartTime = (Get-Date)
[String]$CmdletName = $MyInvocation.MyCommand.Name
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($CmdletName)`' is beginning. Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
#Define Default Action Preferences
$ErrorActionPreference = 'Stop'
[String[]]$AvailableScriptParameters = (Get-Command -Name ($CmdletName)).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)
[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)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($CmdletName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
$OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$OutputObjectProperties.DownloadRequired = $False
#region Function Convert-FileSize
Function Convert-FileSize
{
<#
.SYSNOPSIS
Converts a size in bytes to its upper most value.
.PARAMETER Size
The size in bytes to convert
.EXAMPLE
$ConvertFileSizeParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$ConvertFileSizeParameters.Size = 4294964
$ConvertFileSizeParameters.DecimalPlaces = 2
$ConvertFileSizeResult = Convert-FileSize @ConvertFileSizeParameters
Write-Output -InputObject ($ConvertFileSizeResult)
.EXAMPLE
$ConvertFileSizeResult = Convert-FileSize -Size 4294964
Write-Output -InputObject ($ConvertFileSizeResult)
.NOTES
Size : 429496456565656
DecimalPlaces : 0
Divisor : 1099511627776
SizeUnit : TB
SizeUnitAlias : Terabytes
CalculatedSize : 391
CalculatedSizeStr : 391 TB
#>
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[Alias("Length")]
$Size,
[Parameter(Mandatory=$False)]
[ValidateNotNullOrEmpty()]
[Alias("DP")]
[Int]$DecimalPlaces
)
Try
{
Switch ($True)
{
{([String]::IsNullOrEmpty($DecimalPlaces) -eq $True) -or ([String]::IsNullOrWhiteSpace($DecimalPlaces) -eq $True)}
{
[Int]$DecimalPlaces = 2
}
}
$OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$OutputObjectProperties.Size = $Size
$OutputObjectProperties.DecimalPlaces = $DecimalPlaces
Switch ($Size)
{
{($_ -lt 1MB)}
{
$OutputObjectProperties.Divisor = 1KB
$OutputObjectProperties.SizeUnit = 'KB'
$OutputObjectProperties.SizeUnitAlias = 'Kilobytes'
Break
}
{($_ -lt 1GB)}
{
$OutputObjectProperties.Divisor = 1MB
$OutputObjectProperties.SizeUnit = 'MB'
$OutputObjectProperties.SizeUnitAlias = 'Megabytes'
Break
}
{($_ -lt 1TB)}
{
$OutputObjectProperties.Divisor = 1GB
$OutputObjectProperties.SizeUnit = 'GB'
$OutputObjectProperties.SizeUnitAlias = 'Gigabytes'
Break
}
{($_ -ge 1TB)}
{
$OutputObjectProperties.Divisor = 1TB
$OutputObjectProperties.SizeUnit = 'TB'
$OutputObjectProperties.SizeUnitAlias = 'Terabytes'
Break
}
}
$OutputObjectProperties.CalculatedSize = [System.Math]::Round(($Size / $OutputObjectProperties.Divisor), $OutputObjectProperties.DecimalPlaces)
$OutputObjectProperties.CalculatedSizeStr = "$($OutputObjectProperties.CalculatedSize) $($OutputObjectProperties.SizeUnit)"
}
Catch
{
Write-Error -Exception $_
}
Finally
{
$OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties)
Write-Output -InputObject ($OutputObject)
}
}
#endregion
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
}
}
Process
{
Try
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to create a web request for `"$($URL.OriginalString)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$WebRequest = [System.Net.WebRequest]::Create($URL.OriginalString)
$WebRequestResponse = $WebRequest.GetResponse()
$WebRequestResponseHeaders = $WebRequestResponse.Headers
$WebRequestHeaderProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
ForEach ($WebRequestResponseHeader In $WebRequestResponseHeaders.AllKeys)
{
$WebRequestHeaderProperties."$($WebRequestResponseHeader)" = ($WebRequestResponseHeaders.GetValues($WebRequestResponseHeader))[0]
}
$WebRequestHeaders = New-Object -TypeName 'PSObject' -Property ($WebRequestHeaderProperties)
$WebRequestHeaders.'Last-Modified' = (Get-Date -Date $WebRequestHeaders.'Last-Modified').ToUniversalTime()
$ContentLengthInMB = [System.Math]::Round(($WebRequestHeaders.'Content-Length' / 1MB), 2)
[ScriptBlock]$ExecuteDownload = {
Try
{
$DownloadExecutionStopwatch = New-Object -TypeName 'System.Diagnostics.Stopwatch'
$WebClient = New-Object -TypeName 'System.Net.WebClient'
$WebClient.UseDefaultCredentials = $True
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to download URL `"$($URL.OriginalString)`" to `"$($DestinationPath.FullName)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Download Size: $($ContentLengthInMB) MB"
Write-Verbose -Message ($LoggingDetails.LogMessage)
If ([System.IO.Directory]::Exists($DestinationPath.Directory.FullName) -eq $False) {$Null = [System.IO.Directory]::CreateDirectory($DestinationPath.Directory.FullName)}
$Downloader = $WebClient.DownloadFileTaskAsync($URL.OriginalString, $DestinationPath.FullName)
$Null = Register-ObjectEvent -InputObject ($WebClient) -EventName 'DownloadProgressChanged' -SourceIdentifier 'WebClient.DownloadProgressChanged'
$Null = Start-Sleep -Seconds 3
$Null = $DownloadExecutionStopwatch.Start()
Switch ($Downloader.IsFaulted)
{
{($_ -eq $True)}
{
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A download error has occured. Attempting to generate the error record. Please Wait..."
Write-Warning -Message ($LoggingDetails.WarningMessage)
Write-Error -Message ($Downloader.GetAwaiter().GetResult())
}
}
While ($Downloader.IsCompleted -eq $False)
{
Switch ($Downloader.IsFaulted)
{
{($_ -eq $True)}
{
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A download error has occured. Attempting to generate the error record. Please Wait..."
Write-Warning -Message ($LoggingDetails.WarningMessage)
Write-Error -Message ($Downloader.GetAwaiter().GetResult())
Break
}
}
$EventData = Get-Event -SourceIdentifier 'WebClient.DownloadProgressChanged' | Select-Object -ExpandProperty 'SourceEventArgs' -Last 1
$EventDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$EventDetails.Received = Convert-FileSize -Size ($EventData.BytesReceived) -DecimalPlaces 2
$EventDetails.TotalToReceive = Convert-FileSize -Size ($EventData.TotalBytesToReceive) -DecimalPlaces 2
$EventDetails.ProgressPercentage = $EventData.ProgressPercentage
Switch ($DownloadExecutionStopwatch.Elapsed.Seconds -gt 0)
{
{($_ -eq $True)}
{
[Single]$TransferRate = [System.Math]::Round(($EventDetails.TotalToReceive.Size / $DownloadExecutionStopwatch.Elapsed.Seconds / 1MB), 2)
}
Default
{
[Single]$TransferRate = 0.00
}
}
$WriteProgressParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$WriteProgressParameters.Activity = "Downloading `"$($DestinationPath.Name)`""
$WriteProgressParameters.Status = "Completion Percentage: $($EventDetails.ProgressPercentage)%"
$WriteProgressParameters.PercentComplete = $EventDetails.ProgressPercentage
$WriteProgressParameters.CurrentOperation = "Downloaded $($EventDetails.Received.CalculatedSizeStr) of $($EventDetails.TotalToReceive.CalculatedSizeStr) @ $($TransferRate) Mbps"
Write-Progress @WriteProgressParameters
}
}
Catch
{
Write-Error -Exception $_
$Null = Unregister-Event -SourceIdentifier 'WebClient.DownloadProgressChanged'
$Null = $DownloadExecutionStopwatch.Stop()
$Null = $DownloadExecutionStopwatch.Reset()
Break
}
Finally
{
$WriteProgressParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$WriteProgressParameters.Activity = "Downloading `"$($DestinationPath.Name)`""
$WriteProgressParameters.Completed = $True
Write-Progress @WriteProgressParameters
$Null = Unregister-Event -SourceIdentifier 'WebClient.DownloadProgressChanged'
Switch (($Downloader.IsCompleted -eq $False) -or ($Downloader.IsFaulted -eq $True))
{
{($_ -eq $True)}
{
$Null = $Downloader.CancelAsync()
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Download failed. Attempting to remove incomplete file `"$($DestinationPath.FullName)`". Please Wait..."
Write-Warning -Message ($LoggingDetails.WarningMessage)
$Null = [System.IO.File]::Delete($DestinationPath.FullName)
}
}
$Null = $WebClient.Dispose()
$Null = $DownloadExecutionStopwatch.Stop()
}
$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)."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$Null = $DownloadExecutionStopwatch.Reset()
[Int]$SecondsToWait = 3
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Pausing script execution for $($SecondsToWait) second(s). Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$Null = Start-Sleep -Seconds ($SecondsToWait)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to update the last modified date of `"$($DestinationPath.FullName)`" to match the last modified date of `"$($URL.OriginalString)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Last Modified Date UTC (Local File): $($DestinationPath.LastWriteTimeUTC.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Last Modified Date UTC (URL Header): $($WebRequestHeaders.'Last-Modified'.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
$DestinationPathDetails = Get-Item -Path $DestinationPath.FullName -Force
$Null = $DestinationPathDetails.LastWriteTimeUTC = $WebRequestHeaders.'Last-Modified'
}
Switch ([System.IO.File]::Exists($DestinationPath.FullName))
{
{($_ -eq $True)}
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Destination path `"$($DestinationPath.FullName)`" already exists."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to check the last modified date of `"$($DestinationPath.FullName)`" to see if a download is necessary."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Last Modified Date UTC (Local File): $($DestinationPath.LastWriteTimeUTC.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Last Modified Date UTC (URL Header): $($WebRequestHeaders.'Last-Modified'.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
Switch (($DestinationPath.LastWriteTimeUTC -ine $WebRequestHeaders.'Last-Modified'))
{
{($_ -eq $True)}
{
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A redownload of `"$($URL.OriginalString)`" is necessary."
Write-Warning -Message ($LoggingDetails.WarningMessage)
$OutputObjectProperties.DownloadRequired = $True
$ExecuteDownload.InvokeReturnAsIs()
}
Default
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A redownload of `"$($URL.OriginalString)`" is not necessary."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
}
}
Default
{
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Destination path `"$($DestinationPath.FullName)`" does not exist."
Write-Warning -Message ($LoggingDetails.WarningMessage)
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A download of `"$($URL.OriginalString)`" is necessary."
Write-Warning -Message ($LoggingDetails.WarningMessage)
$OutputObjectProperties.DownloadRequired = $True
$ExecuteDownload.InvokeReturnAsIs()
}
}
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
Try {$Null = $WebRequestResponse.Dispose()} Catch {}
}
}
End
{
Try
{
#Determine the date and time the function completed execution
$FunctionEndTime = (Get-Date)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($CmdletName) ended on $($FunctionEndTime.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
#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)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($CmdletName)`' is completed."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
$DestinationPathDetails = Get-Item -Path $DestinationPath.FullName -Force
$OutputObjectProperties.DownloadPath = $DestinationPathDetails
$OutputObjectProperties.URL = $URL
$OutputObjectProperties.URLHeaders = $WebRequestHeaders
$OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties)
Write-Output -InputObject ($OutputObject)
}
}
}
#endregion
+355
View File
@@ -0,0 +1,355 @@
## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx
#region Function Invoke-RegistryHiveAction
Function Invoke-RegistryHiveAction
{
<#
.SYNOPSIS
A brief overview of what your function does
.DESCRIPTION
Slightly more detailed description of what your function does
.PARAMETER HivePath
A valid file path to a valid registry hive.
.PARAMETER KeyPath
One or more registry key paths that are relative to the specified registry hive.
.PARAMETER ValueNameExpression
One or more regular expressions that will determine which registry value names will be extracted from the specified registry hive.
.EXAMPLE
Invoke-RegistryHiveAction -HivePath "$($Env:Userprofile)\Downloads\RegistryHives\SOFTWARE" -KeyPath @('Root\Microsoft\Windows NT\CurrentVersion') -ValueNameExpression @('.*') -Verbose
.EXAMPLE
$InvokeRegistryHiveActionParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$InvokeRegistryHiveActionParameters.HivePath = "$($Env:Userprofile)\Downloads\RegistryHives\SOFTWARE"
$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
Write-Output -InputObject ($InvokeRegistryHiveActionResult)
.NOTES
Please ensure that the specified registry hive is not in use!
.LINK
https://github.com/EricZimmerman/Registry
#>
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[ValidateScript({(Test-Path -Path $_)})]
[System.IO.FileInfo]$HivePath,
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('^Root\\.+')]
[String[]]$KeyPath,
[Parameter(Mandatory=$False)]
[Regex[]]$ValueNameExpression,
[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)
[System.IO.DirectoryInfo]$System32Directory = [System.Environment]::SystemDirectory
$RegexOptionList = New-Object -TypeName 'System.Collections.Generic.List[System.Text.RegularExpressions.RegexOptions]'
$RegexOptionList.Add([System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
$ValueNameExpressionList = New-Object -TypeName 'System.Collections.Generic.List[System.Text.RegularExpressions.Regex]'
[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)
#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)
[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)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($FunctionName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
#region Load any required libraries
[System.IO.DirectoryInfo]$LibariesDirectory = "$($FunctionDirectory.FullName)\Libraries"
Switch ([System.IO.Directory]::Exists($LibariesDirectory.FullName))
{
{($_ -eq $True)}
{
$LibraryPatternList = New-Object -TypeName 'System.Collections.Generic.List[String]'
$LibraryPatternList.Add('NFluent.dll')
$LibraryPatternList.Add('NLog.dll')
$LibraryPatternList.Add('Registry.dll')
Switch ($LibraryPatternList.Count -gt 0)
{
{($_ -eq $True)}
{
$LibraryList = Get-ChildItem -Path ($LibariesDirectory.FullName) -Include ($LibraryPatternList.ToArray()) -Recurse -Force | Where-Object {($_ -is [System.IO.FileInfo])}
$LibraryListCount = ($LibraryList | Measure-Object).Count
Switch ($LibraryListCount -gt 0)
{
{($_ -eq $True)}
{
For ($LibraryListIndex = 0; $LibraryListIndex -lt $LibraryListCount; $LibraryListIndex++)
{
$Library = $LibraryList[$LibraryListIndex]
[Byte[]]$LibraryBytes = [System.IO.File]::ReadAllBytes($Library.FullName)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to load assembly `"$($Library.FullName)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$Null = [System.Reflection.Assembly]::Load($LibraryBytes)
}
}
}
}
}
}
}
#endregion
#Create an object that will contain the functions output.
$OutputObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
#Set default parameter values
Switch ($True)
{
{($Null -ieq $ValueNameExpression) -or ($ValueNameExpression.Count -eq 0)}
{
$ValueNameExpression += '.*'
}
{($Null -ine $ValueNameExpression) -or ($ValueNameExpression.Count -gt 0)}
{
$ValueNameExpression | ForEach-Object {$ValueNameExpressionList.Add((New-Object -TypeName 'System.Text.RegularExpressions.Regex' -ArgumentList @($_, $RegexOptionList)))}
}
}
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
}
}
Process
{
Try
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to load registry hive `"$($HivePath.FullName)`" on demand. Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$RegistryHive = New-Object -TypeName 'Registry.RegistryHiveOnDemand' -ArgumentList ($HivePath.FullName)
ForEach ($Key In $KeyPath)
{
Try
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to retrieve the details of registry key path `"$($Key)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$RegistryKeyProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$RegistryKeyProperties.Path = $Key
$RegistryKeyProperties.ValueList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
$RegistryKey = $RegistryHive.GetKey($Key)
ForEach ($Item In $RegistryKey.Values)
{
ForEach ($Expression In $ValueNameExpressionList)
{
$ExpressionEvaluation = $Expression.Match($Item.ValueName)
Switch ($ExpressionEvaluation.Success)
{
{($_ -eq $True)}
{
$ValueProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$ValueProperties.Name = $Item.ValueName
$ValueProperties.Alias = $ValueProperties.Name -ireplace '(\s+)', ''
$ValueProperties.Type = $Item.ValueType
$ValueProperties.Value = $Null
$ValueProperties.ValueAsDecimal = $Null
$ValueProperties.ValueAsHex = $Null
#$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to retrieve the registry key value of `"$($ValueProperties.Name)`" because the value name matches the regular expression of `"$($Expression.ToString())`". Please Wait..."
#Write-Verbose -Message ($LoggingDetails.LogMessage)
Switch ($Null -ine $Item.ValueData)
{
{($_ -eq $True)}
{
$ValueProperties.Value = $Item.ValueData
Switch ($ValueProperties.Type)
{
{($_ -iin @('RegDword', 'RegQword'))}
{
$ValueProperties.ValueAsDecimal = Try {[System.Convert]::ToString($ValueProperties.Value, 10)} Catch {}
$ValueProperties.ValueAsHex = Try {'0x' + [System.Convert]::ToString($ValueProperties.Value, 16).PadLeft(8, '0').ToUpper()} Catch {}
}
{($_ -iin @('RegBinary'))}
{
#$ValueProperties.ValueAsDecimal = Try {} Catch {}
#$ValueProperties.ValueAsHex = Try {} Catch {}
}
}
}
}
$ValueObject = New-Object -TypeName 'PSObject' -Property ($ValueProperties)
$RegistryKeyProperties.ValueList.Add($ValueObject)
}
}
}
}
$RegistryKeyObject = New-Object -TypeName 'PSObject' -Property ($RegistryKeyProperties)
$OutputObjectList.Add($RegistryKeyObject)
}
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)
}
}
Finally
{
}
}
}
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)
#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)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is completed."
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
#Write the object to the powershell pipeline
$OutputObjectList = $OutputObjectList.ToArray()
Write-Output -InputObject ($OutputObjectList)
}
}
}
#endregion
+436
View File
@@ -0,0 +1,436 @@
## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx
#region Function Invoke-SQLDBQuery
Function Invoke-SQLDBQuery
{
<#
.SYNOPSIS
This function is able to execute one or more queries against an the specified Microsoft SQL database using either Windows or SQL authentication.
.DESCRIPTION
The database connection will be opened, each database query will be executed, the results will be stored, and the database connection will be closed.
.PARAMETER Server
.PARAMETER Instance
.PARAMETER Port
.PARAMETER UserID
.PARAMETER Password
.PARAMETER Database
.PARAMETER DBQueryList
.EXAMPLE
$DBQueryResults = Invoke-SQLDBQuery -Server 'MyDBServer.mydomain.com' -UserID 'SQLAuthUser' -Password 'SQLAuthUserPassword' -Database 'YourDatabaseName' -DBQueryList @('Select * From YourTableName') -Verbose
Write-Output -InputObject ($DBQueryResults)
.EXAMPLE
$DBQueryList = [System.Collections.Generic.List[String]]@()
$DBQueryList.Add(@"
Select Distinct
dbo.v_Add_Remove_Programs.DisplayName0 As 'DisplayName'
From
dbo.v_Add_Remove_Programs
Order By
dbo.v_Add_Remove_Programs.DisplayName0
"@)
$DBQueryResults = Invoke-SQLDBQuery -Server 'MyDBServer.mydomain.com' -Database 'YourDatabaseName' -DBQueryList ($DBQueryList) -Verbose
.EXAMPLE
$DBQueryResults = Invoke-SQLDBQuery -Server 'MyDBServer.mydomain.com' -Instance 'MyDBInstance' -Database 'YourDatabaseName' -DBQueryList @('Select * From YourTableName')
Write-Output -InputObject ($DBQueryResults)
.EXAMPLE
$DBQueryResults = Invoke-SQLDBQuery -Server 'MyDBServer.mydomain.com' -Port '4530' -Database 'YourDatabaseName' -DBQueryList @('Select * From YourTableName1', 'Select * From YourTableName2')
Write-Output -InputObject ($DBQueryResults)
.LINK
https://www.SQLshack.com/connecting-powershell-to-SQL-server/
.LINK
https://stackoverflow.com/questions/64681003/fetch-a-whole-row-from-SQL-server-with-powershell
#>
[CmdletBinding(ConfirmImpact = 'Low', HelpURI = '', DefaultParameterSetName = '_AllParameterSets', SupportsShouldProcess = $True, PositionalBinding = $True)]
Param
(
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[String]$Server,
[Parameter(Mandatory=$False)]
[ValidateNotNullOrEmpty()]
[String]$Instance,
[Parameter(Mandatory=$False)]
[ValidateNotNullOrEmpty()]
[String]$Port,
[Parameter(Mandatory=$False)]
[ValidateNotNullOrEmpty()]
[String]$UserID,
[Parameter(Mandatory=$False)]
[ValidateNotNullOrEmpty()]
[String]$Password,
[Parameter(Mandatory=$False)]
[ValidateNotNullOrEmpty()]
[String]$Database,
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[String[]]$DBQueryList,
[Parameter(Mandatory=$False, ParameterSetName = 'Export')]
[Switch]$ExportJSON,
[Parameter(Mandatory=$False, ParameterSetName = 'Export')]
[System.IO.DirectoryInfo]$ExportDirectory,
[Parameter(Mandatory=$False)]
[Switch]$ContinueOnError
)
Begin
{
[ScriptBlock]$ErrorHandlingDefinition = {
If ([String]::IsNullOrEmpty($_.Exception.Message)) {$ExceptionMessage = "$($_.Exception.Errors.Message -Join "`r`n`r`n")"} Else {$ExceptionMessage = "$($_.Exception.Message)"}
[String]$ErrorMessage = "[Error Message: $($ExceptionMessage)]`r`n`r`n[ScriptName: $($_.InvocationInfo.ScriptName)]`r`n[Line Number: $($_.InvocationInfo.ScriptLineNumber)]`r`n[Line Position: $($_.InvocationInfo.OffsetInLine)]`r`n[Code: $($_.InvocationInfo.Line.Trim())]"
If ($ContinueOnError.IsPresent -eq $True)
{
Write-Warning -Message ($ErrorMessage)
}
ElseIf ($ContinueOnError.IsPresent -eq $False)
{
Throw ($ErrorMessage)
}
}
Try
{
$DateTimeMessageFormat = 'MM/dd/yyyy HH:mm:ss.FFF' ###03/23/2022 11:12:48.347###
[ScriptBlock]$GetCurrentDateTimeMessageFormat = {(Get-Date).ToString($DateTimeMessageFormat)}
$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)}
$DateFileFormat = 'yyyyMMdd' ###20190403###
[ScriptBlock]$GetCurrentDateFileFormat = {(Get-Date).ToString($DateFileFormat)}
$DateTimeFileFormat = 'yyyyMMdd_HHmmss' ###20190403_115354###
[ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)}
$TextInfo = (Get-Culture).TextInfo
#Determine the date and time we executed the function
$FunctionStartTime = (Get-Date)
[String]$CmdletName = $MyInvocation.MyCommand.Name
$LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($CmdletName)`' is beginning. Please Wait..."
Write-Verbose -Message $LogMessage
#Define Default Action Preferences
$ErrorActionPreference = 'Stop'
$LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The following parameters and values were provided to the `'$($CmdletName)`' function."
Write-Verbose -Message $LogMessage
$FunctionProperties = Get-Command -Name $CmdletName
$FunctionParameters = $FunctionProperties.Parameters.Keys | Where-Object {($_ -inotmatch '(^Password$)|(^UserID$)|(^DBQueryList$)')}
ForEach ($Parameter In $FunctionParameters)
{
If (!([String]::IsNullOrEmpty($Parameter)))
{
$ParameterProperties = Get-Variable -Name $Parameter -ErrorAction SilentlyContinue
$ParameterValueCount = $ParameterProperties.Value | Measure-Object | Select-Object -ExpandProperty Count
If ($ParameterValueCount -gt 1)
{
$ParameterValueStringFormat = ($ParameterProperties.Value | ForEach-Object {"`"$($_)`""}) -Join ", "
$LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($ParameterProperties.Name):`r`n`r`n$($ParameterValueStringFormat)"
}
Else
{
$ParameterValueStringFormat = ($ParameterProperties.Value | ForEach-Object {"`"$($_)`""}) -Join ', '
$LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($ParameterProperties.Name): $($ParameterValueStringFormat)"
}
If (!([String]::IsNullOrEmpty($ParameterProperties.Name)))
{
Write-Verbose -Message $LogMessage
}
}
}
$LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($CmdletName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))"
Write-Verbose -Message $LogMessage
#Create an array list that will contain the functions output
$OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
#Define Variable(s)
$LoggingDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$LoggingDetails.Add('LogMessage', $Null)
$LoggingDetails.Add('WarningMessage', $Null)
$LoggingDetails.Add('ErrorMessage', $Null)
#Create a database connection string builder
$DBConnectionStringBuilder = [System.Data.SQLClient.SQLConnectionStringBuilder]::New()
#Create a database data source builder
$DataSourceBuilder = [System.Text.StringBuilder]::New()
#Dynamically build the connection string based on parameter values
Switch ($True)
{
{([String]::IsNullOrEmpty($Server) -eq $False) -and ([String]::IsNullOrWhiteSpace($Server) -eq $False)}
{
$Null = $DataSourceBuilder.Append($Server)
}
{([String]::IsNullOrEmpty($Instance) -eq $False) -and ([String]::IsNullOrWhiteSpace($Instance) -eq $False)}
{
$Null = $DataSourceBuilder.Append("\$($Instance)")
}
{([String]::IsNullOrEmpty($Port) -eq $False) -and ([String]::IsNullOrWhiteSpace($Port) -eq $False)}
{
$Null = $DataSourceBuilder.Append(",$($Port)")
}
{([String]::IsNullOrEmpty($Database) -eq $False) -and ([String]::IsNullOrWhiteSpace($Database) -eq $False)}
{
$DBConnectionStringBuilder.PSBase.InitialCatalog = $Database
}
{([String]::IsNullOrEmpty($ExportDirectory) -eq $True) -and ([String]::IsNullOrWhiteSpace($ExportDirectory) -eq $True)}
{
[System.IO.DirectoryInfo]$ExportDirectory = "$($Env:Public)\Documents\Reports\$($CmdletName)"
}
}
$DBConnection = [System.Data.SQLClient.SQLConnection]::New()
Switch (([String]::IsNullOrEmpty($UserID) -eq $True) -or ([String]::IsNullOrWhiteSpace($UserID) -eq $True) -or ([String]::IsNullOrEmpty($Password) -eq $True) -or ([String]::IsNullOrWhiteSpace($Password) -eq $True))
{
{($_ -eq $True)}
{
$DBConnectionStringBuilder.PSBase.IntegratedSecurity = $True
}
Default
{
$DBConnectionStringBuilder.PSBase.IntegratedSecurity = $False
$Credential = [System.Management.Automation.PSCredential]::New($UserID, (ConvertTo-SecureString -String $Password -AsPlainText -Force))
$Null = $Credential.Password.MakeReadOnly()
$DBConnectionCredential = [System.Data.SQLClient.SQLCredential]::New($Credential.UserName, $Credential.Password)
$DBConnection.Credential = ($DBConnectionCredential)
}
}
$DBConnectionStringBuilder.PSBase.DataSource = $DataSourceBuilder.ToString()
$DBConnectionString = $DBConnectionStringBuilder.ConnectionString
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - " + "Database Connection String = $($DBConnectionString)"
Write-Verbose -Message ($LoggingDetails.LogMessage)
$DBConnection.ConnectionString = ($DBConnectionString)
$LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to open the database connection. Please Wait..."
Write-Verbose -Message $LogMessage
$DBConnection.Open()
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
}
Process
{
For ($DBQueryListIndex = 0; $DBQueryListIndex -lt $DBQueryList.Count; $DBQueryListIndex++)
{
Try
{
[String]$DBQuery = $DBQueryList[$DBQueryListIndex]
[Int]$DBQueryNumber = $DBQueryListIndex + 1
$DBCommand = [System.Data.SQLClient.SQLCommand]::New()
$DBCommand.Connection = ($DBConnection)
$DBCommand.CommandText = ($DBQuery)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - " + "Attempting to execute database query #$($DBQueryNumber). Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$Null = $DBCommand.ExecuteScalar()
$DBQueryResults = [System.Data.DataTable]::New()
$DBDataAdapter = [System.Data.SQLClient.SQLDataAdapter]::New($DBCommand)
$Null = $DBDataAdapter.Fill($DBQueryResults)
$DBQueryRowCount = $DBQueryResults.Rows.Count
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - " + "$($DBQueryRowCount) row(s) were returned from the database query."
Write-Verbose -Message ($LoggingDetails.LogMessage)
Switch ($DBQueryRowCount -gt 0)
{
{($_ -eq $True)}
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - " + "Database Query Column Names = $($DBQueryResults.Columns.ColumnName -Join ', ')"
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
}
[String]$ResultSetNumber = ($DBQueryNumber).ToString('000')
[String]$ResultSetPropertyName = "ResultSet$($ResultSetNumber)"
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - " + "Attempting to add the result(s) from database query #$($DBQueryNumber) to property `"$($ResultSetPropertyName)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$PropertyInclusionList = [System.Collections.Generic.List[Object]]@()
$Null = $PropertyInclusionList.Add('*')
$PropertyExclusionList = [System.Collections.Generic.List[Object]]@()
$Null = $PropertyExclusionList.AddRange(('HasErrors', 'ItemArray', 'RowError', 'RowState', 'Table'))
$DBQueryRows = $DBQueryResults.Rows | Select-Object -Property ($PropertyInclusionList) -ExcludeProperty ($PropertyExclusionList)
$Null = $OutputObjectProperties.Add($ResultSetPropertyName, $DBQueryRows)
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
Finally
{
Try
{
$Null = $DBQueryResults.Dispose()
$Null = $DBDataAdapter.Dispose()
}
Catch
{
}
}
}
}
End
{
Try
{
#Close the database connection
$LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to close the database connection. Please Wait..."
Write-Verbose -Message $LogMessage
$Null = $DBConnection.Close()
#Create the powershell object that will be exported to the powershell pipeline
$OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties)
#If specified, export each result set to a separate JSON file
Switch ($True)
{
{($ExportJSON.IsPresent)}
{
$ExportParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$ExportParameters.Add('Compress', $False)
$ExportParameters.Add('Encoding', [System.Text.Encoding]::Default)
$ExportParameters.Add('Depth', 10)
[String[]]$OutputObjectPropertyList = $OutputObject.PSObject.Properties.Name
For ($OutputObjectPropertyListIndex = 0; $OutputObjectPropertyListIndex -lt $OutputObjectPropertyList.Count; $OutputObjectPropertyListIndex++)
{
[String]$OutputObjectPropertyName = $OutputObjectPropertyList[$OutputObjectPropertyListIndex]
[System.IO.FileInfo]$OutputObjectExportPath = "$($ExportDirectory.FullName)\$($OutputObjectPropertyName).json"
Switch ([System.IO.File]::Exists($OutputObjectExportPath.FullName))
{
{($_ -eq $True)}
{
[String]$JSONContents = [System.IO.File]::ReadAllText($OutputObjectExportPath.FullName, $ExportParameters.Encoding)
$JSONObject = ConvertFrom-JSON -InputObject ($JSONContents)
$OutputObjectPropertyValue = $OutputObject.$($OutputObjectPropertyName)
$JSONObject.$($OutputObjectPropertyName) = ($OutputObjectPropertyValue)
[String]$OutputObjectPropertyValueAsJSON = $JSONObject | ConvertTo-JSON -Depth ($ExportParameters.Depth) -Compress:($ExportParameters.Compress)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - " + "Attempting to update the result set `"$($OutputObjectPropertyName)`" within the file of `"$($OutputObjectExportPath.FullName)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$Null = [System.IO.File]::WriteAllText($OutputObjectExportPath.FullName, $OutputObjectPropertyValueAsJSON, $ExportParameters.Encoding)
}
{($_ -eq $False)}
{
$OutputObjectPropertyValue = $OutputObject | Select-Object -Property @($OutputObjectPropertyName)
[String]$OutputObjectPropertyValueAsJSON = $OutputObjectPropertyValue | ConvertTo-JSON -Depth ($ExportParameters.Depth) -Compress:($ExportParameters.Compress)
Switch ([System.IO.Directory]::Exists($OutputObjectExportPath.Directory.FullName))
{
{($_ -eq $False)}
{
$Null = [System.IO.Directory]::CreateDirectory($OutputObjectExportPath.Directory.FullName)
}
}
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - " + "Attempting to export the result set `"$($OutputObjectPropertyName)`" to the file of `"$($OutputObjectExportPath.FullName)`". Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$Null = [System.IO.File]::WriteAllText($OutputObjectExportPath.FullName, $OutputObjectPropertyValueAsJSON, $ExportParameters.Encoding)
}
}
}
}
}
#Write the object to the powershell pipeline
Write-Output -InputObject ($OutputObject)
#Determine the date and time the function completed execution
$FunctionEndTime = (Get-Date)
$LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($CmdletName) ended on $($FunctionEndTime.ToString($DateTimeLogFormat))"
Write-Verbose -Message $LogMessage
#Log the total script execution time
$FunctionExecutionTimespan = New-TimeSpan -Start ($FunctionStartTime) -End ($FunctionEndTime)
$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 $LogMessage
$LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($CmdletName)`' is completed."
Write-Verbose -Message $LogMessage
}
Catch
{
$ErrorHandlingDefinition.Invoke()
}
}
}
#endregion
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+366
View File
@@ -0,0 +1,366 @@
#region Start-ProcessWithOutput
Function Start-ProcessWithOutput
{
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$True)]
[ValidateNotNullOrEmpty()]
[String]$FilePath,
[Parameter(Mandatory=$False)]
[AllowEmptyCollection()]
[AllowNull()]
[String[]]$ArgumentList,
[Parameter(Mandatory=$False)]
[AllowEmptyCollection()]
[AllowNull()]
[String[]]$AcceptableExitCodeList,
[Parameter(Mandatory=$False)]
[ValidateNotNullOrEmpty()]
[ValidateSet('Normal', 'Hidden', 'Minimized', 'Maximized')]
[String]$WindowStyle,
[Parameter(Mandatory=$False)]
[Switch]$CreateNoWindow,
[Parameter(Mandatory=$False, ParameterSetName = 'ParseOutput')]
[Switch]$ParseOutput,
[Parameter(Mandatory=$False, ParameterSetName = 'ParseOutput')]
[ValidateNotNullOrEmpty()]
[Alias('StandardOutputParsingExpression')]
[Regex]$ParsingExpression,
[Parameter(Mandatory=$False)]
[Switch]$LogOutput
)
Try
{
$DateTimeLogFormat = 'dddd, MMMM dd, yyyy @ hh:mm:ss.FFF tt' ###Monday, January 01, 2019 @ 10:15:34.000 AM###
[ScriptBlock]$GetCurrentDateTimeLogFormat = {(Get-Date).ToString($DateTimeLogFormat)}
$DateTimeMessageFormat = 'MM/dd/yyyy HH:mm:ss.FFF' ###03/23/2022 11:12:48.347###
[ScriptBlock]$GetCurrentDateTimeMessageFormat = {(Get-Date).ToString($DateTimeMessageFormat)}
$DateFileFormat = 'yyyyMMdd' ###20190403###
[ScriptBlock]$GetCurrentDateFileFormat = {(Get-Date).ToString($DateFileFormat)}
$DateTimeFileFormat = 'yyyyMMdd_HHmmss' ###20190403_115354###
[ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)}
$LoggingDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$LoggingDetails.LogMessage = $Null
$LoggingDetails.WarningMessage = $Null
$LoggingDetails.ErrorMessage = $Null
#Determine the date and time we executed the function
$FunctionStartTime = (Get-Date)
[String]$CmdletName = $MyInvocation.MyCommand.Name
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($CmdletName)`' is beginning. Please Wait..."
Write-Verbose -Message ($LoggingDetails.LogMessage)
#Define Default Action Preferences
$ErrorActionPreference = 'Stop'
[String[]]$AvailableScriptParameters = (Get-Command -Name ($CmdletName)).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)
[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)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($CmdletName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
#Set default parameter values (If necessary)
Switch ($True)
{
{([String]::IsNullOrEmpty($WindowStyle) -eq $True) -or ([String]::IsNullOrWhiteSpace($WindowStyle) -eq $True)}
{
[String]$WindowStyle = 'Hidden'
}
{([String]::IsNullOrEmpty($ParsingExpression) -eq $True) -or ([String]::IsNullOrWhiteSpace($ParsingExpression) -eq $True)}
{
[Regex]$ParsingExpression = '(?:\s+)(?<PropertyName>.+)(?:\s+\:\s+)(?<PropertyValue>.+)'
}
}
$OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$OutputObjectProperties.ExitCode = $Null
$OutputObjectProperties.ExitCodeAsHex = $Null
$OutputObjectProperties.ExitCodeAsInteger = $Null
$OutputObjectProperties.ExitCodeAsDecimal = $Null
$OutputObjectProperties.ProcessObject = $Null
$OutputObjectProperties.StandardOutput = $Null
$OutputObjectProperties.StandardOutputObject = $Null
$OutputObjectProperties.StandardError = $Null
$OutputObjectProperties.StandardErrorObject = $Null
$Process = New-Object -TypeName 'System.Diagnostics.Process'
$Process.StartInfo.FileName = $FilePath
$Process.StartInfo.UseShellExecute = $False
$Process.StartInfo.RedirectStandardOutput = $True
$Process.StartInfo.RedirectStandardError = $True
Switch ($CreateNoWindow.IsPresent)
{
{($_ -eq $True)}
{
$Process.StartInfo.CreateNoWindow = ($CreateNoWindow.IsPresent)
}
Default
{
$Process.StartInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::$($WindowStyle)
}
}
Switch (($Null -ieq $AcceptableExitCodeList) -or ($AcceptableExitCodeList.Count -eq 0))
{
{($_ -eq $True)}
{
$AcceptableExitCodeList += '0'
$AcceptableExitCodeList += '3010'
}
}
Switch (($Null -ine $ArgumentList) -and ($ArgumentList.Count -gt 0))
{
{($_ -eq $True)}
{
$Process.StartInfo.Arguments = $ArgumentList -Join ' '
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to execute the following command: `"$($Process.StartInfo.FileName)`" $($Process.StartInfo.Arguments)"
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
Default
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to execute the following command: `"$($Process.StartInfo.FileName)`""
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
}
$Null = $Process.Start()
$OutputObjectProperties.StandardOutput = $Process.StandardOutput.ReadToEnd()
$OutputObjectProperties.StandardError = $Process.StandardError.ReadToEnd()
$Null = $Process.WaitForExit()
$OutputObjectProperties.ExitCode = $Process.ExitCode
$OutputObjectProperties.ExitCodeAsHex = Try {'0x' + [System.Convert]::ToString($OutputObjectProperties.ExitCode, 16).PadLeft(8, '0').ToUpper()} Catch {$Null}
$OutputObjectProperties.ExitCodeAsInteger = Try {$OutputObjectProperties.ExitCodeAsHex -As [Int]} Catch {$Null}
$OutputObjectProperties.ExitCodeAsDecimal = Try {[System.Convert]::ToString($OutputObjectProperties.ExitCodeAsHex, 10)} Catch {$Null}
$ExitCodeMessageList = New-Object -TypeName 'System.Collections.Generic.List[String]'
$Null = $OutputObjectProperties.GetEnumerator() | Where-Object {($_.Key -imatch '(^ExitCode.*$)')} | Sort-Object -Property @('Key') | ForEach-Object {$ExitCodeMessageList.Add("[$($_.Key): $($_.Value)]")}
$StartProcessExecutionTimespan = New-TimeSpan -Start ($Process.StartTime) -End ($Process.ExitTime)
$OutputObjectProperties.ProcessObject = $Process
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The command execution took $($StartProcessExecutionTimespan.Hours.ToString()) hour(s), $($StartProcessExecutionTimespan.Minutes.ToString()) minute(s), $($StartProcessExecutionTimespan.Seconds.ToString()) second(s), and $($StartProcessExecutionTimespan.Milliseconds.ToString()) millisecond(s)."
Write-Verbose -Message ($LoggingDetails.LogMessage)
Switch (($OutputObjectProperties.ExitCode.ToString() -iin $AcceptableExitCodeList) -or ($OutputObjectProperties.ExitCodeAsHex.ToString() -iin $AcceptableExitCodeList) -or ($OutputObjectProperties.ExitCodeAsInteger.ToString() -iin $AcceptableExitCodeList) -or ($OutputObjectProperties.ExitCodeAsDecimal.ToString() -iin $AcceptableExitCodeList))
{
{($_ -eq $True)}
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The command execution was successful. $($ExitCodeMessageList -Join ' ')"
Write-Verbose -Message ($LoggingDetails.LogMessage)
}
{($_ -eq $False)}
{
$LoggingDetails.WarningMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The command execution was unsuccessful. $($ExitCodeMessageList -Join ' ')"
Write-Warning -Message ($LoggingDetails.WarningMessage) -Verbose
$ErrorMessage = "$($LoggingDetails.WarningMessage)"
$Exception = [System.Exception]::New($ErrorMessage)
$ErrorRecord = [System.Management.Automation.ErrorRecord]::New($Exception, [System.Management.Automation.ErrorCategory]::InvalidResult.ToString(), [System.Management.Automation.ErrorCategory]::InvalidResult, $Process)
$PSCmdlet.ThrowTerminatingError($ErrorRecord)
}
}
Switch (($OutputObjectProperties.ExitCode.ToString() -iin $AcceptableExitCodeList) -or ($OutputObjectProperties.ExitCodeAsHex.ToString() -iin $AcceptableExitCodeList) -or ($OutputObjectProperties.ExitCodeAsInteger.ToString() -iin $AcceptableExitCodeList) -or ($OutputObjectProperties.ExitCodeAsDecimal.ToString() -iin $AcceptableExitCodeList))
{
{($_ -eq $True)}
{
[String]$CommandContents = $OutputObjectProperties.StandardOutput
Switch (($ParseOutput.IsPresent -eq $True) -and ([String]::IsNullOrEmpty($StandardOutputParsingExpression) -eq $False) -and ([String]::IsNullOrWhiteSpace($StandardOutputParsingExpression) -eq $False))
{
{($_ -eq $True)}
{
$RegexOptions = New-Object -TypeName 'System.Collections.Generic.List[System.Text.RegularExpressions.RegexOptions]'
$RegexOptions.Add([System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
$RegexOptions.Add([System.Text.RegularExpressions.RegexOptions]::Multiline)
[System.Text.RegularExpressions.Regex]$RegularExpression = [System.Text.RegularExpressions.Regex]::New($StandardOutputParsingExpression, $RegexOptions.ToArray())
[String[]]$RegularExpressionGroups = $RegularExpression.GetGroupNames() | Where-Object {($_ -notin @('0'))}
[System.Text.RegularExpressions.MatchCollection]$RegularExpressionMatches = $RegularExpression.Matches($CommandContents)
$StandardOutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
For ($RegularExpressionMatchIndex = 0; $RegularExpressionMatchIndex -lt $RegularExpressionMatches.Count; $RegularExpressionMatchIndex++)
{
[System.Text.RegularExpressions.Match]$RegularExpressionMatch = $RegularExpressionMatches[$RegularExpressionMatchIndex]
For ($RegularExpressionGroupIndex = 0; $RegularExpressionGroupIndex -lt $RegularExpressionGroups.Count; $RegularExpressionGroupIndex++)
{
[String]$RegularExpressionGroup = $RegularExpressionGroups[$RegularExpressionGroupIndex]
Switch ($RegularExpressionGroup)
{
{($_ -imatch '(^PropertyName$)')}
{
$PropertyDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$PropertyDetails.Add('Name', $Null)
$PropertyDetails.Add('Value', $Null)
$PropertyDetails.Name = ($RegularExpressionMatch.Groups[$($RegularExpressionGroup)].Value) -ireplace '(\s+)|(\-)|(_)', ''
}
{($_ -imatch '(^PropertyValue$)')}
{
$PropertyDetails.Value = $RegularExpressionMatch.Groups[$($RegularExpressionGroup)].Value
Switch ($True)
{
{($PropertyDetails.Value -imatch '\+(\-){1,}\+')}
{
$PropertyDetails.Value = $Null
}
{($PropertyDetails.Value -imatch '(.+\,\s+.+){1,}')}
{
#$PropertyDetails.Value = $PropertyDetails.Value.Split(',').Trim()
}
{($PropertyDetails.Value -imatch '.+\(.+\).+')}
{
#$PropertyDetails.Value = ($PropertyDetails.Value.Split('()', [System.StringSplitOptions]::RemoveEmptyEntries) -ireplace 'bytes', '')[1]
}
}
Switch ($Null -ine $PropertyDetails.Value)
{
{($_ -eq $True)}
{
$PropertyDetails.Value = $PropertyDetails.Value.Trim()
}
}
}
}
}
Switch ($StandardOutputObjectProperties.Contains($PropertyDetails.Name))
{
{($_ -eq $False)}
{
$Null = $StandardOutputObjectProperties.Add($PropertyDetails.Name, $PropertyDetails.Value)
}
}
}
$OutputObjectProperties.StandardOutputObject = New-Object -TypeName 'PSObject' -Property ($StandardOutputObjectProperties)
}
}
}
}
}
Catch
{
$ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
$ErrorMessageList.Add('Message', $_.Exception.Message)
$ErrorMessageList.Add('Category', $_.Exception.ErrorRecord.FullyQualifiedErrorID)
$ErrorMessageList.Add('Script', $_.InvocationInfo.ScriptName)
$ErrorMessageList.Add('LineNumber', $_.InvocationInfo.ScriptLineNumber)
$ErrorMessageList.Add('LinePosition', $_.InvocationInfo.OffsetInLine)
$ErrorMessageList.Add('Code', $_.InvocationInfo.Line.Trim())
ForEach ($ErrorMessage In $ErrorMessageList.GetEnumerator())
{
$LoggingDetails.ErrorMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - ERROR: $($ErrorMessage.Key): $($ErrorMessage.Value)"
Write-Warning -Message ($LoggingDetails.ErrorMessage) -Verbose
}
Throw "$($_.Exception.Message)"
}
Finally
{
#Dispose of the process object
Try {$Null = $Process.Dispose()} Catch {}
#Determine the date and time the function completed execution
$FunctionEndTime = (Get-Date)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($CmdletName) ended on $($FunctionEndTime.ToString($DateTimeLogFormat))"
Write-Verbose -Message ($LoggingDetails.LogMessage)
#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)
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($CmdletName)`' is completed."
Write-Verbose -Message ($LoggingDetails.LogMessage)
$OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties)
Switch (($LogOutput.IsPresent -eq $True) -or ($LogOutput -eq $True))
{
{($_ -eq $True)}
{
ForEach ($Property In $OutputObject.PSObject.Properties)
{
Switch ($Property.Name)
{
{($_ -iin @('StandardOutput', 'StandardError'))}
{
Switch (([String]::IsNullOrEmpty($Property.Value) -eq $False) -and ([String]::IsNullOrWhiteSpace($Property.Value) -eq $False))
{
{($_ -eq $True)}
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($Property.Name): $($Property.Value)"
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
}
Default
{
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - $($Property.Name): N/A"
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
}
}
}
}
}
}
}
Write-Output -InputObject ($OutputObject)
}
}
#endregion
<#
$ProcessOutput = Start-ProcessWithOutput -FilePath 'dsregcmd.exe' -ArgumentList '/status' -CreateNoWindow -Verbose
$ProcessOutput.StandardOutputObject | ConvertTo-JSON -Depth 10 -OutVariable 'AzureADDetails'
$ProcessOutput
#>