@@ -2997,6 +2997,11 @@ private bool FindSignToolExe()
29972997 #endregion
29982998
29992999 private void buttonExportAsScript_Click ( object sender , EventArgs e )
3000+ {
3001+ ExportCommandScript ( ) ;
3002+ }
3003+
3004+ private void ExportCommandScript ( )
30003005 {
30013006 try
30023007 {
@@ -3007,7 +3012,8 @@ private void buttonExportAsScript_Click(object sender, EventArgs e)
30073012 foreach ( var item in checkedListBoxFiles . CheckedItems )
30083013 {
30093014 var s = item ? . ToString ( ) ?? string . Empty ;
3010- var cleaned = System . Text . RegularExpressions . Regex . Replace ( s , @"\s*\[(Valid|Invalid)\]" , "" , System . Text . RegularExpressions . RegexOptions . IgnoreCase ) ;
3015+ var cleaned = System . Text . RegularExpressions . Regex . Replace (
3016+ s , @"\s*\[(Valid|Invalid)\]" , "" , System . Text . RegularExpressions . RegexOptions . IgnoreCase ) ;
30113017 files . Add ( cleaned ) ;
30123018 }
30133019 }
@@ -3016,14 +3022,16 @@ private void buttonExportAsScript_Click(object sender, EventArgs e)
30163022 foreach ( var item in checkedListBoxFiles . Items )
30173023 {
30183024 var s = item ? . ToString ( ) ?? string . Empty ;
3019- var cleaned = System . Text . RegularExpressions . Regex . Replace ( s , @"\s*\[(Valid|Invalid)\]" , "" , System . Text . RegularExpressions . RegexOptions . IgnoreCase ) ;
3025+ var cleaned = System . Text . RegularExpressions . Regex . Replace (
3026+ s , @"\s*\[(Valid|Invalid)\]" , "" , System . Text . RegularExpressions . RegexOptions . IgnoreCase ) ;
30203027 files . Add ( cleaned ) ;
30213028 }
30223029 }
30233030
30243031 if ( files . Count == 0 )
30253032 {
3026- MessageBox . Show ( "No files available to export." , "Export Command Script" , MessageBoxButtons . OK , MessageBoxIcon . Information ) ;
3033+ MessageBox . Show ( "No files available to export." , "Export Command Script" ,
3034+ MessageBoxButtons . OK , MessageBoxIcon . Information ) ;
30273035 return ;
30283036 }
30293037
@@ -3044,10 +3052,12 @@ private void buttonExportAsScript_Click(object sender, EventArgs e)
30443052 sb . AppendLine ( ) ;
30453053
30463054 // Base vars
3047- var signToolFullPath = Path . GetFullPath ( textBoxSignToolPath . Text ) ;
3055+ var signToolFullPath = Path . GetFullPath ( textBoxSignToolPath . Text ?? string . Empty ) ;
30483056 sb . AppendLine ( "$SignTool = '" + EscapePS ( signToolFullPath ) + "'" ) ;
30493057 sb . AppendLine ( "$VerboseSwitch = " + ( menuItemSignVerbose . Checked ? "$true" : "$false" ) ) ;
30503058 sb . AppendLine ( "$DebugSwitch = " + ( menuItemSignDebug . Checked ? "$true" : "$false" ) ) ;
3059+ // Optional: toggle batch mode from a checkbox if you add one (e.g., checkBoxBatchMode.Checked). Default false.
3060+ sb . AppendLine ( "$BatchMode = $false" ) ;
30513061 if ( ! radioButtonTrustedSigning . Checked )
30523062 {
30533063 // Only used by Windows Store and PFX modes
@@ -3084,13 +3094,25 @@ private void buttonExportAsScript_Click(object sender, EventArgs e)
30843094 sb . AppendLine ( "# Windows Certificate Store signing" ) ;
30853095 sb . AppendLine ( "$Thumbprint = '" + EscapePS ( thumbprint ?? string . Empty ) + "'" ) ;
30863096 sb . AppendLine ( ) ;
3087- sb . AppendLine ( "foreach ($f in $files) {" ) ;
3097+
3098+ // Pre-flight + file normalization
3099+ sb . AppendLine ( "if (!(Test-Path -LiteralPath $SignTool)) { throw \" SignTool not found: $SignTool\" }" ) ;
3100+ sb . AppendLine ( "$targetFiles = @()" ) ;
3101+ sb . AppendLine ( "foreach ($f in $files) { if (Test-Path -LiteralPath $f) { $targetFiles += (Resolve-Path -LiteralPath $f).Path } else { Write-Warning \" File not found, skipping: $f\" } }" ) ;
3102+ sb . AppendLine ( "if ($targetFiles.Count -eq 0) { throw 'No input files to sign.' }" ) ;
3103+ sb . AppendLine ( "$failures = @()" ) ;
3104+ sb . AppendLine ( ) ;
3105+
3106+ // Per-file signing with exit code checks
3107+ sb . AppendLine ( "foreach ($f in $targetFiles) {" ) ;
30883108 sb . AppendLine ( " $sigArgs = @('sign')" ) ;
30893109 sb . AppendLine ( " Add-GlobalSwitches ([ref]$sigArgs)" ) ;
30903110 sb . AppendLine ( " if ($UseTimestamp -and $TimestampUrl) { $sigArgs += '/fd'; $sigArgs += 'sha256'; $sigArgs += '/tr'; $sigArgs += $TimestampUrl; $sigArgs += '/td'; $sigArgs += 'sha256' } else { $sigArgs += '/fd'; $sigArgs += 'sha256' }" ) ;
30913111 sb . AppendLine ( " $sigArgs += '/sha1'; $sigArgs += $Thumbprint; $sigArgs += $f" ) ;
30923112 sb . AppendLine ( " & $SignTool @sigArgs" ) ;
3113+ sb . AppendLine ( " if ($LASTEXITCODE -ne 0) { Write-Warning \" Signing failed (exit $LASTEXITCODE): $f\" ; $failures += $f } else { Write-Host \" Signed: $f\" }" ) ;
30933114 sb . AppendLine ( "}" ) ;
3115+ sb . AppendLine ( "if ($failures.Count -gt 0) { throw (\" One or more files failed to sign:`n - \" + ($failures -join \" `n - \" )) }" ) ;
30943116 }
30953117 else if ( radioButtonPFXCertificate . Checked )
30963118 {
@@ -3103,13 +3125,28 @@ private void buttonExportAsScript_Click(object sender, EventArgs e)
31033125 sb . AppendLine ( "$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)" ) ;
31043126 sb . AppendLine ( "try { $PfxPassword = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) } finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) }" ) ;
31053127 sb . AppendLine ( ) ;
3106- sb . AppendLine ( "foreach ($f in $files) {" ) ;
3107- sb . AppendLine ( " $sigArgs = @('sign')" ) ;
3108- sb . AppendLine ( " Add-GlobalSwitches ([ref]$sigArgs)" ) ;
3109- sb . AppendLine ( " if ($UseTimestamp -and $TimestampUrl) { $sigArgs += '/fd'; $sigArgs += 'sha256'; $sigArgs += '/tr'; $sigArgs += $TimestampUrl; $sigArgs += '/td'; $sigArgs += 'sha256' } else { $sigArgs += '/fd'; $sigArgs += 'sha256' }" ) ;
3110- sb . AppendLine ( " $sigArgs += '/f'; $sigArgs += $PfxPath; $sigArgs += '/p'; $sigArgs += $PfxPassword; $sigArgs += '/a'; $sigArgs += $f" ) ;
3111- sb . AppendLine ( " & $SignTool @sigArgs" ) ;
3112- sb . AppendLine ( "}" ) ;
3128+
3129+ // Pre-flight + file normalization
3130+ sb . AppendLine ( "if (!(Test-Path -LiteralPath $SignTool)) { throw \" SignTool not found: $SignTool\" }" ) ;
3131+ sb . AppendLine ( "if (!(Test-Path -LiteralPath $PfxPath)) { throw \" PFX file not found: $PfxPath\" }" ) ;
3132+ sb . AppendLine ( "$targetFiles = @()" ) ;
3133+ sb . AppendLine ( "foreach ($f in $files) { if (Test-Path -LiteralPath $f) { $targetFiles += (Resolve-Path -LiteralPath $f).Path } else { Write-Warning \" File not found, skipping: $f\" } }" ) ;
3134+ sb . AppendLine ( "if ($targetFiles.Count -eq 0) { throw 'No input files to sign.' }" ) ;
3135+ sb . AppendLine ( "$failures = @()" ) ;
3136+ sb . AppendLine ( ) ;
3137+
3138+ // Per-file signing with exit code checks
3139+ sb . AppendLine ( "try {" ) ;
3140+ sb . AppendLine ( " foreach ($f in $targetFiles) {" ) ;
3141+ sb . AppendLine ( " $sigArgs = @('sign')" ) ;
3142+ sb . AppendLine ( " Add-GlobalSwitches ([ref]$sigArgs)" ) ;
3143+ sb . AppendLine ( " if ($UseTimestamp -and $TimestampUrl) { $sigArgs += '/fd'; $sigArgs += 'sha256'; $sigArgs += '/tr'; $sigArgs += $TimestampUrl; $sigArgs += '/td'; $sigArgs += 'sha256' } else { $sigArgs += '/fd'; $sigArgs += 'sha256' }" ) ;
3144+ sb . AppendLine ( " $sigArgs += '/f'; $sigArgs += $PfxPath; $sigArgs += '/p'; $sigArgs += $PfxPassword; $sigArgs += '/a'; $sigArgs += $f" ) ;
3145+ sb . AppendLine ( " & $SignTool @sigArgs" ) ;
3146+ sb . AppendLine ( " if ($LASTEXITCODE -ne 0) { Write-Warning \" Signing failed (exit $LASTEXITCODE): $f\" ; $failures += $f } else { Write-Host \" Signed: $f\" }" ) ;
3147+ sb . AppendLine ( " }" ) ;
3148+ sb . AppendLine ( " if ($failures.Count -gt 0) { throw (\" One or more files failed to sign:`n - \" + ($failures -join \" `n - \" )) }" ) ;
3149+ sb . AppendLine ( "} finally { $PfxPassword = $null }" ) ;
31133150 }
31143151 else if ( radioButtonTrustedSigning . Checked )
31153152 {
@@ -3123,9 +3160,13 @@ private void buttonExportAsScript_Click(object sender, EventArgs e)
31233160 endpointUrl = tp . Url ;
31243161 else
31253162 {
3126- var enabled = _timestampManager . GetEnabledServers ( ) ;
3127- if ( enabled . Count > 0 )
3128- endpointUrl = enabled . First ( ) . Url ;
3163+ try
3164+ {
3165+ var enabled = _timestampManager . GetEnabledServers ( ) ;
3166+ if ( enabled . Count > 0 )
3167+ endpointUrl = enabled . First ( ) . Url ;
3168+ }
3169+ catch { /* ignore */ }
31293170 }
31303171
31313172 sb . AppendLine ( "# Trusted Signing" ) ;
@@ -3136,17 +3177,32 @@ private void buttonExportAsScript_Click(object sender, EventArgs e)
31363177 sb . AppendLine ( "$CorrelationIdData = '" + EscapePS ( textBoxCorrelationId . Text ) + "'" ) ;
31373178 sb . AppendLine ( "$TimestampUrl = '" + EscapePS ( tsTimestampUrl ) + "'" ) ;
31383179 sb . AppendLine ( ) ;
3139- sb . AppendLine ( "# Create temporary DMDF JSON file" ) ;
3140- sb . AppendLine ( "$dmdfPath = Join-Path $env:TEMP (('signtoolgui_' + [guid]::NewGuid().ToString()) + '.json')" ) ;
3141- sb . AppendLine ( "$dmdfContent = @{ Endpoint = $Endpoint; CodeSigningAccountName = $AccountName; CertificateProfileName = $CertificateProfileName; CorrelationIdData = $CorrelationIdData } | ConvertTo-Json -Depth 3" ) ;
3142- sb . AppendLine ( "$dmdfContent | Out-File -FilePath $dmdfPath -Encoding utf8" ) ;
3180+
3181+ // Pre-flight + file normalization
3182+ sb . AppendLine ( "if (!(Test-Path -LiteralPath $SignTool)) { throw \" SignTool not found: $SignTool\" }" ) ;
3183+ sb . AppendLine ( "if (!(Test-Path -LiteralPath $DlibPath)) { throw \" Dlib not found: $DlibPath\" }" ) ;
3184+ sb . AppendLine ( "$targetFiles = @()" ) ;
3185+ sb . AppendLine ( "foreach ($f in $files) { if (Test-Path -LiteralPath $f) { $targetFiles += (Resolve-Path -LiteralPath $f).Path } else { Write-Warning \" File not found, skipping: $f\" } }" ) ;
3186+ sb . AppendLine ( "if ($targetFiles.Count -eq 0) { throw 'No input files to sign.' }" ) ;
3187+ sb . AppendLine ( ) ;
3188+
3189+ // DMDF payload
3190+ sb . AppendLine ( "if ([string]::IsNullOrWhiteSpace($CorrelationIdData)) { $CorrelationIdData = [guid]::NewGuid().ToString() }" ) ;
3191+ sb . AppendLine ( "$dmdf = @{ Endpoint = $Endpoint; CodeSigningAccountName = $AccountName; CertificateProfileName = $CertificateProfileName; CorrelationIdData = $CorrelationIdData }" ) ;
3192+ sb . AppendLine ( "$dmdfPath = Join-Path $env:TEMP (\" signtoolgui_{0}.json\" -f ([guid]::NewGuid()))" ) ;
3193+ sb . AppendLine ( "$dmdf | ConvertTo-Json -Depth 3 | Out-File -FilePath $dmdfPath -Encoding utf8" ) ;
31433194 sb . AppendLine ( ) ;
3195+
3196+ // Common args and signing
3197+ sb . AppendLine ( "$commonArgs = @('/fd','sha256','/tr',$TimestampUrl,'/td','sha256','/dlib',$DlibPath,'/dmdf',$dmdfPath)" ) ;
3198+ sb . AppendLine ( "$failures = @()" ) ;
31443199 sb . AppendLine ( "try {" ) ;
3145- sb . AppendLine ( " foreach ($f in $files) {" ) ;
3146- sb . AppendLine ( " $sigArgs = @('sign')" ) ;
3147- sb . AppendLine ( " Add-GlobalSwitches ([ref]$sigArgs)" ) ;
3148- sb . AppendLine ( " $sigArgs += '/fd'; $sigArgs += 'sha256'; $sigArgs += '/tr'; $sigArgs += $TimestampUrl; $sigArgs += '/td'; $sigArgs += 'sha256'; $sigArgs += '/dlib'; $sigArgs += $DlibPath; $sigArgs += '/dmdf'; $sigArgs += $dmdfPath; $sigArgs += $f" ) ;
3149- sb . AppendLine ( " & $SignTool @sigArgs" ) ;
3200+ sb . AppendLine ( " if ($BatchMode) {" ) ;
3201+ sb . AppendLine ( " $sigArgs = @('sign'); Add-GlobalSwitches ([ref]$sigArgs); $sigArgs += $commonArgs; $sigArgs += $targetFiles; & $SignTool @sigArgs" ) ;
3202+ sb . AppendLine ( " if ($LASTEXITCODE -ne 0) { $failures = $targetFiles; throw \" signtool exited with code $LASTEXITCODE in batch mode.\" } else { Write-Host (\" Signed {0} file(s) in batch.\" -f $targetFiles.Count) }" ) ;
3203+ sb . AppendLine ( " } else {" ) ;
3204+ sb . AppendLine ( " foreach ($f in $targetFiles) { $sigArgs = @('sign'); Add-GlobalSwitches ([ref]$sigArgs); $sigArgs += $commonArgs; $sigArgs += $f; & $SignTool @sigArgs; if ($LASTEXITCODE -ne 0) { Write-Warning \" Signing failed (exit $LASTEXITCODE): $f\" ; $failures += $f } else { Write-Host \" Signed: $f\" } }" ) ;
3205+ sb . AppendLine ( " if ($failures.Count -gt 0) { throw (\" One or more files failed to sign:`n - \" + ($failures -join \" `n - \" )) }" ) ;
31503206 sb . AppendLine ( " }" ) ;
31513207 sb . AppendLine ( "}" ) ;
31523208 sb . AppendLine ( "finally { Remove-Item -Path $dmdfPath -Force -ErrorAction Ignore }" ) ;
@@ -3160,12 +3216,14 @@ private void buttonExportAsScript_Click(object sender, EventArgs e)
31603216 File . WriteAllText ( sfd . FileName , sb . ToString ( ) , Encoding . UTF8 ) ;
31613217
31623218 Message ( "Command script exported: '" + sfd . FileName + "'" , EventType . Information , 20100 ) ;
3163- MessageBox . Show ( "Command script exported:\n " + sfd . FileName , "Export Command Script" , MessageBoxButtons . OK , MessageBoxIcon . Information ) ;
3219+ MessageBox . Show ( "Command script exported:\n " + sfd . FileName , "Export Command Script" ,
3220+ MessageBoxButtons . OK , MessageBoxIcon . Information ) ;
31643221 }
31653222 }
31663223 catch ( Exception ex )
31673224 {
3168- MessageBox . Show ( "Failed to export command script: " + ex . Message , "Export Command Script" , MessageBoxButtons . OK , MessageBoxIcon . Error ) ;
3225+ MessageBox . Show ( "Failed to export command script: " + ex . Message , "Export Command Script" ,
3226+ MessageBoxButtons . OK , MessageBoxIcon . Error ) ;
31693227 Message ( "Failed to export command script: " + ex . Message , EventType . Error , 20101 ) ;
31703228 }
31713229 }
0 commit comments