navcontainerhelper/AppHandling/Sign-NavContainerApp.ps1

189 строки
9.0 KiB
PowerShell

<#
.Synopsis
Uses a NAV/BC Container to sign an App
.Description
appFile must be shared with the container
Copies the pfxFile to the container if necessary
Creates a session to the container and Signs the App using the provided certificate and password
.Parameter containerName
Name of the container in which you want to publish an app
.Parameter appFile
Path of the app you want to sign
.Parameter pfxFile
Path/Url of the certificate pfx file to use for signing
.Parameter pfxPassword
Password of the certificate pfx file
.Parameter timeStampServer
Specifies the URL of the time stamp server. Default is $bcContainerHelperConfig.timeStampServer, which defaults to http://timestamp.verisign.com/scripts/timestamp.dll
.Example
Sign-BcContainerApp -appFile c:\programdata\bccontainerhelper\myapp.app -pfxFile http://my.secure.url/mycert.pfx -pfxPassword $securePassword
.Example
Sign-BcContainerApp -appFile c:\programdata\bccontainerhelper\myapp.app -pfxFile c:\programdata\bccontainerhelper\mycert.pfx -pfxPassword $securePassword
#>
function Sign-BcContainerApp {
Param (
[string] $containerName = $bcContainerHelperConfig.defaultContainerName,
[Parameter(Mandatory=$true)]
[string] $appFile,
[Parameter(Mandatory=$true)]
[string] $pfxFile,
[Parameter(Mandatory=$true)]
[SecureString] $pfxPassword,
[Parameter(Mandatory=$false)]
[string] $timeStampServer = $bcContainerHelperConfig.timeStampServer,
[Parameter(Mandatory=$false)]
[string] $digestAlgorithm = $bcContainerHelperConfig.digestAlgorithm,
[switch] $importCertificate
)
$telemetryScope = InitTelemetryScope -name $MyInvocation.InvocationName -parameterValues $PSBoundParameters -includeParameters @()
try {
$containerAppFile = Get-BcContainerPath -containerName $containerName -path $appFile
if ("$containerAppFile" -eq "") {
throw "The app ($appFile)needs to be in a folder, which is shared with the container $containerName"
}
$sharedPfxFile = Join-Path $bcContainerHelperConfig.hostHelperFolder "Extensions\$containerName\my\$([GUID]::NewGuid().ToString()).pfx"
$removeSharedPfxFile = $true
if ($pfxFile -like "https://*" -or $pfxFile -like "http://*") {
Write-Host "Downloading certificate file to container"
Download-File -sourceUrl $pfxFile -destinationFile $sharedPfxFile
}
else {
if (Get-BcContainerPath -containerName $containerName -path $pfxFile) {
$sharedPfxFile = $pfxFile
$removeSharedPfxFile = $false
}
else {
Write-Host "Copying certificate file to container"
Copy-Item -Path $pfxFile -Destination $sharedPfxFile -Force
}
}
try {
TestPfxCertificate -pfxFile $sharedPfxFile -pfxPassword $pfxPassword -certkind "Codesign"
Invoke-ScriptInBcContainer -containerName $containerName -ScriptBlock { Param($appFile, $pfxFile, $pfxPassword, $timeStampServer, $digestAlgorithm, $importCertificate)
function GetExtendedErrorMessage {
Param(
$errorRecord
)
$exception = $errorRecord.Exception
$message = $exception.Message
try {
$errorDetails = $errorRecord.ErrorDetails | ConvertFrom-Json
$message += " $($errorDetails.error)`r`n$($errorDetails.error_description)"
}
catch {}
try {
if ($exception -is [System.Management.Automation.MethodInvocationException]) {
$exception = $exception.InnerException
}
$webException = [System.Net.WebException]$exception
$webResponse = $webException.Response
try {
if ($webResponse.StatusDescription) {
$message += "`r`n$($webResponse.StatusDescription)"
}
} catch {}
$reqstream = $webResponse.GetResponseStream()
$sr = new-object System.IO.StreamReader $reqstream
$result = $sr.ReadToEnd()
try {
$json = $result | ConvertFrom-Json
$message += "`r`n$($json.Message)"
}
catch {
$message += "`r`n$result"
}
try {
$correlationX = $webResponse.GetResponseHeader('ms-correlation-x')
if ($correlationX) {
$message += " (ms-correlation-x = $correlationX)"
}
}
catch {}
}
catch{}
$message
}
if ($importCertificate) {
Import-PfxCertificate -FilePath $pfxFile -Password $pfxPassword -CertStoreLocation "cert:\localMachine\root" | Out-Null
Import-PfxCertificate -FilePath $pfxFile -Password $pfxPassword -CertStoreLocation "cert:\localMachine\my" | Out-Null
}
if (!(Test-Path "C:\Windows\System32\msvcr120.dll")) {
Write-Host "Downloading vcredist_x86"
(New-Object System.Net.WebClient).DownloadFile('https://bcartifacts.azureedge.net/prerequisites/vcredist_x86.exe','c:\run\install\vcredist_x86.exe')
Write-Host "Installing vcredist_x86"
start-process -Wait -FilePath c:\run\install\vcredist_x86.exe -ArgumentList /q, /norestart
Write-Host "Downloading vcredist_x64"
(New-Object System.Net.WebClient).DownloadFile('https://bcartifacts.azureedge.net/prerequisites/vcredist_x64.exe','c:\run\install\vcredist_x64.exe')
Write-Host "Installing vcredist_x64"
start-process -Wait -FilePath c:\run\install\vcredist_x64.exe -ArgumentList /q, /norestart
}
if (Test-Path "C:\Program Files (x86)\Windows Kits\10\bin\*\x64\SignTool.exe") {
$signToolExe = (get-item "C:\Program Files (x86)\Windows Kits\10\bin\*\x64\SignTool.exe").FullName
} else {
Write-Host "Downloading Signing Tools"
$winSdkSetupExe = "c:\run\install\winsdksetup.exe"
$winSdkSetupUrl = "https://bcartifacts.azureedge.net/prerequisites/winsdksetup.exe"
(New-Object System.Net.WebClient).DownloadFile($winSdkSetupUrl,$winSdkSetupExe)
Write-Host "Installing Signing Tools"
Start-Process $winSdkSetupExe -ArgumentList "/features OptionId.SigningTools /q" -Wait
if (!(Test-Path "C:\Program Files (x86)\Windows Kits\10\bin\*\x64\SignTool.exe")) {
throw "Cannot locate signtool.exe after installation"
}
$signToolExe = (get-item "C:\Program Files (x86)\Windows Kits\10\bin\*\x64\SignTool.exe").FullName
}
Write-Host "Signing $appFile"
$unsecurepassword = ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pfxPassword)))
$attempt = 1
$maxAttempts = 5
do {
try {
if ($digestAlgorithm) {
& "$signtoolexe" @("sign", "/f", "$pfxFile", "/p","$unsecurepassword", "/fd", $digestAlgorithm, "/td", $digestAlgorithm, "/tr", "$timeStampServer", "$appFile") | Write-Host
}
else {
& "$signtoolexe" @("sign", "/f", "$pfxFile", "/p","$unsecurepassword", "/t", "$timeStampServer", "$appFile") | Write-Host
}
break
} catch {
if ($attempt -ge $maxAttempts) {
throw
}
else {
$seconds = [Math]::Pow(4,$attempt)
Write-Host "Signing failed, retrying in $seconds seconds"
$attempt++
Start-Sleep -Seconds $seconds
}
}
} while ($attempt -le $maxAttempts)
} -ArgumentList $containerAppFile, (Get-BcContainerPath -containerName $containerName -path $sharedPfxFile), $pfxPassword, $timeStampServer, $digestAlgorithm, $importCertificate
}
finally {
if ($removeSharedPfxFile -and (Test-Path $sharedPfxFile)) {
Remove-Item -Path $sharedPfxFile -Force
}
}
}
catch {
TrackException -telemetryScope $telemetryScope -errorRecord $_
throw
}
finally {
TrackTrace -telemetryScope $telemetryScope
}
}
Set-Alias -Name Sign-NavContainerApp -Value Sign-BcContainerApp
Export-ModuleMember -Function Sign-BcContainerApp -Alias Sign-NavContainerApp