mirror of
https://github.com/Grace-Solutions/Invoke-OpenSSHConfiguration.git
synced 2026-08-10 18:26:52 +00:00
Detection, Download, and Installation Framework Completed
This commit is contained in:
@@ -0,0 +1,603 @@
|
||||
## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx
|
||||
|
||||
#region Function ConvertFrom-CertificateToPEM
|
||||
Function ConvertFrom-CertificateToPEM
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
A brief overview of what your function does
|
||||
|
||||
.DESCRIPTION
|
||||
Slightly more detailed description of what your function does
|
||||
|
||||
.PARAMETER ParameterName
|
||||
Your parameter description
|
||||
|
||||
.PARAMETER ParameterName
|
||||
Your parameter description
|
||||
|
||||
.PARAMETER ParameterName
|
||||
Your parameter description
|
||||
|
||||
.EXAMPLE
|
||||
$ConvertFromCertificateToPEMParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$ConvertFromCertificateToPEMParameters.SerialNumberList = New-Object -TypeName 'System.Collections.Generic.List[System.String]'
|
||||
$ConvertFromCertificateToPEMParameters.SerialNumberList.Add('3d05e1f73beb5d3cd1be2b9f8d96f6c323260f78')
|
||||
$ConvertFromCertificateToPEMParameters.Export = $True
|
||||
$ConvertFromCertificateToPEMParameters.ExportRootDirectory = "$($Env:Userprofile)\Downloads\Certificates"
|
||||
$ConvertFromCertificateToPEMParameters.ContinueOnError = $False
|
||||
$ConvertFromCertificateToPEMParameters.Verbose = $True
|
||||
|
||||
$ConvertFromCertificateToPEMResult = ConvertFrom-CertificateToPEM @ConvertFromCertificateToPEMParameters
|
||||
|
||||
Write-Output -InputObject ($ConvertFromCertificateToPEMResult)
|
||||
|
||||
.EXAMPLE
|
||||
[String]$RootCALocation = 'Cert:\LocalMachine\My'
|
||||
|
||||
[String]$RootCAFriendlyName = 'Self Signed Root CA Certificate'
|
||||
|
||||
$DNSHostEntry = [System.Net.Dns]::GetHostEntry('LocalHost')
|
||||
|
||||
$NewSelfSignedCertificateParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$NewSelfSignedCertificateParameters.FriendlyName = $RootCAFriendlyName
|
||||
$NewSelfSignedCertificateParameters.Subject = "$($Env:ComputerName.ToUpper())"
|
||||
$NewSelfSignedCertificateParameters.DnsName = New-Object -TypeName 'System.Collections.Generic.List[System.String]'
|
||||
$NewSelfSignedCertificateParameters.DnsName.Add($DNSHostEntry.HostName)
|
||||
$NewSelfSignedCertificateParameters.NotBefore = (Get-Date).Date
|
||||
$NewSelfSignedCertificateParameters.NotAfter = $NewSelfSignedCertificateParameters.NotBefore.Date.AddYears(10)
|
||||
$NewSelfSignedCertificateParameters.CertStoreLocation = $RootCALocation
|
||||
$NewSelfSignedCertificateParameters.KeyExportPolicy = New-Object -TypeName 'System.Collections.Generic.List[Microsoft.Certificateservices.Commands.Keyexportpolicy]'
|
||||
$NewSelfSignedCertificateParameters.KeyExportPolicy.Add('Exportable')
|
||||
$NewSelfSignedCertificateParameters.Provider = 'Microsoft Enhanced RSA and AES Cryptographic Provider'
|
||||
$NewSelfSignedCertificateParameters.TextExtension = New-Object -TypeName 'System.Collections.Generic.List[System.String]'
|
||||
$NewSelfSignedCertificateParameters.TextExtension.Add('2.5.29.19={text}CA=1&pathlength=3')
|
||||
$NewSelfSignedCertificateParameters.TextExtension.Add('2.5.29.37={text}1.3.6.1.5.5.7.3.3')
|
||||
$NewSelfSignedCertificateParameters.KeyUsageProperty = New-Object -TypeName 'System.Collections.Generic.List[Microsoft.Certificateservices.Commands.Keyusageproperty]'
|
||||
$NewSelfSignedCertificateParameters.KeyUsageProperty.Add('All')
|
||||
$NewSelfSignedCertificateParameters.KeyUsage = New-Object -TypeName 'System.Collections.Generic.List[Microsoft.Certificateservices.Commands.Keyusage]'
|
||||
$NewSelfSignedCertificateParameters.KeyUsage.Add('CertSign')
|
||||
$NewSelfSignedCertificateParameters.KeyUsage.Add('CRLSign')
|
||||
$NewSelfSignedCertificateParameters.KeyUsage.Add('DigitalSignature')
|
||||
$NewSelfSignedCertificateParameters.Confirm = $False
|
||||
|
||||
$SelfSignedCertificate = New-SelfSignedCertificate @NewSelfSignedCertificateParameters
|
||||
|
||||
$ConvertFromCertificateToPEMParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$ConvertFromCertificateToPEMParameters.CertificateList = New-Object -TypeName 'System.Collections.Generic.List[System.Security.Cryptography.X509Certificates.X509Certificate2]'
|
||||
$ConvertFromCertificateToPEMParameters.CertificateList.Add($SelfSignedCertificate)
|
||||
$ConvertFromCertificateToPEMParameters.Export = $True
|
||||
$ConvertFromCertificateToPEMParameters.ExportRootDirectory = "$($Env:Userprofile)\Downloads\Certificates"
|
||||
$ConvertFromCertificateToPEMParameters.ContinueOnError = $False
|
||||
$ConvertFromCertificateToPEMParameters.Verbose = $True
|
||||
|
||||
$ConvertFromCertificateToPEMResult = ConvertFrom-CertificateToPEM @ConvertFromCertificateToPEMParameters
|
||||
|
||||
Write-Output -InputObject ($ConvertFromCertificateToPEMResult)
|
||||
|
||||
.NOTES
|
||||
Any useful tidbits
|
||||
|
||||
.LINK
|
||||
Place any useful link here where your function or cmdlet can be referenced
|
||||
#>
|
||||
|
||||
[CmdletBinding(ConfirmImpact = 'Low', DefaultParameterSetName = 'BySerialNumber')]
|
||||
|
||||
Param
|
||||
(
|
||||
[Parameter(Mandatory=$True, ParameterSetName = 'BySerialNumber')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String[]]$SerialNumberList,
|
||||
|
||||
[Parameter(Mandatory=$True, ParameterSetName = 'ByCertificate')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[System.Security.Cryptography.X509Certificates.X509Certificate2[]]$CertificateList,
|
||||
|
||||
[Parameter(Mandatory=$False)]
|
||||
[Switch]$Export,
|
||||
|
||||
[Parameter(Mandatory=$False)]
|
||||
[AllowEmptyString()]
|
||||
[AllowNull()]
|
||||
[System.IO.DirectoryInfo]$ExportRootDirectory,
|
||||
|
||||
[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 = {
|
||||
Param
|
||||
(
|
||||
[Int16]$Severity,
|
||||
[Boolean]$ContinueOnError
|
||||
)
|
||||
|
||||
$ExceptionPropertyDictionary = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$ExceptionPropertyDictionary.Message = $_.Exception.Message
|
||||
$ExceptionPropertyDictionary.Category = $_.Exception.ErrorRecord.FullyQualifiedErrorID
|
||||
$ExceptionPropertyDictionary.Script = [System.IO.Path]::GetFileName($_.InvocationInfo.ScriptName)
|
||||
$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())
|
||||
{
|
||||
$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))} {Write-Verbose @LogMessageParameters}
|
||||
{($_ -in @(2))} {Write-Warning @LogMessageParameters}
|
||||
{($_ -in @(3))} {Write-Error @LogMessageParameters}
|
||||
}
|
||||
|
||||
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.FullName
|
||||
[System.IO.FileInfo]$FunctionPath = "$($InvokingScriptDirectory.FullName)\Functions\$($FunctionName).ps1"
|
||||
[System.IO.DirectoryInfo]$FunctionDirectory = "$($FunctionPath.Directory.FullName)"
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is beginning. Please Wait..."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
#Define Default Action Preferences
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
[String[]]$AvailableScriptParameters = (Get-Command -Name ($FunctionName)).Parameters.GetEnumerator() | Where-Object {($_.Value.Name -inotin $CommonParameterList)} | ForEach-Object {"-$($_.Value.Name):$($_.Value.ParameterType.Name)"}
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Available Function Parameter(s) = $($AvailableScriptParameters -Join ', ')"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
[String[]]$SuppliedScriptParameters = $PSBoundParameters.GetEnumerator() | ForEach-Object {Try {"-$($_.Key):$($_.Value.GetType().Name)"} Catch {"-$($_.Key):Unknown"}}
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Supplied Function Parameter(s) = $($SuppliedScriptParameters -Join ', ')"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($FunctionName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
#Create an object that will contain the functions output.
|
||||
$OutputObjectList = New-Object -TypeName 'System.Collections.Generic.List[System.Management.Automation.PSObject]'
|
||||
|
||||
#Set default parameter value(s)
|
||||
Switch ($True)
|
||||
{
|
||||
{([String]::IsNullOrEmpty($ExportRootDirectory) -eq $True) -or ([String]::IsNullOrWhiteSpace($ExportRootDirectory) -eq $True)}
|
||||
{
|
||||
[System.IO.DirectoryInfo]$ExportRootDirectory = "$($Env:Public)\Documents\$($FunctionName)"
|
||||
}
|
||||
}
|
||||
|
||||
$X509Certificate2List = New-Object -TypeName 'System.Collections.Generic.List[System.Security.Cryptography.X509Certificates.X509Certificate2]'
|
||||
|
||||
Switch ($PSCmdlet.ParameterSetName)
|
||||
{
|
||||
{($_ -iin @('BySerialNumber'))}
|
||||
{
|
||||
$ExistingCertificateList = Get-ChildItem -Path @('Microsoft.PowerShell.Security\Certificate::\') -Recurse -Force -ErrorAction SilentlyContinue | Where-Object {($Null -ine $_.SerialNumber)}
|
||||
|
||||
ForEach ($SerialNumber In $SerialNumberList)
|
||||
{
|
||||
Switch ($ExistingCertificateList.SerialNumber -icontains $SerialNumber)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$ExistingCertificates = $ExistingCertificateList | Where-Object {($_.SerialNumber -ieq $SerialNumber)} | Sort-Object -Property @('NotAfter') -Descending -Unique
|
||||
|
||||
$ExistingCertificateCount = ($ExistingCertificates | Measure-Object).Count
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Located $($ExistingCertificateCount) certificate(s) for certificate serial number `"$($SerialNumber)`"."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
Switch ($ExistingCertificateCount)
|
||||
{
|
||||
{($_ -eq 1)}
|
||||
{
|
||||
$X509Certificate2List.Add($ExistingCertificates)
|
||||
}
|
||||
|
||||
{($_ -gt 1)}
|
||||
{
|
||||
ForEach ($ExistingCertificate In $ExistingCertificates)
|
||||
{
|
||||
$X509Certificate2List.Add($ExistingCertificate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{($_ -iin @('ByCertificate'))}
|
||||
{
|
||||
$CertificateList | Sort-Object -Property @('NotAfter') -Descending -Unique | ForEach-Object {($X509Certificate2List.Add($_))}
|
||||
}
|
||||
}
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$ErrorHandlingDefinition.Invoke(2, $ContinueOnError.IsPresent)
|
||||
}
|
||||
Finally
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Process
|
||||
{
|
||||
Try
|
||||
{
|
||||
$X509Certificate2ListCounter = 1
|
||||
|
||||
$X509Certificate2ListCount = ($X509Certificate2List | Measure-Object).Count
|
||||
|
||||
For ($X509Certificate2ListIndex = 0; $X509Certificate2ListIndex -lt $X509Certificate2ListCount; $X509Certificate2ListIndex++)
|
||||
{
|
||||
Try
|
||||
{
|
||||
$X509Certificate2ListItem = $X509Certificate2List[$X509Certificate2ListIndex]
|
||||
|
||||
$OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$OutputObjectProperties.SerialNumber = $X509Certificate2ListItem.SerialNumber
|
||||
$OutputObjectProperties.Blobs = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$OutputObjectProperties.Blobs.Certificate = $Null
|
||||
$OutputObjectProperties.Blobs.PublicKey = $Null
|
||||
$OutputObjectProperties.Blobs.PrivateKey = $Null
|
||||
$OutputObjectProperties.Exports = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$OutputObjectProperties.Exports.Certificate = $Null
|
||||
$OutputObjectProperties.Exports.PublicKey = $Null
|
||||
$OutputObjectProperties.Exports.PrivateKey = $Null
|
||||
$OutputObjectProperties.Certificate = $X509Certificate2ListItem
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to process certificate `"$($X509Certificate2ListItem.SerialNumber)`". Please Wait..."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Issuer: $($X509Certificate2ListItem.Issuer)"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Thumbprint: $($X509Certificate2ListItem.Thumbprint)"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Serial Number: $($X509Certificate2ListItem.SerialNumber)"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - DNS Name List: $($X509Certificate2ListItem.DnsNameList -Join ', ')"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Not Before: $($X509Certificate2ListItem.NotBefore.ToString($DateTimeLogFormat))"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Not After: $($X509Certificate2ListItem.NotAfter.ToString($DateTimeLogFormat))"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
$StringBuilders = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$StringBuilders.Certificate = New-Object -TypeName 'System.Text.StringBuilder'
|
||||
$StringBuilders.PrivateKey = New-Object -TypeName 'System.Text.StringBuilder'
|
||||
$StringBuilders.PublicKey = New-Object -TypeName 'System.Text.StringBuilder'
|
||||
|
||||
$X509KeyStorageFlags = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$X509KeyStorageFlags.Valid = [System.Enum]::GetNames('System.Security.Cryptography.X509Certificates.X509KeyStorageFlags') | Sort-Object
|
||||
$X509KeyStorageFlags.Specified = New-Object -TypeName 'System.Collections.Generic.List[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]'
|
||||
$X509KeyStorageFlags.Specified.Add('Exportable')
|
||||
|
||||
$X509Certificate2 = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$X509Certificate2.Object = $X509Certificate2ListItem
|
||||
$X509Certificate2.ObjectEncoded = $Null
|
||||
$X509Certificate2.ContentType = $Null
|
||||
$X509Certificate2.OID = $Null
|
||||
$X509Certificate2.DSA = $Null
|
||||
$X509Certificate2.CNG = $Null
|
||||
$X509Certificate2.PublicKey = $Null
|
||||
$X509Certificate2.PublicKeyEncoded = $Null
|
||||
$X509Certificate2.PrivateKey = $Null
|
||||
$X509Certificate2.PrivateKeyEncoded = $Null
|
||||
|
||||
$X509Certificate2.ContentType = [System.Security.Cryptography.X509Certificates.X509Certificate2]::GetCertContentType($X509Certificate2.Object.RawData)
|
||||
|
||||
$X509Certificate2.ObjectEncoded = [System.Convert]::ToBase64String($X509Certificate2.Object.RawData, [System.Base64FormattingOptions]::InsertLineBreaks)
|
||||
|
||||
$Null = $StringBuilders.Certificate.Append('-----BEGIN CERTIFICATE-----').AppendLine()
|
||||
$Null = $StringBuilders.Certificate.Append($X509Certificate2.ObjectEncoded).AppendLine()
|
||||
$Null = $StringBuilders.Certificate.Append('-----END CERTIFICATE-----')
|
||||
|
||||
$OutputObjectProperties.Blobs.Certificate = $StringBuilders.Certificate.ToString()
|
||||
|
||||
$X509Certificate2.OID = [System.Security.Cryptography.OID]::New($X509Certificate2.Object.GetKeyAlgorithm())
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - A certificate key algorithm of `"$($X509Certificate2.OID.FriendlyName)`" [OID: $($X509Certificate2.OID.Value)] was detected."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
Switch ($Null -ine $X509Certificate2.Object.PublicKey)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
Switch ($X509Certificate2.OID.FriendlyName)
|
||||
{
|
||||
{($_ -iin @('RSA'))}
|
||||
{
|
||||
$X509Certificate2.DSA = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPublicKey($X509Certificate2.Object)
|
||||
$X509Certificate2.CNG = [System.Security.Cryptography.RSACNG]($X509Certificate2.DSA)
|
||||
}
|
||||
|
||||
{($_ -iin @('ECC'))}
|
||||
{
|
||||
$X509Certificate2.DSA = [System.Security.Cryptography.X509Certificates.ECDSACertificateExtensions]::GetECDSAPublicKey($X509Certificate2.Object)
|
||||
$X509Certificate2.CNG = [System.Security.Cryptography.ECDSACNG]($X509Certificate2.DSA)
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The certificate key algorithm of `"$($X509Certificate2.OID.FriendlyName)`" [OID: $($X509Certificate2.OID.Value)] is unsupported for public key extraction."
|
||||
Write-Warning -Message ($LoggingDetails.LogMessage)
|
||||
}
|
||||
}
|
||||
|
||||
$X509Certificate2.PublicKey = $X509Certificate2.CNG.Key
|
||||
|
||||
$X509Certificate2.PublicKeyEncoded = [System.Convert]::ToBase64String(($X509Certificate2.PublicKey.Export([System.Security.Cryptography.CngKeyBlobFormat]::GenericPublicBlob)), [System.Base64FormattingOptions]::InsertLineBreaks)
|
||||
|
||||
$Null = $StringBuilders.PublicKey.Append('-----BEGIN PUBLIC KEY-----').AppendLine()
|
||||
$Null = $StringBuilders.PublicKey.Append($X509Certificate2.PublicKeyEncoded).AppendLine()
|
||||
$Null = $StringBuilders.PublicKey.Append('-----END PUBLIC KEY-----')
|
||||
|
||||
$OutputObjectProperties.Blobs.PublicKey = $StringBuilders.PublicKey.ToString()
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The certificate `"$($X509Certificate2ListItem.SerialNumber)`" [Thumbprint: $($X509Certificate2ListItem.Thumbprint)] does not contain a public key."
|
||||
Write-Warning -Message ($LoggingDetails.LogMessage)
|
||||
}
|
||||
}
|
||||
|
||||
Switch ($X509Certificate2.Object.HasPrivateKey)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
Switch ($X509Certificate2.OID.FriendlyName)
|
||||
{
|
||||
{($_ -iin @('RSA'))}
|
||||
{
|
||||
$X509Certificate2.DSA = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($X509Certificate2.Object)
|
||||
$X509Certificate2.CNG = [System.Security.Cryptography.RSACNG]($X509Certificate2.DSA)
|
||||
}
|
||||
|
||||
{($_ -iin @('ECC'))}
|
||||
{
|
||||
$X509Certificate2.DSA = [System.Security.Cryptography.X509Certificates.ECDsaCertificateExtensions]::GetECDSAPrivateKey($X509Certificate2.Object)
|
||||
$X509Certificate2.CNG = [System.Security.Cryptography.ECDSACNG]($X509Certificate2.DSA)
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The certificate key algorithm of `"$($X509Certificate2.OID.FriendlyName)`" [OID: $($X509Certificate2.OID.Value)] is unsupported for private key extracted."
|
||||
Write-Warning -Message ($LoggingDetails.LogMessage)
|
||||
}
|
||||
}
|
||||
|
||||
$X509Certificate2.PrivateKey = $X509Certificate2.CNG.Key
|
||||
|
||||
$X509Certificate2.PrivateKeyEncoded = [System.Convert]::ToBase64String(($X509Certificate2.PrivateKey.Export([System.Security.Cryptography.CngKeyBlobFormat]::PKCS8PrivateBlob)), [System.Base64FormattingOptions]::InsertLineBreaks)
|
||||
|
||||
$Null = $StringBuilders.PrivateKey.Append('-----BEGIN PRIVATE KEY-----').AppendLine()
|
||||
$Null = $StringBuilders.PrivateKey.Append($X509Certificate2.PrivateKeyEncoded).AppendLine()
|
||||
$Null = $StringBuilders.PrivateKey.Append('-----END PRIVATE KEY-----')
|
||||
|
||||
$OutputObjectProperties.Blobs.PrivateKey = $StringBuilders.PrivateKey.ToString()
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - The certificate `"$($X509Certificate2ListItem.SerialNumber)`" [Thumbprint: $($X509Certificate2ListItem.Thumbprint)] does not contain a private key. Please ensure that the private key is exportable."
|
||||
Write-Warning -Message ($LoggingDetails.LogMessage)
|
||||
}
|
||||
}
|
||||
|
||||
$WriteAllTextParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$WriteAllTextParameters.Path = $Null
|
||||
$WriteAllTextParameters.Contents = $Null
|
||||
$WriteAllTextParameters.Encoding = [System.Text.Encoding]::ASCII
|
||||
|
||||
Switch ($Export.IsPresent)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$X509Certificate2.ExportDirectory = "$($ExportRootDirectory.FullName)\$($X509Certificate2ListItem.SerialNumber)" -As [System.IO.DirectoryInfo]
|
||||
|
||||
Switch (([String]::IsNullOrEmpty($OutputObjectProperties.Blobs.Certificate) -eq $False) -or ([String]::IsNullOrWhiteSpace($OutputObjectProperties.Blobs.Certificate) -eq $False))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
Switch ($True)
|
||||
{
|
||||
{([System.IO.Directory]::Exists($X509Certificate2.ExportDirectory.FullName) -eq $False)}
|
||||
{
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to create directory `"$($X509Certificate2.ExportDirectory.FullName)`". Please Wait..."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
$Null = [System.IO.Directory]::CreateDirectory($X509Certificate2.ExportDirectory.FullName)
|
||||
}
|
||||
}
|
||||
|
||||
$WriteAllTextParameters.Path = "$($X509Certificate2.ExportDirectory.FullName)\Certificate.pem"
|
||||
$WriteAllTextParameters.Contents = $OutputObjectProperties.Blobs.Certificate
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to export the certificate to `"$($WriteAllTextParameters.Path)`". Please Wait..."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
$Null = [System.IO.File]::WriteAllText($WriteAllTextParameters.Path, $WriteAllTextParameters.Contents, $WriteAllTextParameters.Encoding)
|
||||
|
||||
Switch ($?)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$OutputObjectProperties.Exports.Certificate = $WriteAllTextParameters.Path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Unable to export the certificate from `"$($X509Certificate2ListItem.SerialNumber)`" [Thumbprint: $($X509Certificate2ListItem.Thumbprint)] to `"$($WriteAllTextParameters.Path)`"."
|
||||
Write-Warning -Message ($LoggingDetails.LogMessage)
|
||||
}
|
||||
}
|
||||
|
||||
Switch (([String]::IsNullOrEmpty($OutputObjectProperties.Blobs.PublicKey) -eq $False) -or ([String]::IsNullOrWhiteSpace($OutputObjectProperties.Blobs.PublicKey) -eq $False))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$WriteAllTextParameters.Path = "$($X509Certificate2.ExportDirectory.FullName)\PublicKey.pem"
|
||||
$WriteAllTextParameters.Contents = $OutputObjectProperties.Blobs.PublicKey
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to export the public key to `"$($WriteAllTextParameters.Path)`". Please Wait..."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
$Null = [System.IO.File]::WriteAllText($WriteAllTextParameters.Path, $WriteAllTextParameters.Contents, $WriteAllTextParameters.Encoding)
|
||||
|
||||
Switch ($?)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$OutputObjectProperties.Exports.PublicKey = $WriteAllTextParameters.Path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Unable to export the public key from certificate `"$($X509Certificate2ListItem.SerialNumber)`" [Thumbprint: $($X509Certificate2ListItem.Thumbprint)] to `"$($WriteAllTextParameters.Path)`"."
|
||||
Write-Warning -Message ($LoggingDetails.LogMessage)
|
||||
}
|
||||
}
|
||||
|
||||
Switch (([String]::IsNullOrEmpty($OutputObjectProperties.Blobs.PrivateKey) -eq $False) -or ([String]::IsNullOrWhiteSpace($OutputObjectProperties.Blobs.PrivateKey) -eq $False))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$WriteAllTextParameters.Path = "$($X509Certificate2.ExportDirectory.FullName)\PrivateKey.pem"
|
||||
$WriteAllTextParameters.Contents = $OutputObjectProperties.Blobs.PrivateKey
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to export the private key to `"$($WriteAllTextParameters.Path)`". Please Wait..."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
$Null = [System.IO.File]::WriteAllText($WriteAllTextParameters.Path, $WriteAllTextParameters.Contents, $WriteAllTextParameters.Encoding)
|
||||
|
||||
Switch ($?)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$OutputObjectProperties.Exports.PrivateKey = $WriteAllTextParameters.Path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Unable to export the private key from certificate `"$($X509Certificate2ListItem.SerialNumber)`" [Thumbprint: $($X509Certificate2ListItem.Thumbprint)] to `"$($WriteAllTextParameters.Path)`"."
|
||||
Write-Warning -Message ($LoggingDetails.LogMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$ErrorHandlingDefinition.Invoke(2, $True)
|
||||
}
|
||||
Finally
|
||||
{
|
||||
$OutputObject = New-Object -TypeName 'System.Management.Automation.PSObject' -Property ($OutputObjectProperties)
|
||||
|
||||
$OutputObjectList.Add($OutputObject)
|
||||
|
||||
$X509Certificate2ListCounter++
|
||||
}
|
||||
}
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$ErrorHandlingDefinition.Invoke(2, $ContinueOnError.IsPresent)
|
||||
}
|
||||
Finally
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
End
|
||||
{
|
||||
Try
|
||||
{
|
||||
#Determine the date and time the function completed execution
|
||||
$FunctionEndTime = (Get-Date)
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($FunctionName) ended on $($FunctionEndTime.ToString($DateTimeLogFormat))"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
#Log the total script execution time
|
||||
$FunctionExecutionTimespan = New-TimeSpan -Start ($FunctionStartTime) -End ($FunctionEndTime)
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function execution took $($FunctionExecutionTimespan.Hours.ToString()) hour(s), $($FunctionExecutionTimespan.Minutes.ToString()) minute(s), $($FunctionExecutionTimespan.Seconds.ToString()) second(s), and $($FunctionExecutionTimespan.Milliseconds.ToString()) millisecond(s)"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is completed."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$ErrorHandlingDefinition.Invoke(2, $ContinueOnError.IsPresent)
|
||||
}
|
||||
Finally
|
||||
{
|
||||
#Write the object to the powershell pipeline
|
||||
$OutputObjectList = $OutputObjectList.ToArray()
|
||||
|
||||
Write-Output -InputObject ($OutputObjectList)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -0,0 +1,738 @@
|
||||
## 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
|
||||
@@ -0,0 +1,670 @@
|
||||
## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx
|
||||
|
||||
#region Function Get-InstalledSoftware
|
||||
Function Get-InstalledSoftware
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Retrieves a list of software installed on the current device.
|
||||
|
||||
.DESCRIPTION
|
||||
Supports filtering the resulting list of software by using regular expressions.
|
||||
|
||||
.PARAMETER FilterInclusionExpression
|
||||
Includes software based on their display name.
|
||||
|
||||
.PARAMETER FilterInclusionExpression
|
||||
Excludes software based on their display name.
|
||||
|
||||
.PARAMETER PropertyList
|
||||
Retrieves the value of each specified value name for a piece software. This will make the returned objects uniform.
|
||||
|
||||
By default, the following properties are retrieved by default. Additional non specified properties are also added to the returned objects for easier locating of software outside of this function.
|
||||
|
||||
.PARAMETER AllProperties
|
||||
Retrieves the value of each value name that is detected for a piece of software. This will make the returned objects non-uniform because of how software vendors have not standardized this process.
|
||||
|
||||
.PARAMETER AllUserProfiles
|
||||
When this function is executed with the appropriate permissions, all user profile(s) can be searched for software by using their SIDs. The user profile(s) will be dynamically determined and associated with the pieces of software that are located.
|
||||
|
||||
.PARAMETER AdditionalRegistryHiveObjects
|
||||
Allows for searching additional registry hives as necessary in order to extend the search. See examples below.
|
||||
|
||||
.PARAMETER ContinueOnError
|
||||
Continues processing even if an error has occured.
|
||||
|
||||
.EXAMPLE
|
||||
Get-InstalledSoftware -AllProperties
|
||||
|
||||
.EXAMPLE
|
||||
$GetInstalledSoftwareParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$GetInstalledSoftwareParameters.FilterExpression = {($_.DisplayName -imatch '(^.*Google.*Chrome.*$)') -and ([Version]$_.DisplayVersion -ge [Version]'75.0.0.0')}
|
||||
$GetInstalledSoftwareParameters.AllProperties = $False
|
||||
$GetInstalledSoftwareParameters.AllUserProfiles = $True
|
||||
$GetInstalledSoftwareParameters.ContinueOnError = $False
|
||||
$GetInstalledSoftwareParameters.Verbose = $True
|
||||
|
||||
$GetInstalledSoftwareResult = Get-InstalledSoftware @GetInstalledSoftwareParameters
|
||||
|
||||
Write-Output -InputObject ($GetInstalledSoftwareResult)
|
||||
|
||||
.EXAMPLE
|
||||
$GetInstalledSoftwareParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$GetInstalledSoftwareParameters.FilterExpression = {($_.DisplayName -imatch '(^.*$)') -and ($_.DisplayName -inotmatch '(^.{0,0}$)')}
|
||||
$GetInstalledSoftwareParameters.PropertyList = New-Object -TypeName 'System.Collections.Generic.List[String]'
|
||||
$GetInstalledSoftwareParameters.PropertyList.Add('DisplayName')
|
||||
$GetInstalledSoftwareParameters.PropertyList.Add('DisplayVersion')
|
||||
$GetInstalledSoftwareParameters.PropertyList.Add('UninstallString')
|
||||
$GetInstalledSoftwareParameters.PropertyList.Add('InstallLocation')
|
||||
$GetInstalledSoftwareParameters.PropertyList.Add('Publisher')
|
||||
$GetInstalledSoftwareParameters.PropertyList.Add('InstallDate')
|
||||
$GetInstalledSoftwareParameters.ContinueOnError = $False
|
||||
$GetInstalledSoftwareParameters.Verbose = $False
|
||||
|
||||
$GetInstalledSoftwareResult = Get-InstalledSoftware @GetInstalledSoftwareParameters
|
||||
|
||||
Write-Output -InputObject ($GetInstalledSoftwareResult)
|
||||
|
||||
.EXAMPLE
|
||||
$GetInstalledSoftwareParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$GetInstalledSoftwareParameters.FilterExpression = {($_.DisplayName -imatch '(^.*$)') -and ($_.DisplayName -inotmatch '(^.{0,0}$)')}
|
||||
$GetInstalledSoftwareParameters.AllProperties = $True
|
||||
$GetInstalledSoftwareParameters.AdditionalRegistryHiveObjects = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
|
||||
|
||||
$RegistryHiveProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$RegistryHiveProperties.Add('Type', [Microsoft.Win32.RegistryHive]::Users)
|
||||
$RegistryHiveProperties.Add('KeyList', (New-Object -TypeName 'System.Collections.Generic.List[String]'))
|
||||
$RegistryHiveProperties.KeyList.Add("SID\Software\Microsoft\Windows\CurrentVersion\Uninstall")
|
||||
|
||||
Switch ([System.Environment]::Is64BitOperatingSystem)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$RegistryHiveProperties.KeyList.Add("SID\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall")
|
||||
}
|
||||
}
|
||||
|
||||
$RegistryHiveObject = New-Object -TypeName 'PSObject' -Property ($RegistryHiveProperties)
|
||||
|
||||
$GetInstalledSoftwareParameters.AdditionalRegistryHiveObjects.Add($RegistryHiveObject)
|
||||
|
||||
$GetInstalledSoftwareParameters.ContinueOnError = $False
|
||||
$GetInstalledSoftwareParameters.Verbose = $True
|
||||
|
||||
$GetInstalledSoftwareResult = Get-InstalledSoftware @GetInstalledSoftwareParameters
|
||||
|
||||
Write-Output -InputObject ($GetInstalledSoftwareResult)
|
||||
#>
|
||||
|
||||
[CmdletBinding(DefaultParameterSetName = 'PropertyList')]
|
||||
|
||||
Param
|
||||
(
|
||||
[Parameter(Mandatory=$False)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('IE')]
|
||||
[ScriptBlock]$FilterExpression,
|
||||
|
||||
[Parameter(Mandatory=$False, ParameterSetName = 'PropertyList')]
|
||||
[Alias('PL')]
|
||||
[String[]]$PropertyList,
|
||||
|
||||
[Parameter(Mandatory=$False, ParameterSetName = 'AllProperties')]
|
||||
[Alias('AP')]
|
||||
[Switch]$AllProperties,
|
||||
|
||||
[Parameter(Mandatory=$False)]
|
||||
[Alias('AUP')]
|
||||
[Switch]$AllUserProfiles,
|
||||
|
||||
[Parameter(Mandatory=$False)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('ARH')]
|
||||
[PSObject[]]$AdditionalRegistryHiveObjects,
|
||||
|
||||
[Parameter(Mandatory=$False)]
|
||||
[Alias('COE')]
|
||||
[Switch]$ContinueOnError
|
||||
)
|
||||
|
||||
Begin
|
||||
{
|
||||
Try
|
||||
{
|
||||
#Determine the date and time we executed the function
|
||||
$FunctionStartTime = (Get-Date)
|
||||
|
||||
$DateTimeLogFormat = 'dddd, MMMM dd, yyyy @ hh:mm:ss.FFF tt' ###Monday, January 01, 2019 @ 10:15:34.000 AM###
|
||||
[ScriptBlock]$GetCurrentDateTimeLogFormat = {(Get-Date).ToString($DateTimeLogFormat)}
|
||||
$DateTimeMessageFormat = 'MM/dd/yyyy HH:mm:ss.FFF' ###03/23/2022 11:12:48.347###
|
||||
[ScriptBlock]$GetCurrentDateTimeMessageFormat = {(Get-Date).ToString($DateTimeMessageFormat)}
|
||||
$DateFileFormat = 'yyyyMMdd' ###20190403###
|
||||
[ScriptBlock]$GetCurrentDateFileFormat = {(Get-Date).ToString($DateFileFormat)}
|
||||
$DateTimeFileFormat = 'yyyyMMdd_HHmmss' ###20190403_115354###
|
||||
[ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)}
|
||||
$TextInfo = (Get-Culture).TextInfo
|
||||
$LoggingDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$LoggingDetails.Add('LogMessage', $Null)
|
||||
$LoggingDetails.Add('WarningMessage', $Null)
|
||||
$LoggingDetails.Add('ErrorMessage', $Null)
|
||||
$CommonParameterList = New-Object -TypeName 'System.Collections.Generic.List[String]'
|
||||
$CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::CommonParameters)
|
||||
$CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::OptionalCommonParameters)
|
||||
$RegularExpressionTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$RegularExpressionTable.Base64 = '^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$' -As [Regex]
|
||||
$RegularExpressionTable.GUID = '(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}' -As [Regex]
|
||||
$RegexOptionList = New-Object -TypeName 'System.Collections.Generic.List[System.Text.RegularExpressions.RegexOptions[]]'
|
||||
$RegexOptionList.Add([System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
|
||||
$RegexOptionList.Add([System.Text.RegularExpressions.RegexOptions]::Multiline)
|
||||
|
||||
[ScriptBlock]$ErrorHandlingDefinition = {
|
||||
$ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$ErrorMessageList.Add('Message', $_.Exception.Message)
|
||||
$ErrorMessageList.Add('Category', $_.Exception.ErrorRecord.FullyQualifiedErrorID)
|
||||
$ErrorMessageList.Add('Script', $_.InvocationInfo.ScriptName)
|
||||
$ErrorMessageList.Add('LineNumber', $_.InvocationInfo.ScriptLineNumber)
|
||||
$ErrorMessageList.Add('LinePosition', $_.InvocationInfo.OffsetInLine)
|
||||
$ErrorMessageList.Add('Code', $_.InvocationInfo.Line.Trim())
|
||||
|
||||
ForEach ($ErrorMessage In $ErrorMessageList.GetEnumerator())
|
||||
{
|
||||
$LoggingDetails.ErrorMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - ERROR: $($ErrorMessage.Key): $($ErrorMessage.Value)"
|
||||
Write-Warning -Message ($LoggingDetails.ErrorMessage)
|
||||
}
|
||||
|
||||
Switch (($ContinueOnError.IsPresent -eq $False) -or ($ContinueOnError -eq $False))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
Throw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[String]$FunctionName = $MyInvocation.MyCommand
|
||||
[System.IO.FileInfo]$InvokingScriptPath = $MyInvocation.PSCommandPath
|
||||
[System.IO.DirectoryInfo]$InvokingScriptDirectory = $InvokingScriptPath.Directory.FullName
|
||||
[System.IO.FileInfo]$FunctionPath = "$($InvokingScriptDirectory.FullName)\Functions\$($FunctionName).ps1"
|
||||
[System.IO.DirectoryInfo]$FunctionDirectory = "$($FunctionPath.Directory.FullName)"
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is beginning. Please Wait..."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
#Define Default Action Preferences
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
[String[]]$AvailableScriptParameters = (Get-Command -Name ($FunctionName)).Parameters.GetEnumerator() | Where-Object {($_.Value.Name -inotin $CommonParameterList)} | ForEach-Object {"-$($_.Value.Name):$($_.Value.ParameterType.Name)"}
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Available Function Parameter(s) = $($AvailableScriptParameters -Join ', ')"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
[String[]]$SuppliedScriptParameters = $PSBoundParameters.GetEnumerator() | ForEach-Object {"-$($_.Key):$($_.Value.GetType().Name)"}
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Supplied Function Parameter(s) = $($SuppliedScriptParameters -Join ', ')"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($FunctionName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
#region Set Default Parameter Values
|
||||
Switch ($True)
|
||||
{
|
||||
{($Null -ieq $PropertyList) -or ($PropertyList.Count -eq 0)}
|
||||
{
|
||||
$OutputObjectValueList = New-Object -TypeName 'System.Collections.Generic.List[String]'
|
||||
$OutputObjectValueList.Add('DisplayName')
|
||||
$OutputObjectValueList.Add('DisplayVersion')
|
||||
$OutputObjectValueList.Add('UninstallString')
|
||||
$OutputObjectValueList.Add('QuietUninstallString')
|
||||
$OutputObjectValueList.Add('InstallLocation')
|
||||
$OutputObjectValueList.Add('Publisher')
|
||||
$OutputObjectValueList.Add('InstallDate')
|
||||
|
||||
[String[]]$PropertyList = $OutputObjectValueList.ToArray()
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#Create a table for the conversion of dates
|
||||
$DateTimeProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$DateTimeProperties.FormatList = New-Object -TypeName 'System.Collections.Generic.List[String]'
|
||||
$DateTimeProperties.FormatList.AddRange(([System.Globalization.DateTimeFormatInfo]::CurrentInfo.GetAllDateTimePatterns()))
|
||||
$DateTimeProperties.FormatList.AddRange(([System.Globalization.DateTimeFormatInfo]::InvariantInfo.GetAllDateTimePatterns()))
|
||||
$DateTimeProperties.FormatList.Add('yyyyMM')
|
||||
$DateTimeProperties.FormatList.Add('yyyyMMdd')
|
||||
$DateTimeProperties.Culture = $Null
|
||||
$DateTimeProperties.Styles = New-Object -TypeName 'System.Collections.Generic.List[System.Globalization.DateTimeStyles]'
|
||||
$DateTimeProperties.Styles.Add([System.Globalization.DateTimeStyles]::AssumeLocal)
|
||||
$DateTimeProperties.Styles.Add([System.Globalization.DateTimeStyles]::AllowWhiteSpaces)
|
||||
|
||||
#Create an object that will contain the functions output.
|
||||
$OutputObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$ErrorHandlingDefinition.Invoke()
|
||||
}
|
||||
Finally
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Process
|
||||
{
|
||||
Try
|
||||
{
|
||||
$RegistryHiveList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
|
||||
|
||||
$RegistryHiveProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$RegistryHiveProperties.Add('Type', [Microsoft.Win32.RegistryHive]::LocalMachine)
|
||||
$RegistryHiveProperties.Add('KeyList', (New-Object -TypeName 'System.Collections.Generic.List[String]'))
|
||||
$RegistryHiveProperties.KeyList.Add('Software\Microsoft\Windows\CurrentVersion\Uninstall')
|
||||
|
||||
Switch ([System.Environment]::Is64BitOperatingSystem)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$RegistryHiveProperties.KeyList.Add('Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall')
|
||||
}
|
||||
}
|
||||
|
||||
$RegistryHiveObject = New-Object -TypeName 'PSObject' -Property ($RegistryHiveProperties)
|
||||
|
||||
$RegistryHiveList.Add($RegistryHiveObject)
|
||||
|
||||
Switch ($AllUserProfiles.IsPresent)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$UserProfilePropertyList = New-Object -TypeName 'System.Collections.Generic.List[Object]'
|
||||
$UserProfilePropertyList.Add('LocalPath')
|
||||
$UserProfilePropertyList.Add('SID')
|
||||
$UserProfilePropertyList.Add(@{Name = 'NTAccount'; Expression = {Try {(New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' -ArgumentList @($_.SID)).Translate([System.Security.Principal.NTAccount]).Value} Catch {$Null}}})
|
||||
$UserProfilePropertyList.Add('Special')
|
||||
$UserProfilePropertyList.Add('Loaded')
|
||||
|
||||
$UserProfileList = Get-CIMInstance -Namespace 'root\CIMv2' -Class 'Win32_UserProfile' -Verbose:$False | Where-Object {($_.Special -eq $False)} | Select-Object -Property ($UserProfilePropertyList) | Where-Object {([String]::IsNullOrEmpty($_.NTAccount) -eq $False) -and ([String]::IsNullOrWhiteSpace($_.NTAccount) -eq $False)}
|
||||
|
||||
ForEach ($UserProfile In $UserProfileList)
|
||||
{
|
||||
$RegistryHiveProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$RegistryHiveProperties.Add('Type', [Microsoft.Win32.RegistryHive]::Users)
|
||||
$RegistryHiveProperties.Add('NTAccount', $UserProfile.NTAccount)
|
||||
$RegistryHiveProperties.Add('SID', $UserProfile.SID)
|
||||
$RegistryHiveProperties.Add('KeyList', (New-Object -TypeName 'System.Collections.Generic.List[String]'))
|
||||
$RegistryHiveProperties.KeyList.Add("$($RegistryHiveProperties.SID)\Software\Microsoft\Windows\CurrentVersion\Uninstall")
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to add user profile `"$($RegistryHiveProperties.NTAccount)`" [SID: $($RegistryHiveProperties.SID)] to the search for installed software. Please Wait..."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
Switch ([System.Environment]::Is64BitOperatingSystem)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$RegistryHiveProperties.KeyList.Add("$($RegistryHiveProperties.SID)\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall")
|
||||
}
|
||||
}
|
||||
|
||||
$RegistryHiveObject = New-Object -TypeName 'PSObject' -Property ($RegistryHiveProperties)
|
||||
|
||||
$RegistryHiveList.Add($RegistryHiveObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ForEach ($AdditionalRegistryHiveObject In $AdditionalRegistryHiveObjects) {$RegistryHiveList.Add($AdditionalRegistryHiveObject)}
|
||||
|
||||
For ($RegistryHiveListIndex = 0; $RegistryHiveListIndex -lt $RegistryHiveList.Count; $RegistryHiveListIndex++)
|
||||
{
|
||||
$RegistryHive = $RegistryHiveList[$RegistryHiveListIndex]
|
||||
|
||||
$RegistryHivePropertyList = $RegistryHive.PSObject.Properties
|
||||
|
||||
[Char[]]$HiveNameCharacterArray = ForEach ($Character in $RegistryHive.Type.ToString().ToCharArray())
|
||||
{
|
||||
If ([Char]::IsUpper($Character))
|
||||
{
|
||||
'_'
|
||||
}
|
||||
|
||||
$Character
|
||||
}
|
||||
|
||||
$HiveName = 'HKEY' + ($HiveNameCharacterArray -Join '').Trim().ToUpper()
|
||||
|
||||
Switch ([System.Environment]::Is64BitOperatingSystem)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
[Microsoft.Win32.RegistryView]$RegistryView = [Microsoft.Win32.RegistryView]::Registry64
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
[Microsoft.Win32.RegistryView]$RegistryView = [Microsoft.Win32.RegistryView]::Registry32
|
||||
}
|
||||
}
|
||||
|
||||
$RegistryHiveObject = [Microsoft.Win32.RegistryKey]::OpenBaseKey($RegistryHive.Type, $RegistryView)
|
||||
|
||||
For ($KeyListIndex = 0; $KeyListIndex -lt $RegistryHive.KeyList.Count; $KeyListIndex++)
|
||||
{
|
||||
$RegistryKey = $RegistryHive.KeyList[$KeyListIndex]
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to search registry key path `"$($HiveName)\$($RegistryKey)`". Please Wait..."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
$RegistryKeyObject = $RegistryHiveObject.OpenSubKey($RegistryKey)
|
||||
|
||||
Switch ($Null -ine $RegistryKeyObject)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$SubKeyNameList = $RegistryKeyObject.GetSubKeyNames() | Sort-Object
|
||||
|
||||
For ($SubKeyNameListIndex = 0; $SubKeyNameListIndex -lt $SubKeyNameList.Count; $SubKeyNameListIndex++)
|
||||
{
|
||||
Try
|
||||
{
|
||||
$SubKeyName = $SubKeyNameList[$SubKeyNameListIndex]
|
||||
|
||||
$SubKeyObject = $RegistryKeyObject.OpenSubKey($SubKeyName)
|
||||
|
||||
$SubKeyObjectSegments = $SubKeyObject.Name.Split('\')
|
||||
|
||||
$OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$OutputObjectProperties.RegistryPath = $SubKeyObject.Name
|
||||
$OutputObjectProperties.RegistryHive = $RegistryHive.Type.value__
|
||||
$OutputObjectProperties.RegistryHiveName = $HiveName
|
||||
$OutputObjectProperties.RegistryLocation = ($SubKeyObjectSegments[1..$($SubKeyObjectSegments.GetUpperBound(0))]) -Join '\'
|
||||
|
||||
ForEach ($OutputObjectValueName In $PropertyList)
|
||||
{
|
||||
$OutputObjectProperties.$($OutputObjectValueName) = $Null
|
||||
}
|
||||
|
||||
Switch ($AllProperties.IsPresent)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$ValueNameList = $SubKeyObject.GetValueNames() | Sort-Object
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
$ValueNameList = $PropertyList
|
||||
}
|
||||
}
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Now processing entry `"$($OutputObjectProperties.RegistryPath)`" [ValueCount: $($ValueNameList.Count)]. Please Wait..."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
Switch ($ValueNameList.Count -gt 0)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
For ($ValueNameListIndex = 0; $ValueNameListIndex -lt $ValueNameList.Count; $ValueNameListIndex++)
|
||||
{
|
||||
Try
|
||||
{
|
||||
$ValueName = $ValueNameList[$ValueNameListIndex]
|
||||
|
||||
$ValueKind = $SubKeyObject.GetValueKind($ValueName)
|
||||
|
||||
Switch ($ValueKind)
|
||||
{
|
||||
{($_ -ieq 'PlaceHolder')}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
$Value = $SubKeyObject.GetValue($ValueName)
|
||||
}
|
||||
}
|
||||
|
||||
$OutputObjectProperties.$($ValueName) = $Value
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$OutputObjectProperties.$($ValueName) = $Null
|
||||
}
|
||||
Finally
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$ProductCodePropertyList = New-Object -TypeName 'System.Collections.Generic.List[String]'
|
||||
$ProductCodePropertyList.Add('UninstallString')
|
||||
$ProductCodePropertyList.Add('QuietUninstallString')
|
||||
$ProductCodePropertyList.Add('ModifyPath')
|
||||
$ProductCodePropertyList.Add('RegistryLocation')
|
||||
$ProductCodePropertyList.Add('RegistryPath')
|
||||
|
||||
$OutputObjectProperties.ProductCode = $Null
|
||||
|
||||
:ProductCodePropertyLoop ForEach ($ProductCodeProperty In $ProductCodePropertyList)
|
||||
{
|
||||
$ProductCodePropertyValue = $OutputObjectProperties.$($ProductCodeProperty)
|
||||
|
||||
$ProductCodeMatch = [Regex]::Match($ProductCodePropertyValue, $RegularExpressionTable.GUID.ToString(), $RegexOptionList.ToArray())
|
||||
|
||||
Switch ($ProductCodeMatch.Success)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
Switch (([String]::IsNullOrEmpty($OutputObjectProperties.ProductCode) -eq $True) -or ([String]::IsNullOrWhiteSpace($OutputObjectProperties.ProductCode) -eq $True))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$OutputObjectProperties.ProductCode = Try {"`{$($ProductCodeMatch.Value.Trim().ToUpper() -ireplace '(\{)|(\})', '')`}"} Catch {$Null}
|
||||
|
||||
Break ProductCodePropertyLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Switch ($Null -ine $FilterExpression)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$FilterExpressionResult = [Boolean]($OutputObjectProperties | Where-Object -FilterScript $FilterExpression)
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
$FilterExpressionResult = $True
|
||||
}
|
||||
}
|
||||
|
||||
Switch ($FilterExpressionResult)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
ForEach ($OutputObjectProperty In ($OutputObjectProperties.Keys | Sort-Object))
|
||||
{
|
||||
$OutputObjectPropertyName = $OutputObjectProperty
|
||||
|
||||
$OutputObjectPropertyValue = $OutputObjectProperties.$($OutputObjectPropertyName)
|
||||
|
||||
Switch ($OutputObjectPropertyName)
|
||||
{
|
||||
{($_ -iin @('DisplayVersion'))}
|
||||
{
|
||||
$ParsedVersion = New-Object -TypeName 'System.Version'
|
||||
|
||||
$ParseVersionResult = [Version]::TryParse($OutputObjectPropertyValue, [Ref]$ParsedVersion)
|
||||
|
||||
Switch ($ParseVersionResult)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$OutputObjectPropertyValue = $ParsedVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{($_ -iin @('InstallDate'))}
|
||||
{
|
||||
$DateTime = New-Object -TypeName 'DateTime'
|
||||
|
||||
$DateTimeProperties.Input = $OutputObjectPropertyValue
|
||||
$DateTimeProperties.Successful = [DateTime]::TryParseExact($DateTimeProperties.Input, $DateTimeProperties.FormatList, $DateTimeProperties.Culture, $DateTimeProperties.Styles.ToArray(), [Ref]$DateTime)
|
||||
$DateTimeProperties.DateTime = $DateTime
|
||||
|
||||
$DateTimeObject = New-Object -TypeName 'PSObject' -Property ($DateTimeProperties)
|
||||
|
||||
Switch ($DateTimeObject.Successful)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$OutputObjectPropertyValue = $DateTimeObject.DateTime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{($_ -iin @('UninstallString'))}
|
||||
{
|
||||
Switch (([String]::IsNullOrEmpty($OutputObjectPropertyValue) -eq $True) -or ([String]::IsNullOrWhiteSpace($OutputObjectPropertyValue) -eq $True))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
Switch (([String]::IsNullOrEmpty($OutputObjectProperties.ProductCode) -eq $False) -and ([String]::IsNullOrWhiteSpace($OutputObjectProperties.ProductCode) -eq $False))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$OutputObjectPropertyValue = "msiexec.exe /x `"$($OutputObjectProperties.ProductCode)`""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{($_ -iin @('QuietUninstallString'))}
|
||||
{
|
||||
Switch (([String]::IsNullOrEmpty($OutputObjectPropertyValue) -eq $True) -or ([String]::IsNullOrWhiteSpace($OutputObjectPropertyValue) -eq $True))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
Switch (([String]::IsNullOrEmpty($OutputObjectProperties.ProductCode) -eq $False) -and ([String]::IsNullOrWhiteSpace($OutputObjectProperties.ProductCode) -eq $False))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$OutputObjectPropertyValue = "msiexec.exe /x `"$($OutputObjectProperties.ProductCode)`" /qn /norestart REBOOT=ReallySuppress /L*v `"$($Env:Windir)\Temp\$(($OutputObjectProperties.DisplayName.Split([System.IO.Path]::GetInvalidFileNameChars()) -Join '') -ireplace '(\s+)', '_')_Removal.log`""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
Switch ($OutputObjectPropertyValue)
|
||||
{
|
||||
{($_ -imatch '(^\d+$)')}
|
||||
{
|
||||
$OutputObjectPropertyValue = $OutputObjectPropertyValue -As [System.Int64]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$OutputObjectProperties.Remove($OutputObjectPropertyName)
|
||||
|
||||
$OutputObjectProperties.$($OutputObjectPropertyName) = $OutputObjectPropertyValue
|
||||
}
|
||||
|
||||
Switch (($RegistryHivePropertyList.Name -icontains 'NTAccount') -and ($RegistryHivePropertyList.Name -icontains 'SID'))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$OutputObjectProperties.ProfileNTAccount = $RegistryHive.NTAccount -As [String]
|
||||
$OutputObjectProperties.ProfileSID = $RegistryHive.SID -As [String]
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
$OutputObjectProperties.ProfileNTAccount = $Null -As [String]
|
||||
$OutputObjectProperties.ProfileSID = $Null -As [String]
|
||||
}
|
||||
}
|
||||
|
||||
$OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties)
|
||||
|
||||
$OutputObjectList.Add($OutputObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Try {$Null = $SubKeyObject.Close()} Catch {}
|
||||
}
|
||||
Catch
|
||||
{
|
||||
|
||||
}
|
||||
Finally
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Try {$Null = $RegistryKeyObject.Close()} Catch {}
|
||||
}
|
||||
|
||||
Try {$Null = $RegistryHiveObject.Close()} Catch {}
|
||||
}
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Software Detection Filter: $($FilterExpression)"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Found $($OutputObjectList.Count) installed software entries matching the specified criteria."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$ErrorHandlingDefinition.Invoke()
|
||||
}
|
||||
Finally
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
End
|
||||
{
|
||||
Try
|
||||
{
|
||||
#Determine the date and time the function completed execution
|
||||
$FunctionEndTime = (Get-Date)
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($FunctionName) ended on $($FunctionEndTime.ToString($DateTimeLogFormat))"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
#Log the total script execution time
|
||||
$FunctionExecutionTimespan = New-TimeSpan -Start ($FunctionStartTime) -End ($FunctionEndTime)
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function execution took $($FunctionExecutionTimespan.Hours.ToString()) hour(s), $($FunctionExecutionTimespan.Minutes.ToString()) minute(s), $($FunctionExecutionTimespan.Seconds.ToString()) second(s), and $($FunctionExecutionTimespan.Milliseconds.ToString()) millisecond(s)"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is completed."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$ErrorHandlingDefinition.Invoke()
|
||||
}
|
||||
Finally
|
||||
{
|
||||
$OutputObjectList = $OutputObjectList.ToArray()
|
||||
|
||||
Write-Output -InputObject ($OutputObjectList)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -0,0 +1,105 @@
|
||||
Function Get-MSIPropertyList
|
||||
{
|
||||
[CmdletBinding()]
|
||||
Param
|
||||
(
|
||||
[Parameter(Mandatory=$True)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ValidateScript({(Test-Path -Path $_)})]
|
||||
[System.IO.FileInfo[]]$Path
|
||||
)
|
||||
|
||||
Begin
|
||||
{
|
||||
$OutputObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
|
||||
}
|
||||
|
||||
Process
|
||||
{
|
||||
Try
|
||||
{
|
||||
ForEach ($Item In $Path)
|
||||
{
|
||||
$ComObject = New-Object -ComObject 'WindowsInstaller.Installer'
|
||||
|
||||
$MSIDatabase = $ComObject.GetType().InvokeMember('OpenDatabase', 'InvokeMethod', $Null, $ComObject, @($Item.FullName, 0))
|
||||
|
||||
[String]$Query = 'SELECT * FROM Property'
|
||||
|
||||
$View = $MSIDatabase.GetType().InvokeMember('OpenView', 'InvokeMethod', $Null, $MSIDatabase, $Query)
|
||||
$View.GetType().InvokeMember('Execute', 'InvokeMethod', $Null, $View, $Null)
|
||||
|
||||
$OutputObjectProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$OutputObjectProperties.Add('Path', $Item)
|
||||
|
||||
While ($Record = $View.GetType().InvokeMember('Fetch', 'InvokeMethod', $Null, $View, $Null))
|
||||
{
|
||||
Switch ($Null -ine $Record)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
[String]$MSIPropertyName = $Record.GetType().InvokeMember('StringData', 'GetProperty', $Null, $Record, 1)
|
||||
[String]$MSIPropertyValue = $Record.GetType().InvokeMember('StringData', 'GetProperty', $Null, $Record, 2)
|
||||
|
||||
Switch ($OutputObjectProperties.Contains($MSIPropertyName))
|
||||
{
|
||||
{($_ -eq $False)}
|
||||
{
|
||||
$OutputObjectProperties.Add($MSIPropertyName, $MSIPropertyValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$OutputObject = New-Object -TypeName 'PSObject' -Property ($OutputObjectProperties)
|
||||
|
||||
$OutputObjectList.Add($OutputObject)
|
||||
|
||||
$Null = [System.Runtime.InteropServices.Marshal]::ReleaseComObject($MSIDatabase)
|
||||
|
||||
$Null = [System.Runtime.InteropServices.Marshal]::ReleaseComObject($ComObject)
|
||||
|
||||
$Null = [System.GC]::Collect()
|
||||
|
||||
$Null = [System.GC]::WaitForPendingFinalizers()
|
||||
}
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$ErrorMessageList.Add('ErrorMessage', $_.Exception.Message)
|
||||
$ErrorMessageList.Add('Command', $_.InvocationInfo.MyCommand.Name)
|
||||
$ErrorMessageList.Add('LineNumber', $_.InvocationInfo.ScriptLineNumber)
|
||||
$ErrorMessageList.Add('LinePosition', $_.InvocationInfo.OffsetInLine)
|
||||
$ErrorMessageList.Add('Code', $_.InvocationInfo.Line.Trim())
|
||||
|
||||
ForEach ($ErrorMessage In $ErrorMessageList.GetEnumerator())
|
||||
{
|
||||
$ErrorMessage = "$($ErrorMessage.Key): $($ErrorMessage.Value)"
|
||||
Write-Warning -Message ($ErrorMessage) -Verbose
|
||||
}
|
||||
}
|
||||
Finally
|
||||
{
|
||||
Try
|
||||
{
|
||||
$Null = $View.Close()
|
||||
$Null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($View)
|
||||
$Null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($MSIDatabase)
|
||||
$Null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ComObject)
|
||||
}
|
||||
Catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
End
|
||||
{
|
||||
$OutputObjectList = $OutputObjectList.ToArray()
|
||||
|
||||
Write-Output -InputObject ($OutputObjectList)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,390 @@
|
||||
## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx
|
||||
|
||||
#region Function Get-NetworkInterfaceList
|
||||
Function Get-NetworkInterfaceList
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Returns a list of the network interface(s) available on the device this function is being executed on.
|
||||
|
||||
.DESCRIPTION
|
||||
Slightly more detailed description of what your function does
|
||||
|
||||
.PARAMETER InterfaceTypeExpression
|
||||
A valid regular expression that will allow for filtering the available network interface(s) based on their interface type.
|
||||
|
||||
.PARAMETER OperationalStatusExpression
|
||||
A valid regular expression that will allow for filtering the available network interface(s) based on their operational status.
|
||||
|
||||
.EXAMPLE
|
||||
Get-NetworkInterfaceList
|
||||
|
||||
.EXAMPLE
|
||||
$GetNetworkInterfaceListParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$GetNetworkInterfaceListParameters.InterfaceTypeExpression = "(.*Ethernet.*)|(.*Wireless.*)"
|
||||
$GetNetworkInterfaceListParameters.OperationalStatusExpression = "(^Up$)"
|
||||
$GetNetworkInterfaceListParameters.ContinueOnError = $False
|
||||
$GetNetworkInterfaceListParameters.Verbose = $True
|
||||
$GetNetworkInterfaceListParameters.ErrorAction = [System.Management.Automation.Actionpreference]::Stop
|
||||
|
||||
$GetNetworkInterfaceListResult = Get-NetworkInterfaceList @GetNetworkInterfaceListParameters
|
||||
|
||||
Write-Output -InputObject ($GetNetworkInterfaceListResult)
|
||||
|
||||
.NOTES
|
||||
Get Network Interface Types - '@(' + (([System.Enum]::GetNames('System.Net.NetworkInformation.NetworkInterfaceType') | Sort-Object | ForEach-Object {"'$($_)'"}) -Join ', ') + ')'
|
||||
|
||||
Network Interface Type List - 'AsymmetricDsl', 'Atm', 'BasicIsdn', 'Ethernet', 'Ethernet3Megabit', 'FastEthernetFx', 'FastEthernetT', 'Fddi', 'GenericModem', 'GigabitEthernet', 'HighPerformanceSerialBus', 'IPOverAtm', 'Isdn', 'Loopback', 'MultiRateSymmetricDsl', 'Ppp', 'PrimaryIsdn', 'RateAdaptDsl', 'Slip', 'SymmetricDsl', 'TokenRing', 'Tunnel', 'Unknown', 'VeryHighSpeedDsl', 'Wireless80211', 'Wman', 'Wwanpp', 'Wwanpp2'
|
||||
|
||||
Get Operational Status List - '@(' + (([System.Enum]::GetNames('System.Net.NetworkInformation.OperationalStatus') | Sort-Object | ForEach-Object {"'$($_)'"}) -Join ', ') + ')'
|
||||
|
||||
Operational Status List - 'Dormant', 'Down', 'LowerLayerDown', 'NotPresent', 'Testing', 'Unknown', 'Up'
|
||||
|
||||
.LINK
|
||||
https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation
|
||||
#>
|
||||
|
||||
[CmdletBinding(ConfirmImpact = 'Low', DefaultParameterSetName = '__AllParameterSets', HelpURI = 'https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation', PositionalBinding = $True)]
|
||||
|
||||
Param
|
||||
(
|
||||
[Parameter(Mandatory=$False)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Regex]$InterfaceTypeExpression,
|
||||
|
||||
[Parameter(Mandatory=$False)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Regex]$OperationalStatusExpression,
|
||||
|
||||
[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]$InvokingScriptPath = $MyInvocation.PSCommandPath
|
||||
[System.IO.DirectoryInfo]$InvokingScriptDirectory = $InvokingScriptPath.Directory.FullName
|
||||
[System.IO.FileInfo]$FunctionPath = "$($InvokingScriptDirectory.FullName)\Functions\$($FunctionName).ps1"
|
||||
[System.IO.DirectoryInfo]$FunctionDirectory = "$($FunctionPath.Directory.FullName)"
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is beginning. Please Wait..."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
#Define Default Action Preferences
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
[String[]]$AvailableScriptParameters = (Get-Command -Name ($FunctionName)).Parameters.GetEnumerator() | Where-Object {($_.Value.Name -inotin $CommonParameterList)} | ForEach-Object {"-$($_.Value.Name):$($_.Value.ParameterType.Name)"}
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Available Function Parameter(s) = $($AvailableScriptParameters -Join ', ')"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
[String[]]$SuppliedScriptParameters = $PSBoundParameters.GetEnumerator() | ForEach-Object {"-$($_.Key):$($_.Value.GetType().Name)"}
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Supplied Function Parameter(s) = $($SuppliedScriptParameters -Join ', ')"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($FunctionName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
#Create an object that will contain the functions output.
|
||||
$OutputObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
|
||||
|
||||
#Set default parameter value(s)
|
||||
Switch ($True)
|
||||
{
|
||||
{([String]::IsNullOrEmpty($InterfaceTypeExpression) -eq $True) -or ([String]::IsNullOrWhiteSpace($InterfaceTypeExpression) -eq $True)}
|
||||
{
|
||||
[Regex]$InterfaceTypeExpression = '(.*)'
|
||||
}
|
||||
|
||||
{([String]::IsNullOrEmpty($OperationalStatusExpression) -eq $True) -or ([String]::IsNullOrWhiteSpace($OperationalStatusExpression) -eq $True)}
|
||||
{
|
||||
[Regex]$OperationalStatusExpression = '(.*)'
|
||||
}
|
||||
}
|
||||
|
||||
#Define additional variables
|
||||
$AddressFamilyTable = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$AddressFamilyTable.IPv4 = New-Object -TypeName 'System.Collections.Generic.List[String]'
|
||||
$AddressFamilyTable.IPv4.Add('InterNetwork')
|
||||
$AddressFamilyTable.IPv6 = New-Object -TypeName 'System.Collections.Generic.List[String]'
|
||||
$AddressFamilyTable.IPv6.Add('InterNetworkV6')
|
||||
|
||||
$NetworkAdapterConfigurationClass = Get-CIMInstance -Namespace 'Root\CIMv2' -ClassName 'Win32_NetworkAdapterConfiguration' -Property @('*')
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$ErrorHandlingDefinition.Invoke()
|
||||
}
|
||||
Finally
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Process
|
||||
{
|
||||
Try
|
||||
{
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to get the list of available network adapter(s). Please Wait..."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage)
|
||||
|
||||
#region Network Adapter Information
|
||||
Switch ([System.Net.NetworkInformation.NetworkInterface]::GetIsNetworkAvailable())
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$LogMessage = "Attempting to enumerate network interface(s). Please Wait..."
|
||||
Write-Verbose -Message "$($LogMessage)"
|
||||
|
||||
$NetworkInterfaces = [System.Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces() | Where-Object {($_.NetworkInterfaceType -imatch $InterfaceTypeExpression) -and ($_.OperationalStatus -imatch $OperationalStatusExpression)}
|
||||
|
||||
$NetworkInterfacesCount = ($NetworkInterfaces | Measure-Object).Count
|
||||
|
||||
$LogMessage = "Found $($NetworkInterfacesCount) available network interface(s) with an interface type matching `"$($InterfaceTypeExpression)`" and an operational status matching `"$($OperationalStatusExpression)`"."
|
||||
Write-Verbose -Message "$($LogMessage)"
|
||||
|
||||
:NetworkInterfaceLoop ForEach ($NetworkInterface In $NetworkInterfaces)
|
||||
{
|
||||
$NetworkInterfaceProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary'
|
||||
$NetworkInterfaceProperties.InterfaceName = $Null
|
||||
$NetworkInterfaceProperties.Type = $Null
|
||||
$NetworkInterfaceProperties.Status = $Null
|
||||
$NetworkInterfaceProperties.Speed = 0
|
||||
$NetworkInterfaceProperties.MACAddress = $Null
|
||||
$NetworkInterfaceProperties.IPv4DHCPServer = $Null
|
||||
$NetworkInterfaceProperties.IPv4Address = $Null
|
||||
$NetworkInterfaceProperties.IPv4Gateway = $Null
|
||||
$NetworkInterfaceProperties.IPv4SubnetMask = $Null
|
||||
$NetworkInterfaceProperties.IPv4PrefixLength = 0
|
||||
$NetworkInterfaceProperties.IPv4DNSServers = New-Object -TypeName 'System.Collections.Generic.List[String]'
|
||||
$NetworkInterfaceProperties.IPv6Address = $Null
|
||||
$NetworkInterfaceProperties.DNSEnabled = $Null
|
||||
$NetworkInterfaceProperties.DynamicDNSEnabled = $Null
|
||||
$NetworkInterfaceProperties.DNSSuffix = $Null
|
||||
$NetworkInterfaceProperties.Description = $Null
|
||||
$NetworkInterfaceProperties.DNSServerSearchOrder = New-Object -TypeName 'System.Collections.Generic.List[String]'
|
||||
$NetworkInterfaceProperties.DNSDomainSuffixSearchOrder = New-Object -TypeName 'System.Collections.Generic.List[String]'
|
||||
$NetworkInterfaceProperties.ID = $Null
|
||||
|
||||
$NetworkInterfaceProperties.InterfaceName = $NetworkInterface.Name
|
||||
$NetworkInterfaceProperties.Description = $NetworkInterface.Description
|
||||
$NetworkInterfaceProperties.Type = $NetworkInterface.NetworkInterfaceType -As [String]
|
||||
$NetworkInterfaceProperties.Status = $NetworkInterface.OperationalStatus -As [String]
|
||||
$NetworkInterfaceProperties.Speed = Try {($NetworkInterface.Speed / 1000000) -As [Int]} Catch {0 -As [Int]}
|
||||
$NetworkInterfaceProperties.ID = $NetworkInterface.ID
|
||||
|
||||
$NetworkInterfaceMACAddress = If ($NetworkInterface.GetPhysicalAddress() -imatch '.*\:.*') {$NetworkInterface.GetPhysicalAddress()} Else {($NetworkInterface.GetPhysicalAddress() -ireplace '([a-zA-Z0-9]{2,2})', '$1:').TrimEnd(':').ToUpper()}
|
||||
|
||||
$NetworkInterfaceProperties.MACAddress = $NetworkInterfaceMACAddress
|
||||
|
||||
$NetworkInterfaceIPProperties = $NetworkInterface.GetIPProperties()
|
||||
|
||||
$NetworkInterfaceProperties.DNSEnabled = $NetworkInterfaceIPProperties.IsDnsEnabled
|
||||
$NetworkInterfaceProperties.DynamicDNSEnabled = $NetworkInterfaceIPProperties.IsDynamicDnsEnabled
|
||||
$NetworkInterfaceProperties.DNSSuffix = $NetworkInterfaceIPProperties.DnsSuffix
|
||||
|
||||
$NetworkInterfaceConfiguration = $NetworkAdapterConfigurationClass | Where-Object {($_.SettingID -ieq $NetworkInterface.ID)}
|
||||
|
||||
Switch ($Null -ine $NetworkInterfaceConfiguration)
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
$NetworkInterfaceProperties.DNSServerSearchOrder = $NetworkInterfaceConfiguration.DNSServerSearchOrder
|
||||
$NetworkInterfaceProperties.DNSDomainSuffixSearchOrder = $NetworkInterfaceConfiguration.DNSDomainSuffixSearchOrder
|
||||
}
|
||||
}
|
||||
|
||||
ForEach ($UnicastAddress In $NetworkInterfaceIPProperties.UnicastAddresses)
|
||||
{
|
||||
Switch (([String]::IsNullOrEmpty($UnicastAddress.Address) -eq $False) -and ([String]::IsNullOrWhiteSpace($UnicastAddress.Address) -eq $False))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
Switch ($UnicastAddress.Address.AddressFamily)
|
||||
{
|
||||
{($_ -iin $AddressFamilyTable.IPv4)}
|
||||
{
|
||||
$NetworkInterfaceProperties.IPv4Address = $UnicastAddress.Address.IPAddressToString -As [String]
|
||||
$NetworkInterfaceProperties.IPv4SubnetMask = $UnicastAddress.IPv4Mask -As [String]
|
||||
$NetworkInterfaceProperties.IPv4PrefixLength = $UnicastAddress.PrefixLength
|
||||
}
|
||||
|
||||
{($_ -iin $AddressFamilyTable.IPv6)}
|
||||
{
|
||||
$NetworkInterfaceProperties.IPv6Address = $UnicastAddress.Address.IPAddressToString.ToUpper()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ForEach ($GatewayAddress In $NetworkInterfaceIPProperties.GatewayAddresses)
|
||||
{
|
||||
Switch (([String]::IsNullOrEmpty($GatewayAddress.Address.Address) -eq $False) -and ([String]::IsNullOrWhiteSpace($GatewayAddress.Address.Address) -eq $False))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
Switch ($GatewayAddress.Address.AddressFamily)
|
||||
{
|
||||
{($_ -iin $AddressFamilyTable.IPv4)}
|
||||
{
|
||||
$NetworkInterfaceProperties.IPv4Gateway = $GatewayAddress.Address.IPAddressToString.ToString()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ForEach ($DHCPServerAddress In $NetworkInterfaceIPProperties.DhcpServerAddresses)
|
||||
{
|
||||
Switch (([String]::IsNullOrEmpty($DHCPServerAddress.Address) -eq $False) -and ([String]::IsNullOrWhiteSpace($DHCPServerAddress.Address) -eq $False))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
Switch ($DHCPServerAddress.AddressFamily)
|
||||
{
|
||||
{($_ -iin $AddressFamilyTable.IPv4)}
|
||||
{
|
||||
$NetworkInterfaceProperties.IPv4DHCPServer = $DHCPServerAddress.IPAddressToString.ToString()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ForEach ($DNSAddress In $NetworkInterfaceIPProperties.DnsAddresses)
|
||||
{
|
||||
Switch (([String]::IsNullOrEmpty($DNSAddress.Address) -eq $False) -and ([String]::IsNullOrWhiteSpace($DNSAddress.Address) -eq $False))
|
||||
{
|
||||
{($_ -eq $True)}
|
||||
{
|
||||
Switch ($DNSAddress.AddressFamily)
|
||||
{
|
||||
{($_ -iin $AddressFamilyTable.IPv4)}
|
||||
{
|
||||
$NetworkInterfaceProperties.IPv4DNSServers.Add($DNSAddress.ToString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$NetworkInterfaceObject = New-Object -TypeName 'PSObject' -Property ($NetworkInterfaceProperties)
|
||||
|
||||
$OutputObjectList.Add($NetworkInterfaceObject)
|
||||
}
|
||||
|
||||
For ($NetworkInterfaceObjectListIndex = 0; $NetworkInterfaceObjectListIndex -lt $OutputObjectList.Count; $NetworkInterfaceObjectListIndex++)
|
||||
{
|
||||
$NetworkInterfaceItem = $OutputObjectList[$NetworkInterfaceObjectListIndex]
|
||||
|
||||
$NetworkInterfaceNumber = ($NetworkInterfaceObjectListIndex + 1).ToString('00')
|
||||
|
||||
$NetworkInterfacePropertyList = New-Object -TypeName 'System.Collections.Generic.List[String]'
|
||||
|
||||
$Null = $NetworkInterfaceItem.PSObject.Properties | ForEach-Object {$NetworkInterfacePropertyList.Add("[$($_.Name): $($_.Value -Join ', ')]")}
|
||||
|
||||
$LogMessage = "Network Interface #$($NetworkInterfaceNumber) - $($NetworkInterfacePropertyList -Join ' ')"
|
||||
Write-Verbose -Message "$($LogMessage)"
|
||||
}
|
||||
}
|
||||
|
||||
{($_ -eq $False)}
|
||||
{
|
||||
$WarningMessage = "There are no available network connections!"
|
||||
Write-Warning -Message "$($WarningMessage)"
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$ErrorHandlingDefinition.Invoke()
|
||||
}
|
||||
Finally
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
End
|
||||
{
|
||||
Try
|
||||
{
|
||||
#Determine the date and time the function completed execution
|
||||
$FunctionEndTime = (Get-Date)
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($FunctionName) ended on $($FunctionEndTime.ToString($DateTimeLogFormat))"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
#Log the total script execution time
|
||||
$FunctionExecutionTimespan = New-TimeSpan -Start ($FunctionStartTime) -End ($FunctionEndTime)
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function execution took $($FunctionExecutionTimespan.Hours.ToString()) hour(s), $($FunctionExecutionTimespan.Minutes.ToString()) minute(s), $($FunctionExecutionTimespan.Seconds.ToString()) second(s), and $($FunctionExecutionTimespan.Milliseconds.ToString()) millisecond(s)"
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
|
||||
$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is completed."
|
||||
Write-Verbose -Message ($LoggingDetails.LogMessage) -Verbose
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$ErrorHandlingDefinition.Invoke()
|
||||
}
|
||||
Finally
|
||||
{
|
||||
#Write the object to the powershell pipeline
|
||||
$OutputObjectList = $OutputObjectList.ToArray()
|
||||
|
||||
Write-Output -InputObject ($OutputObjectList | Sort-Object -Property @('Status'))
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
Reference in New Issue
Block a user