mirror of
https://github.com/Grace-Solutions/Invoke-OpenSSHConfiguration.git
synced 2026-07-26 19:48:14 +00:00
739 lines
44 KiB
PowerShell
739 lines
44 KiB
PowerShell
## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx
|
|
|
|
#region Function Get-GitRepositoryRelease
|
|
Function Get-GitRepositoryRelease
|
|
{
|
|
<#
|
|
.SYNOPSIS
|
|
Download release assets from public and private Git repositories.
|
|
|
|
.DESCRIPTION
|
|
Leverages the GitHub API (by default) to list and download release assets from public and private Git repositories.
|
|
Supports filtering by release version (latest, specific tag, or pre-release) and asset name patterns.
|
|
The function can download assets while maintaining logging through the $WriteLogMessage scriptblock from the toolkit.
|
|
|
|
.PARAMETER AccessToken
|
|
A personal access token (PAT) for authenticating with the Git API. Required for private repositories.
|
|
For GitHub, generate tokens at https://github.com/settings/tokens with appropriate repository access scopes.
|
|
|
|
.PARAMETER BaseURI
|
|
The base URI of the Git hosting API. Defaults to 'https://api.github.com' if not specified.
|
|
Can be customized for GitHub Enterprise, Gitea, GitLab, or other compatible Git hosting platforms.
|
|
|
|
.PARAMETER RepositoryOwner
|
|
The username or organization name that owns the repository. This is the first part of the repository URL path.
|
|
|
|
.PARAMETER RepositoryName
|
|
The name of the repository to access. This is the second part of the repository URL path.
|
|
|
|
.PARAMETER ReleaseTag
|
|
The specific release tag to download. If not specified, defaults to 'latest'.
|
|
Use 'latest' for the most recent non-prerelease version, or specify a tag name like 'v1.0.0'.
|
|
|
|
.PARAMETER IncludePreRelease
|
|
When specified, includes pre-release versions when searching for releases.
|
|
When combined with ReleaseTag 'latest', returns the most recent release including pre-releases.
|
|
|
|
.PARAMETER AssetInclusionExpression
|
|
A regular expression pattern to include only matching asset file names.
|
|
Defaults to '(.*)' to include all assets. Example: '\.exe$' for only .exe files.
|
|
|
|
.PARAMETER AssetExclusionExpression
|
|
A regular expression pattern to exclude matching asset file names.
|
|
Defaults to '^$' to exclude nothing (only matches empty strings). Example: '\.sig$|\.sha256$' to exclude signature files.
|
|
|
|
.PARAMETER DestinationDirectory
|
|
The local directory path where assets will be downloaded.
|
|
Defaults to '$Env:Windir\Temp\GitHubReleases\$RepositoryName' if not specified.
|
|
|
|
.PARAMETER Download
|
|
When specified, downloads the assets to the DestinationDirectory. Without this switch, only a listing is returned.
|
|
|
|
.PARAMETER Force
|
|
When specified, overwrites existing files at the destination. Without this switch, existing files are skipped.
|
|
|
|
.PARAMETER ContinueOnError
|
|
When specified, continues processing remaining items if an error occurs. Without this switch, errors are terminating.
|
|
|
|
.EXAMPLE
|
|
Download the latest Win32-OpenSSH MSI release, dynamically filtering for the current OS architecture.
|
|
|
|
# Determine the OS architecture for asset filtering (Win32, Win64, ARM64)
|
|
$OSArchitectureMap = @{
|
|
'AMD64' = 'Win64'
|
|
'x86' = 'Win32'
|
|
'ARM64' = 'ARM64'
|
|
'ARM' = 'ARM'
|
|
}
|
|
$ProcessorArchitecture = [System.Environment]::GetEnvironmentVariable('PROCESSOR_ARCHITECTURE')
|
|
$OSArchitectureFilter = $OSArchitectureMap[$ProcessorArchitecture]
|
|
|
|
# Build regex pattern to match MSI for the current architecture (e.g., "OpenSSH-Win64.*\.msi$")
|
|
$AssetPattern = "OpenSSH-$($OSArchitectureFilter).*\.msi$"
|
|
|
|
$GetGitRepositoryReleaseParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
|
$GetGitRepositoryReleaseParameters.BaseURI = 'https://api.github.com'
|
|
$GetGitRepositoryReleaseParameters.RepositoryOwner = "PowerShell"
|
|
$GetGitRepositoryReleaseParameters.RepositoryName = "Win32-OpenSSH"
|
|
$GetGitRepositoryReleaseParameters.ReleaseTag = "latest"
|
|
$GetGitRepositoryReleaseParameters.AssetInclusionExpression = $AssetPattern
|
|
$GetGitRepositoryReleaseParameters.DestinationDirectory = "$($Env:Userprofile)\Downloads\OpenSSH-Release"
|
|
$GetGitRepositoryReleaseParameters.Download = $True
|
|
$GetGitRepositoryReleaseParameters.Force = $False
|
|
$GetGitRepositoryReleaseParameters.ContinueOnError = $False
|
|
$GetGitRepositoryReleaseParameters.Verbose = $True
|
|
|
|
$GetGitRepositoryReleaseResult = Get-GitRepositoryRelease @GetGitRepositoryReleaseParameters
|
|
|
|
Write-Output -InputObject ($GetGitRepositoryReleaseResult)
|
|
|
|
.EXAMPLE
|
|
Download a specific release version from the microsoft/winget-cli repository.
|
|
|
|
$GetGitRepositoryReleaseParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
|
$GetGitRepositoryReleaseParameters.BaseURI = 'https://api.github.com'
|
|
$GetGitRepositoryReleaseParameters.RepositoryOwner = "microsoft"
|
|
$GetGitRepositoryReleaseParameters.RepositoryName = "winget-cli"
|
|
$GetGitRepositoryReleaseParameters.ReleaseTag = "v1.7.10661"
|
|
$GetGitRepositoryReleaseParameters.AssetInclusionExpression = '\.msixbundle$'
|
|
$GetGitRepositoryReleaseParameters.DestinationDirectory = "$($Env:Userprofile)\Downloads\WinGet-Release"
|
|
$GetGitRepositoryReleaseParameters.Download = $True
|
|
$GetGitRepositoryReleaseParameters.Force = $False
|
|
$GetGitRepositoryReleaseParameters.ContinueOnError = $False
|
|
$GetGitRepositoryReleaseParameters.Verbose = $True
|
|
|
|
$GetGitRepositoryReleaseResult = Get-GitRepositoryRelease @GetGitRepositoryReleaseParameters
|
|
|
|
Write-Output -InputObject ($GetGitRepositoryReleaseResult)
|
|
|
|
.EXAMPLE
|
|
Download the latest pre-release from a private repository using an access token.
|
|
|
|
$GetGitRepositoryReleaseParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
|
$GetGitRepositoryReleaseParameters.AccessToken = "YourAccessToken"
|
|
$GetGitRepositoryReleaseParameters.BaseURI = 'https://api.github.com'
|
|
$GetGitRepositoryReleaseParameters.RepositoryOwner = "YourOrganization"
|
|
$GetGitRepositoryReleaseParameters.RepositoryName = "YourPrivateRepo"
|
|
$GetGitRepositoryReleaseParameters.ReleaseTag = "latest"
|
|
$GetGitRepositoryReleaseParameters.IncludePreRelease = $True
|
|
$GetGitRepositoryReleaseParameters.DestinationDirectory = "$($Env:Userprofile)\Downloads\PrivateRelease"
|
|
$GetGitRepositoryReleaseParameters.Download = $True
|
|
$GetGitRepositoryReleaseParameters.Force = $True
|
|
$GetGitRepositoryReleaseParameters.ContinueOnError = $False
|
|
$GetGitRepositoryReleaseParameters.Verbose = $True
|
|
|
|
$GetGitRepositoryReleaseResult = Get-GitRepositoryRelease @GetGitRepositoryReleaseParameters
|
|
|
|
Write-Output -InputObject ($GetGitRepositoryReleaseResult)
|
|
|
|
.NOTES
|
|
This function uses the $WriteLogMessage scriptblock from the toolkit for logging.
|
|
Ensure the toolkit is dot-sourced before calling this function for proper logging support.
|
|
|
|
This function could also theoretically support Git repositories outside of GitHub, such as Gitea, or GitLab,
|
|
provided they have compatible API endpoints.
|
|
|
|
.LINK
|
|
https://docs.github.com/en/rest/releases/releases
|
|
|
|
.LINK
|
|
https://docs.github.com/en/rest/releases/assets
|
|
#>
|
|
|
|
[CmdletBinding(ConfirmImpact = 'Low')]
|
|
Param
|
|
(
|
|
[Parameter(Mandatory=$False)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[System.String]$AccessToken,
|
|
|
|
[Parameter(Mandatory=$False)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[System.URI]$BaseURI,
|
|
|
|
[Parameter(Mandatory=$True)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[System.String]$RepositoryOwner,
|
|
|
|
[Parameter(Mandatory=$True)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[System.String]$RepositoryName,
|
|
|
|
[Parameter(Mandatory=$False)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[System.String]$ReleaseTag,
|
|
|
|
[Parameter(Mandatory=$False)]
|
|
[Switch]$IncludePreRelease,
|
|
|
|
[Parameter(Mandatory=$False)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[Regex]$AssetInclusionExpression,
|
|
|
|
[Parameter(Mandatory=$False)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[Regex]$AssetExclusionExpression,
|
|
|
|
[Parameter(Mandatory=$False)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[System.IO.DirectoryInfo]$DestinationDirectory,
|
|
|
|
[Parameter(Mandatory=$False)]
|
|
[Switch]$Download,
|
|
|
|
[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
|
|
$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 = {
|
|
Param
|
|
(
|
|
[Int16]$Severity,
|
|
[Boolean]$ContinueOnError
|
|
)
|
|
|
|
$ExceptionPropertyDictionary = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
|
$ExceptionPropertyDictionary.Message = $_.Exception.Message
|
|
$ExceptionPropertyDictionary.Category = $_.Exception.ErrorRecord.FullyQualifiedErrorID
|
|
$ExceptionPropertyDictionary.Script = Try {[System.IO.Path]::GetFileName($_.InvocationInfo.ScriptName)} Catch {$Null}
|
|
$ExceptionPropertyDictionary.LineNumber = $_.InvocationInfo.ScriptLineNumber
|
|
$ExceptionPropertyDictionary.LinePosition = $_.InvocationInfo.OffsetInLine
|
|
$ExceptionPropertyDictionary.Code = $_.InvocationInfo.Line.Trim()
|
|
|
|
$ExceptionMessageList = New-Object -TypeName 'System.Collections.Generic.List[String]'
|
|
|
|
ForEach ($ExceptionProperty In $ExceptionPropertyDictionary.GetEnumerator())
|
|
{
|
|
Switch ($Null -ine $ExceptionProperty.Value)
|
|
{
|
|
{($_ -eq $True)}
|
|
{
|
|
$ExceptionMessageList.Add("[$($ExceptionProperty.Key): $($ExceptionProperty.Value)]")
|
|
}
|
|
}
|
|
}
|
|
|
|
$LogMessageParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
|
$LogMessageParameters.Message = $ExceptionMessageList -Join ' '
|
|
$LogMessageParameters.Verbose = $True
|
|
|
|
Switch ($Severity)
|
|
{
|
|
{($_ -in @(1))} {$WriteLogMessage.Invoke(1, @($LogMessageParameters.Message))}
|
|
{($_ -in @(2))} {$WriteLogMessage.Invoke(2, @($LogMessageParameters.Message))}
|
|
{($_ -in @(3))} {$WriteLogMessage.Invoke(3, @($LogMessageParameters.Message))}
|
|
}
|
|
|
|
Switch ($ContinueOnError)
|
|
{
|
|
{($_ -eq $False)}
|
|
{
|
|
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
|
|
[System.IO.FileInfo]$FunctionPath = "$($InvokingScriptDirectory)\Functions\$($FunctionName).ps1"
|
|
[System.IO.DirectoryInfo]$FunctionDirectory = "$($FunctionPath.Directory)"
|
|
|
|
$WriteLogMessage.Invoke(0, @("Function `'$($FunctionName)`' is beginning. Please Wait..."))
|
|
|
|
#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)"}
|
|
$WriteLogMessage.Invoke(0, @("Available Function Parameter(s) = $($AvailableScriptParameters -Join ', ')"))
|
|
|
|
[String[]]$SuppliedScriptParameters = $PSBoundParameters.GetEnumerator() | ForEach-Object {Try {"-$($_.Key):$($_.Value.GetType().Name)"} Catch {"-$($_.Key):Unknown"}}
|
|
$WriteLogMessage.Invoke(0, @("Supplied Function Parameter(s) = $($SuppliedScriptParameters -Join ', ')"))
|
|
|
|
$WriteLogMessage.Invoke(0, @("Execution of $($FunctionName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))"))
|
|
|
|
#region Adjust security protocol type(s)
|
|
[System.Net.SecurityProtocolType]$DesiredSecurityProtocol = [System.Net.SecurityProtocolType]::TLS12
|
|
|
|
$WriteLogMessage.Invoke(0, @("Attempting to set the desired security protocol to `"$($DesiredSecurityProtocol.ToString().ToUpper())`". Please Wait..."))
|
|
|
|
$Null = [System.Net.ServicePointManager]::SecurityProtocol = ($DesiredSecurityProtocol)
|
|
#endregion
|
|
|
|
#Define default parameter values
|
|
Switch ($True)
|
|
{
|
|
{([String]::IsNullOrEmpty($BaseURI) -eq $True) -or ([String]::IsNullOrWhiteSpace($BaseURI) -eq $True)}
|
|
{
|
|
[System.URI]$BaseURI = 'https://api.github.com'
|
|
}
|
|
|
|
{([String]::IsNullOrEmpty($ReleaseTag) -eq $True) -or ([String]::IsNullOrWhiteSpace($ReleaseTag) -eq $True)}
|
|
{
|
|
[System.String]$ReleaseTag = 'latest'
|
|
}
|
|
|
|
{([String]::IsNullOrEmpty($DestinationDirectory) -eq $True) -or ([String]::IsNullOrWhiteSpace($DestinationDirectory) -eq $True)}
|
|
{
|
|
[System.IO.DirectoryInfo]$DestinationDirectory = "$($Env:Windir)\Temp\GitHubReleases\$($RepositoryName)"
|
|
}
|
|
|
|
{([String]::IsNullOrEmpty($AssetInclusionExpression) -eq $True) -or ([String]::IsNullOrWhiteSpace($AssetInclusionExpression) -eq $True)}
|
|
{
|
|
[Regex]$AssetInclusionExpression = '(.*)'
|
|
}
|
|
|
|
{([String]::IsNullOrEmpty($AssetExclusionExpression) -eq $True) -or ([String]::IsNullOrWhiteSpace($AssetExclusionExpression) -eq $True)}
|
|
{
|
|
[Regex]$AssetExclusionExpression = '^$'
|
|
}
|
|
}
|
|
|
|
#Define helper function
|
|
#region Function Convert-FileSize
|
|
Function Convert-FileSize
|
|
{
|
|
[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
|
|
|
|
#Create an object that will contain the functions output.
|
|
$OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
|
$OutputObjectProperties.RequestURI = $Null
|
|
$OutputObjectProperties.ReleaseInfo = $Null
|
|
$OutputObjectProperties.WebRequestResponseList = New-Object -TypeName 'System.Collections.Generic.List[System.Object]'
|
|
}
|
|
Catch
|
|
{
|
|
$ErrorHandlingDefinition.Invoke(2, $ContinueOnError.IsPresent)
|
|
}
|
|
Finally
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
Process
|
|
{
|
|
Try
|
|
{
|
|
#region Build the release request URI
|
|
$RequestURIBuilder = New-Object -TypeName 'System.Text.StringBuilder'
|
|
$Null = $RequestURIBuilder.Append($BaseURI.Scheme).Append('://')
|
|
$Null = $RequestURIBuilder.Append($BaseURI.DnsSafeHost)
|
|
$Null = $RequestURIBuilder.Append(':').Append($BaseURI.Port)
|
|
$Null = $RequestURIBuilder.Append('/').Append('repos')
|
|
$Null = $RequestURIBuilder.Append('/').Append($RepositoryOwner)
|
|
$Null = $RequestURIBuilder.Append('/').Append($RepositoryName)
|
|
$Null = $RequestURIBuilder.Append('/').Append('releases')
|
|
|
|
Switch ($ReleaseTag.ToLower())
|
|
{
|
|
{($_ -ieq 'latest')}
|
|
{
|
|
Switch ($IncludePreRelease.IsPresent)
|
|
{
|
|
{($_ -eq $True)}
|
|
{
|
|
# Get all releases and pick the first one (most recent)
|
|
$Null = $RequestURIBuilder.Append('?per_page=1')
|
|
}
|
|
|
|
Default
|
|
{
|
|
# Use the /latest endpoint for non-prerelease
|
|
$Null = $RequestURIBuilder.Append('/').Append('latest')
|
|
}
|
|
}
|
|
}
|
|
Default
|
|
{
|
|
# Specific tag requested
|
|
$Null = $RequestURIBuilder.Append('/').Append('tags').Append('/').Append($ReleaseTag)
|
|
}
|
|
}
|
|
|
|
[System.URI]$RequestURI = $RequestURIBuilder.ToString()
|
|
|
|
$WriteLogMessage.Invoke(0, @("Request URI: $($RequestURI)"))
|
|
#endregion
|
|
|
|
$OutputObjectProperties.RequestURI = $RequestURI
|
|
|
|
#region Invoke the web request to get release information
|
|
$InvokeWebRequestHeaders = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
|
$InvokeWebRequestHeaders.'Accept' = 'application/vnd.github+json'
|
|
|
|
Switch ($True)
|
|
{
|
|
{([String]::IsNullOrEmpty($AccessToken) -eq $False) -and ([String]::IsNullOrWhiteSpace($AccessToken) -eq $False)}
|
|
{
|
|
$InvokeWebRequestHeaders.Authorization = "Bearer $($AccessToken)"
|
|
}
|
|
}
|
|
|
|
$InvokeWebRequestParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
|
$InvokeWebRequestParameters.UseBasicParsing = $True
|
|
$InvokeWebRequestParameters.Uri = $RequestURI
|
|
$InvokeWebRequestParameters.UseDefaultCredentials = $True
|
|
$InvokeWebRequestParameters.DisableKeepAlive = $False
|
|
$InvokeWebRequestParameters.TimeoutSec = 30
|
|
$InvokeWebRequestParameters.Method = 'Get'
|
|
$InvokeWebRequestParameters.ContentType = 'application/vnd.github+json'
|
|
$InvokeWebRequestParameters.UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome
|
|
$InvokeWebRequestParameters.Verbose = $False
|
|
|
|
Switch ($InvokeWebRequestHeaders.Keys.Count -gt 0)
|
|
{
|
|
{($_ -eq $True)}
|
|
{
|
|
$InvokeWebRequestParameters.Headers = $InvokeWebRequestHeaders
|
|
}
|
|
}
|
|
|
|
$WriteLogMessage.Invoke(0, @("Attempting to retrieve release information. Please Wait..."))
|
|
|
|
$InvokeWebRequestResult = Invoke-WebRequest @InvokeWebRequestParameters
|
|
|
|
$WriteLogMessage.Invoke(0, @("Status Code: $($InvokeWebRequestResult.StatusCode)"))
|
|
|
|
$OutputObjectProperties.WebRequestResponseList.Add($InvokeWebRequestResult)
|
|
#endregion
|
|
|
|
#region Process the release response
|
|
Switch ($InvokeWebRequestResult.StatusCode -in @(200))
|
|
{
|
|
{($_ -eq $True)}
|
|
{
|
|
$WebRequestResponseContent = $InvokeWebRequestResult.Content
|
|
|
|
$ReleaseData = ConvertFrom-JSON -InputObject ($WebRequestResponseContent)
|
|
|
|
# Handle array response (when using per_page for pre-releases)
|
|
Switch ($ReleaseData -is [System.Array])
|
|
{
|
|
{($_ -eq $True)}
|
|
{
|
|
$ReleaseData = $ReleaseData[0]
|
|
}
|
|
}
|
|
|
|
$ReleaseInfoProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
|
$ReleaseInfoProperties.TagName = $ReleaseData.tag_name
|
|
$ReleaseInfoProperties.Name = $ReleaseData.name
|
|
$ReleaseInfoProperties.IsPreRelease = $ReleaseData.prerelease
|
|
$ReleaseInfoProperties.IsDraft = $ReleaseData.draft
|
|
$ReleaseInfoProperties.PublishedAt = $ReleaseData.published_at
|
|
$ReleaseInfoProperties.HTMLURL = $ReleaseData.html_url
|
|
$ReleaseInfoProperties.TarballURL = $ReleaseData.tarball_url
|
|
$ReleaseInfoProperties.ZipballURL = $ReleaseData.zipball_url
|
|
$ReleaseInfoProperties.Body = $ReleaseData.body
|
|
$ReleaseInfoProperties.AssetList = New-Object -TypeName 'System.Collections.Generic.List[System.Management.Automation.PSObject]'
|
|
|
|
$OutputObjectProperties.ReleaseInfo = New-Object -TypeName 'System.Management.Automation.PSObject' -Property ($ReleaseInfoProperties)
|
|
|
|
$WriteLogMessage.Invoke(0, @("Release Tag: $($OutputObjectProperties.ReleaseInfo.TagName)"))
|
|
|
|
$WriteLogMessage.Invoke(0, @("Release Name: $($OutputObjectProperties.ReleaseInfo.Name)"))
|
|
|
|
$WriteLogMessage.Invoke(0, @("Is Pre-Release: $($OutputObjectProperties.ReleaseInfo.IsPreRelease)"))
|
|
|
|
$WriteLogMessage.Invoke(0, @("Published At: $($OutputObjectProperties.ReleaseInfo.PublishedAt)"))
|
|
|
|
#region Process release assets
|
|
$ReleaseAssets = $ReleaseData.assets
|
|
|
|
$ReleaseAssetCount = ($ReleaseAssets | Measure-Object).Count
|
|
|
|
$WriteLogMessage.Invoke(0, @("Found $($ReleaseAssetCount) asset(s) in this release."))
|
|
|
|
ForEach ($Asset In $ReleaseAssets)
|
|
{
|
|
$AssetName = $Asset.name
|
|
|
|
# Apply inclusion/exclusion filters
|
|
Switch ($AssetName -imatch $AssetInclusionExpression)
|
|
{
|
|
{($_ -eq $True)}
|
|
{
|
|
Switch ($AssetName -inotmatch $AssetExclusionExpression)
|
|
{
|
|
{($_ -eq $True)}
|
|
{
|
|
$AssetObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
|
$AssetObjectProperties.Name = $AssetName
|
|
$AssetObjectProperties.DownloadURL = $Asset.browser_download_url -As [System.URI]
|
|
$AssetObjectProperties.Size = $Asset.size -As [System.UInt64]
|
|
$AssetObjectProperties.ContentType = $Asset.content_type
|
|
$AssetObjectProperties.DownloadCount = $Asset.download_count
|
|
$AssetObjectProperties.CreatedAt = $Asset.created_at
|
|
$AssetObjectProperties.UpdatedAt = $Asset.updated_at
|
|
$AssetObjectProperties.DestinationPath = [System.IO.FileInfo]"$($DestinationDirectory.FullName)\$($AssetName)"
|
|
$AssetObjectProperties.DownloadStatus = 'NotAttempted'
|
|
$AssetObjectProperties.DownloadStartTime = $Null
|
|
$AssetObjectProperties.DownloadCompletionTime = $Null
|
|
$AssetObjectProperties.DownloadDuration = $Null
|
|
|
|
$AssetObject = New-Object -TypeName 'System.Management.Automation.PSObject' -Property ($AssetObjectProperties)
|
|
|
|
$OutputObjectProperties.ReleaseInfo.AssetList.Add($AssetObject)
|
|
|
|
$WriteLogMessage.Invoke(0, @("Asset matched filters: $($AssetName) [Size: $((Convert-FileSize -Size $Asset.size).CalculatedSizeStr)]"))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
$WriteLogMessage.Invoke(0, @("$($OutputObjectProperties.ReleaseInfo.AssetList.Count) asset(s) matched the inclusion/exclusion filters."))
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
$OutputObject = New-Object -TypeName 'System.Management.Automation.PSObject' -Property ($OutputObjectProperties)
|
|
|
|
# Convert AssetList to array if ReleaseInfo exists, otherwise ensure it's an empty array
|
|
Switch ($Null -ine $OutputObject.ReleaseInfo)
|
|
{
|
|
{($_ -eq $True)}
|
|
{
|
|
Try {$OutputObject.ReleaseInfo.AssetList = $OutputObject.ReleaseInfo.AssetList.ToArray()} Catch {$OutputObject.ReleaseInfo.AssetList = @()}
|
|
}
|
|
}
|
|
|
|
#region Download assets if requested
|
|
Switch ($Download.IsPresent)
|
|
{
|
|
{($_ -eq $True)}
|
|
{
|
|
$AssetList = $OutputObject.ReleaseInfo.AssetList
|
|
|
|
$AssetListCount = ($AssetList | Measure-Object).Count
|
|
|
|
Switch ($AssetListCount -gt 0)
|
|
{
|
|
{($_ -eq $True)}
|
|
{
|
|
$AssetListCounter = 1
|
|
|
|
For ($AssetListIndex = 0; $AssetListIndex -lt $AssetListCount; $AssetListIndex++)
|
|
{
|
|
Try
|
|
{
|
|
$AssetItem = $AssetList[$AssetListIndex]
|
|
|
|
$DownloadAssetItem = {
|
|
Param
|
|
(
|
|
[System.Management.Automation.PSObject]$AssetItem
|
|
)
|
|
|
|
$WriteLogMessage.Invoke(0, @("Attempting to download asset $($AssetListCounter) of $($AssetListCount). Please Wait..."))
|
|
|
|
$WriteLogMessage.Invoke(0, @("Asset Name: $($AssetItem.Name)"))
|
|
|
|
$WriteLogMessage.Invoke(0, @("Download URL: $($AssetItem.DownloadURL)"))
|
|
|
|
$WriteLogMessage.Invoke(0, @("Destination: $($AssetItem.DestinationPath)"))
|
|
|
|
$WriteLogMessage.Invoke(0, @("Size: $((Convert-FileSize -Size $AssetItem.Size).CalculatedSizeStr)"))
|
|
|
|
$WebClient = New-Object -TypeName 'System.Net.WebClient'
|
|
|
|
Switch ([System.IO.Directory]::Exists($AssetItem.DestinationPath.Directory))
|
|
{
|
|
{($_ -eq $False)}
|
|
{
|
|
$Null = [System.IO.Directory]::CreateDirectory($AssetItem.DestinationPath.Directory)
|
|
}
|
|
}
|
|
|
|
$AssetItem.DownloadStatus = 'Attempted'
|
|
$AssetItem.DownloadStartTime = Get-Date
|
|
|
|
$Null = $WebClient.DownloadFile($AssetItem.DownloadURL, $AssetItem.DestinationPath.FullName)
|
|
|
|
$AssetItem.DownloadCompletionTime = Get-Date
|
|
$AssetItem.DownloadDuration = New-TimeSpan -Start ($AssetItem.DownloadStartTime) -End ($AssetItem.DownloadCompletionTime)
|
|
$AssetItem.DestinationPath = New-Object -TypeName 'System.IO.FileInfo' -ArgumentList @($AssetItem.DestinationPath.FullName)
|
|
$AssetItem.DownloadStatus = 'Success'
|
|
|
|
$WriteLogMessage.Invoke(0, @("Download completed in $($AssetItem.DownloadDuration.TotalSeconds.ToString('F2')) second(s)"))
|
|
}
|
|
|
|
Switch ([System.IO.File]::Exists($AssetItem.DestinationPath))
|
|
{
|
|
{($_ -eq $True)}
|
|
{
|
|
Switch ($Force.IsPresent)
|
|
{
|
|
{($_ -eq $True)}
|
|
{
|
|
$Null = $DownloadAssetItem.InvokeReturnAsIs($AssetItem)
|
|
}
|
|
|
|
Default
|
|
{
|
|
$WriteLogMessage.Invoke(0, @("Skipping download of asset $($AssetListCounter) of $($AssetListCount) - file already exists."))
|
|
|
|
$AssetItem.DownloadStatus = 'Skipped'
|
|
}
|
|
}
|
|
}
|
|
|
|
Default
|
|
{
|
|
$Null = $DownloadAssetItem.InvokeReturnAsIs($AssetItem)
|
|
}
|
|
}
|
|
}
|
|
Catch
|
|
{
|
|
$AssetItem.DownloadStatus = 'Failed'
|
|
|
|
$ErrorHandlingDefinition.Invoke(2, $ContinueOnError.IsPresent)
|
|
}
|
|
Finally
|
|
{
|
|
$AssetListCounter++
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
Catch
|
|
{
|
|
$ErrorHandlingDefinition.Invoke(2, $ContinueOnError.IsPresent)
|
|
}
|
|
Finally
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
End
|
|
{
|
|
Try
|
|
{
|
|
#Determine the date and time the function completed execution
|
|
$FunctionEndTime = (Get-Date)
|
|
|
|
$WriteLogMessage.Invoke(0, @("Execution of $($FunctionName) ended on $($FunctionEndTime.ToString($DateTimeLogFormat))"))
|
|
|
|
#Log the total script execution time
|
|
$FunctionExecutionTimespan = New-TimeSpan -Start ($FunctionStartTime) -End ($FunctionEndTime)
|
|
|
|
$WriteLogMessage.Invoke(0, @("Function execution took $($FunctionExecutionTimespan.Hours.ToString()) hour(s), $($FunctionExecutionTimespan.Minutes.ToString()) minute(s), $($FunctionExecutionTimespan.Seconds.ToString()) second(s), and $($FunctionExecutionTimespan.Milliseconds.ToString()) millisecond(s)"))
|
|
|
|
$WriteLogMessage.Invoke(0, @("Function `'$($FunctionName)`' is completed."))
|
|
}
|
|
Catch
|
|
{
|
|
$ErrorHandlingDefinition.Invoke(2, $ContinueOnError.IsPresent)
|
|
}
|
|
Finally
|
|
{
|
|
Write-Output -InputObject ($OutputObject)
|
|
}
|
|
}
|
|
}
|
|
#endregion
|