MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.ObjectModel;6using System.IO;7using System.Management.Automation;8using System.Management.Automation.Host;9using System.Management.Automation.Internal;10using System.Management.Automation.Language;11using System.Management.Automation.Security;12using System.Security;13using System.Security.Cryptography.X509Certificates;14using System.Text;15 16using Dbg = System.Management.Automation;17 18namespace Microsoft.PowerShell19{20 /// <summary>21 /// Defines the authorization policy that controls the way scripts22 /// (and other command types) are handled by PowerShell. This authorization23 /// policy enforces one of four levels, as defined by the 'ExecutionPolicy'24 /// value in one of the following locations:25 ///26 /// In priority-order (highest priority first,) these come from:27 ///28 /// - Machine-wide Group Policy29 /// HKLM\Software\Policies\Microsoft\Windows\PowerShell30 /// - Current-user Group Policy31 /// HKCU\Software\Policies\Microsoft\Windows\PowerShell.32 /// - Current session preference33 /// ENV:PSExecutionPolicyPreference34 /// - Current user machine preference35 /// HKEY_CURRENT_USER\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell36 /// - Local machine preference37 /// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell38 ///39 /// Restricted - All .ps1 files are blocked. ps1xml files must be digitally40 /// signed, and by a trusted publisher. If you haven't made a trust decision41 /// on the publisher yet, prompting is done as in AllSigned mode.42 /// AllSigned - All .ps1 and .ps1xml files must be digitally signed. If43 /// signed and executed, PowerShell prompts to determine if files from the44 /// signing publisher should be run or not.45 /// RemoteSigned - Only .ps1 and .ps1xml files originating from the internet46 /// must be digitally signed. If remote, signed, and executed, PowerShell47 /// prompts to determine if files from the signing publisher should be48 /// run or not. This is the default setting.49 /// Unrestricted - No files must be signed. If a file originates from the50 /// internet, PowerShell provides a warning prompt to alert the user. To51 /// suppress this warning message, right-click on the file in File Explorer,52 /// select "Properties," and then "Unblock." Requires Shell.53 /// Bypass - No files must be signed, and internet origin is not verified.54 /// </summary>55 public sealed class PSAuthorizationManager : AuthorizationManager56 {57 internal enum RunPromptDecision58 {59 NeverRun = 0,60 DoNotRun = 1,61 RunOnce = 2,62 AlwaysRun = 3,63 Suspend = 464 }65 66 #region constructor67 68 // execution policy that dictates what can run in msh69 private ExecutionPolicy _executionPolicy;70 71 // shellId supplied by runspace configuration72 private readonly string _shellId;73 74 /// <summary>75 /// Initializes a new instance of the PSAuthorizationManager76 /// class, for a given ShellId.77 /// </summary>78 /// <param name="shellId">79 /// The shell identifier that the authorization manager applies80 /// to. For example, Microsoft.PowerShell81 /// </param>82 public PSAuthorizationManager(string shellId)83 : base(shellId)84 {85 if (string.IsNullOrEmpty(shellId))86 {87 throw PSTraceSource.NewArgumentNullException(nameof(shellId));88 }89 90 _shellId = shellId;91 }92 93 #endregion constructor94 95 #region signing check96 97 private static bool IsSupportedExtension(string ext)98 {99 return (100 ext.Equals(".ps1", StringComparison.OrdinalIgnoreCase) ||101 ext.Equals(".ps1xml", StringComparison.OrdinalIgnoreCase) ||102 ext.Equals(".psm1", StringComparison.OrdinalIgnoreCase) ||103 ext.Equals(".psd1", StringComparison.OrdinalIgnoreCase) ||104 ext.Equals(".xaml", StringComparison.OrdinalIgnoreCase) ||105 ext.Equals(".cdxml", StringComparison.OrdinalIgnoreCase));106 }107 108 private bool CheckPolicy(ExternalScriptInfo script, PSHost host, out Exception reason)109 {110 bool policyCheckPassed = false;111 reason = null;112 string path = script.Path;113 string reasonMessage;114 115 // path is assumed to be fully qualified here116 if (path.IndexOf(System.IO.Path.DirectorySeparatorChar) < 0)117 {118 throw PSTraceSource.NewArgumentException("path");119 }120 121 if (path.LastIndexOf(System.IO.Path.DirectorySeparatorChar) == (path.Length - 1))122 {123 throw PSTraceSource.NewArgumentException("path");124 }125 126 FileInfo fi = new FileInfo(path);127 128 // Return false if the file does not exist, so that129 // we don't introduce a race condition130 if (!fi.Exists)131 {132 reason = new FileNotFoundException(path);133 return false;134 }135 136 // Quick exit if we don't support the file type137 if (!IsSupportedExtension(fi.Extension))138 return true;139 140 // Get the execution policy141 _executionPolicy = SecuritySupport.GetExecutionPolicy(_shellId);142 143 // Always check the SAFER APIs if code integrity isn't being handled system-wide through144 // WLDP or AppLocker. In those cases, the scripts will be run in ConstrainedLanguage.145 // Otherwise, block.146 // SAFER APIs are not on CSS or OneCore147 if (SystemPolicy.GetSystemLockdownPolicy() != SystemEnforcementMode.Enforce)148 {149 SaferPolicy saferPolicy = SaferPolicy.Disallowed;150 int saferAttempt = 0;151 bool gotSaferPolicy = false;152 153 // We need to put in a retry workaround, as the SAFER APIs fail when under stress.154 while ((!gotSaferPolicy) && (saferAttempt < 5))155 {156 try157 {158 saferPolicy = SecuritySupport.GetSaferPolicy(path, null);159 gotSaferPolicy = true;160 }161 catch (System.ComponentModel.Win32Exception)162 {163 if (saferAttempt > 4)164 {165 throw;166 }167 168 saferAttempt++;169 System.Threading.Thread.Sleep(100);170 }171 }172 173 // If the script is disallowed via AppLocker, block the file174 // unless the system-wide lockdown policy is "Enforce" (where all PowerShell175 // scripts are in blocked). If the system policy is "Enforce", then the176 // script will be allowed (but ConstrainedLanguage will be applied).177 if (saferPolicy == SaferPolicy.Disallowed)178 {179 reasonMessage = StringUtil.Format(Authenticode.Reason_DisallowedBySafer, path);180 reason = new UnauthorizedAccessException(reasonMessage);181 182 return false;183 }184 }185 186 // WLDP and Applocker takes priority over powershell execution policy.187 // See if they want to bypass the authorization manager188 if (_executionPolicy == ExecutionPolicy.Bypass)189 {190 return true;191 }192 193 if (_executionPolicy == ExecutionPolicy.Unrestricted)194 {195 // Product binaries are always trusted196 // This avoids signature and security zone checks197 if (SecuritySupport.IsProductBinary(path))198 return true;199 200 // We need to give the "Remote File" warning201 // if the file originated from the internet202 if (!IsLocalFile(fi.FullName))203 {204 // Get the signature of the file.205 if (string.IsNullOrEmpty(script.ScriptContents))206 {207 reasonMessage = StringUtil.Format(Authenticode.Reason_FileContentUnavailable, path);208 reason = new UnauthorizedAccessException(reasonMessage);209 210 return false;211 }212 213 Signature signature = GetSignatureWithEncodingRetry(path, script);214 215 // The file is signed, with a publisher that216 // we trust217 if (signature.Status == SignatureStatus.Valid)218 {219 // The file is signed by a trusted publisher220 if (IsTrustedPublisher(signature, path))221 {222 policyCheckPassed = true;223 }224 }225 226 // We don't care about the signature. If you distrust them,227 // or the signature does not exist, we prompt you only228 // because it's remote.229 if (!policyCheckPassed)230 {231 RunPromptDecision decision = RunPromptDecision.DoNotRun;232 233 // Get their remote prompt answer, allowing them to234 // enter nested prompts, if wanted.235 do236 {237 decision = RemoteFilePrompt(path, host);238 239 if (decision == RunPromptDecision.Suspend)240 host.EnterNestedPrompt();241 } while (decision == RunPromptDecision.Suspend);242 243 switch (decision)244 {245 case RunPromptDecision.RunOnce:246 policyCheckPassed = true;247 break;248 case RunPromptDecision.DoNotRun:249 default:250 policyCheckPassed = false;251 reasonMessage = StringUtil.Format(Authenticode.Reason_DoNotRun, path);252 reason = new UnauthorizedAccessException(reasonMessage);253 break;254 }255 }256 }257 else258 {259 policyCheckPassed = true;260 }261 }262 // Don't need to check the signature if the file is local263 // and we're in "RemoteSigned" mode264 else if ((IsLocalFile(fi.FullName)) &&265 (_executionPolicy == ExecutionPolicy.RemoteSigned))266 {267 policyCheckPassed = true;268 }269 else if ((_executionPolicy == ExecutionPolicy.AllSigned) ||270 (_executionPolicy == ExecutionPolicy.RemoteSigned))271 {272 // if policy requires signature verification,273 // make it so.274 275 // Get the signature of the file.276 if (string.IsNullOrEmpty(script.ScriptContents))277 {278 reasonMessage = StringUtil.Format(Authenticode.Reason_FileContentUnavailable, path);279 reason = new UnauthorizedAccessException(reasonMessage);280 281 return false;282 }283 284 Signature signature = GetSignatureWithEncodingRetry(path, script);285 286 // The file is signed.287 if (signature.Status == SignatureStatus.Valid)288 {289 // The file is signed by a trusted publisher290 if (IsTrustedPublisher(signature, path))291 {292 policyCheckPassed = true;293 }294 // The file is signed by an unknown publisher,295 // So prompt.296 else297 {298 policyCheckPassed = SetPolicyFromAuthenticodePrompt(path, host, ref reason, signature);299 }300 }301 // The file is UnknownError, NotSigned, HashMismatch,302 // NotTrusted, NotSupportedFileFormat303 else304 {305 policyCheckPassed = false;306 307 if (signature.Status == SignatureStatus.NotTrusted)308 {309 reason = new UnauthorizedAccessException(310 StringUtil.Format(Authenticode.Reason_NotTrusted,311 path,312 signature.SignerCertificate.SubjectName.Name));313 }314 else315 {316 reason = new UnauthorizedAccessException(317 StringUtil.Format(Authenticode.Reason_Unknown,318 path,319 signature.StatusMessage));320 }321 }322 }323 else // if(executionPolicy == ExecutionPolicy.Restricted)324 {325 // Deny everything326 policyCheckPassed = false;327 328 // But accept mshxml files from publishers that we329 // trust, or files in the system protected directories330 bool reasonSet = false;331 if (string.Equals(fi.Extension, ".ps1xml", StringComparison.OrdinalIgnoreCase))332 {333 string[] trustedDirectories = new string[]334 {335 Environment.GetFolderPath(Environment.SpecialFolder.System),336 Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)337 };338 339 foreach (string trustedDirectory in trustedDirectories)340 {341 if (fi.FullName.StartsWith(trustedDirectory, StringComparison.OrdinalIgnoreCase))342 policyCheckPassed = true;343 }344 345 if (!policyCheckPassed)346 {347 // Get the signature of the file.348 Signature signature = GetSignatureWithEncodingRetry(path, script);349 350 // The file is signed by a trusted publisher351 if (signature.Status == SignatureStatus.Valid)352 {353 if (IsTrustedPublisher(signature, path))354 {355 policyCheckPassed = true;356 }357 // The file is signed by an unknown publisher,358 // So prompt.359 else360 {361 policyCheckPassed = SetPolicyFromAuthenticodePrompt(path, host, ref reason, signature);362 reasonSet = true;363 }364 }365 }366 }367 368 if (!policyCheckPassed && !reasonSet)369 {370 reason = new UnauthorizedAccessException(371 StringUtil.Format(Authenticode.Reason_RestrictedMode,372 path));373 }374 }375 376 return policyCheckPassed;377 }378 379 private static bool SetPolicyFromAuthenticodePrompt(string path, PSHost host, ref Exception reason, Signature signature)380 {381 bool policyCheckPassed = false;382 383 string reasonMessage;384 RunPromptDecision decision = AuthenticodePrompt(path, signature, host);385 386 switch (decision)387 {388 case RunPromptDecision.RunOnce:389 policyCheckPassed = true; break;390 case RunPromptDecision.AlwaysRun:391 {392 TrustPublisher(signature);393 policyCheckPassed = true;394 }395 396 break;397 case RunPromptDecision.DoNotRun:398 policyCheckPassed = false;399 reasonMessage = StringUtil.Format(Authenticode.Reason_DoNotRun, path);400 reason = new UnauthorizedAccessException(reasonMessage);401 break;402 case RunPromptDecision.NeverRun:403 {404 UntrustPublisher(signature);405 reasonMessage = StringUtil.Format(Authenticode.Reason_NeverRun, path);406 reason = new UnauthorizedAccessException(reasonMessage);407 policyCheckPassed = false;408 }409 410 break;411 }412 413 return policyCheckPassed;414 }415 416 private static bool IsLocalFile(string filename)417 {418#if UNIX419 return true;420#else421 SecurityZone zone = ClrFacade.GetFileSecurityZone(filename);422 423 if (zone == SecurityZone.MyComputer ||424 zone == SecurityZone.Intranet ||425 zone == SecurityZone.Trusted)426 {427 return true;428 }429 430 return false;431#endif432 }433 434 // Checks that a publisher is trusted by the system or is one of435 // the signed product binaries436 private static bool IsTrustedPublisher(Signature signature, string file)437 {438 // Get the thumbprint of the current signature439 X509Certificate2 signerCertificate = signature.SignerCertificate;440 string thumbprint = signerCertificate.Thumbprint;441 442 // See if it matches any in the list of trusted publishers443 X509Store trustedPublishers = new X509Store(StoreName.TrustedPublisher, StoreLocation.CurrentUser);444 trustedPublishers.Open(OpenFlags.ReadOnly);445 446 foreach (X509Certificate2 trustedCertificate in trustedPublishers.Certificates)447 {448 if (string.Equals(trustedCertificate.Thumbprint, thumbprint, StringComparison.OrdinalIgnoreCase))449 {450 if (!IsUntrustedPublisher(signature, file))451 {452 return true;453 }454 }455 }456 457 return false;458 }459 460 private static bool IsUntrustedPublisher(Signature signature, string file)461 {462 // Get the thumbprint of the current signature463 X509Certificate2 signerCertificate = signature.SignerCertificate;464 string thumbprint = signerCertificate.Thumbprint;465 466 // See if it matches any in the list of trusted publishers467 X509Store trustedPublishers = new X509Store(StoreName.Disallowed, StoreLocation.CurrentUser);468 trustedPublishers.Open(OpenFlags.ReadOnly);469 470 foreach (X509Certificate2 trustedCertificate in trustedPublishers.Certificates)471 {472 if (string.Equals(trustedCertificate.Thumbprint, thumbprint, StringComparison.OrdinalIgnoreCase))473 return true;474 }475 476 return false;477 }478 479 /// <summary>480 /// Trust a publisher by adding it to the "Trusted Publishers" store.481 /// </summary>482 /// <param name="signature"></param>483 private static void TrustPublisher(Signature signature)484 {485 // Get the certificate of the signer486 X509Certificate2 signerCertificate = signature.SignerCertificate;487 X509Store trustedPublishers = new X509Store(StoreName.TrustedPublisher, StoreLocation.CurrentUser);488 489 try490 {491 // Add it to the list of trusted publishers492 trustedPublishers.Open(OpenFlags.ReadWrite);493 trustedPublishers.Add(signerCertificate);494 }495 finally496 {497 trustedPublishers.Close();498 }499 }500 501 private static void UntrustPublisher(Signature signature)502 {503 // Get the certificate of the signer504 X509Certificate2 signerCertificate = signature.SignerCertificate;505 X509Store untrustedPublishers = new X509Store(StoreName.Disallowed, StoreLocation.CurrentUser);506 X509Store trustedPublishers = new X509Store(StoreName.TrustedPublisher, StoreLocation.CurrentUser);507 508 // Remove it from the list of trusted publishers509 try510 {511 // Remove the signer, if it's there512 trustedPublishers.Open(OpenFlags.ReadWrite);513 trustedPublishers.Remove(signerCertificate);514 }515 finally516 {517 trustedPublishers.Close();518 }519 520 try521 {522 // Add it to the list of untrusted publishers523 untrustedPublishers.Open(OpenFlags.ReadWrite);524 untrustedPublishers.Add(signerCertificate);525 }526 finally527 {528 untrustedPublishers.Close();529 }530 }531 532 // Check the signature via the SIP which should never erroneously validate an invalid signature533 // or altered script.534 private static Signature GetSignatureWithEncodingRetry(string path, ExternalScriptInfo script)535 {536 // Invoke the SIP directly with the most simple method537 Signature signature = SignatureHelper.GetSignature(path, fileContent: null);538 if (signature.Status == SignatureStatus.Valid)539 {540 return signature;541 }542 543 // try harder to validate the signature by being explicit about encoding544 // and providing the script contents545 byte[] bytesWithBom = GetContentBytesWithBom(script.OriginalEncoding, script.ScriptContents);546 signature = SignatureHelper.GetSignature(path, bytesWithBom);547 548 // A last ditch effort -549 // If the file was originally ASCII or UTF8, the SIP may have added the Unicode BOM550 if (signature.Status != SignatureStatus.Valid551 && script.OriginalEncoding != Encoding.Unicode)552 {553 bytesWithBom = GetContentBytesWithBom(Encoding.Unicode, script.ScriptContents);554 Signature fallbackSignature = SignatureHelper.GetSignature(path, bytesWithBom);555 556 if (fallbackSignature.Status == SignatureStatus.Valid)557 signature = fallbackSignature;558 }559 560 return signature;561 }562 563 private static byte[] GetContentBytesWithBom(Encoding encoding, string scriptContent)564 {565 ReadOnlySpan<byte> bomBytes = encoding.Preamble;566 byte[] contentBytes = encoding.GetBytes(scriptContent);567 byte[] bytesWithBom = new byte[bomBytes.Length + contentBytes.Length];568 569 bomBytes.CopyTo(bytesWithBom);570 contentBytes.CopyTo(bytesWithBom, index: bomBytes.Length);571 return bytesWithBom;572 }573 574 #endregion signing check575 576 /// <summary>577 /// Determines if should run the specified command. Please see the578 /// class summary for an overview of the semantics enforced by this579 /// authorization manager.580 /// </summary>581 /// <param name="commandInfo">582 /// The command to be run.583 /// </param>584 /// <param name="origin">585 /// The origin of the command.586 /// </param>587 /// <param name="host">588 /// The PSHost executing the command.589 /// </param>590 /// <param name="reason">591 /// If access is denied, this parameter provides a specialized592 /// Exception as the reason.593 /// </param>594 /// <returns>595 /// True if the command should be run. False otherwise.596 /// </returns>597 /// <exception cref="System.ArgumentException">598 /// CommandInfo is invalid. This may occur if599 /// commandInfo.Name is null or empty.600 /// </exception>601 /// <exception cref="System.ArgumentNullException">602 /// CommandInfo is null.603 /// </exception>604 /// <exception cref="System.IO.FileNotFoundException">605 /// The file specified by commandInfo.Path is not found.606 /// </exception>607 protected internal override bool ShouldRun(CommandInfo commandInfo,608 CommandOrigin origin,609 PSHost host,610 out Exception reason)611 {612 Dbg.Diagnostics.Assert(commandInfo != null, "caller should validate the parameter");613 614 bool allowRun = false;615 reason = null;616 Utils.CheckArgForNull(commandInfo, "commandInfo");617 Utils.CheckArgForNullOrEmpty(commandInfo.Name, "commandInfo.Name");618 619 switch (commandInfo.CommandType)620 {621 case CommandTypes.Cmdlet:622 // Always allow cmdlets to run623 allowRun = true;624 break;625 626 case CommandTypes.Alias:627 //628 // we do not care about verifying an alias as we will629 // get subsequent call(s) for commands/scripts630 // when the alias is expanded.631 //632 allowRun = true;633 break;634 635 case CommandTypes.Function:636 case CommandTypes.Filter:637 case CommandTypes.Configuration:638 //639 // we do not check functions/filters.640 // we only perform script level check.641 //642 allowRun = true;643 break;644 645 case CommandTypes.Script:646 //647 // Allow scripts that are built into the648 // runspace configuration to run.649 //650 allowRun = true;651 break;652 653 case CommandTypes.ExternalScript:654 if (commandInfo is not ExternalScriptInfo si)655 {656 reason = PSTraceSource.NewArgumentException("scriptInfo");657 }658 else659 {660 bool etwEnabled = ParserEventSource.Log.IsEnabled();661 if (etwEnabled)662 {663 ParserEventSource.Log.CheckSecurityStart(si.Path);664 }665 666 allowRun = CheckPolicy(si, host, out reason);667 if (etwEnabled)668 {669 ParserEventSource.Log.CheckSecurityStop(si.Path);670 }671 }672 673 break;674 675 case CommandTypes.Application:676 //677 // We do not check executables -- that is done by Windows678 //679 allowRun = true;680 break;681 }682 683 return allowRun;684 }685 686 private static RunPromptDecision AuthenticodePrompt(string path,687 Signature signature,688 PSHost host)689 {690 if ((host == null) || (host.UI == null))691 {692 return RunPromptDecision.DoNotRun;693 }694 695 RunPromptDecision decision = RunPromptDecision.DoNotRun;696 697 if (signature == null)698 {699 return decision;700 }701 702 switch (signature.Status)703 {704 //705 // we do not allow execution in any one of the706 // following cases707 //708 case SignatureStatus.UnknownError:709 case SignatureStatus.NotSigned:710 case SignatureStatus.HashMismatch:711 case SignatureStatus.NotSupportedFileFormat:712 decision = RunPromptDecision.DoNotRun;713 break;714 715 case SignatureStatus.Valid:716 Collection<ChoiceDescription> choices = GetAuthenticodePromptChoices();717 718 string promptCaption =719 Authenticode.AuthenticodePromptCaption;720 721 string promptText;722 723 if (signature.SignerCertificate == null)724 {725 promptText =726 StringUtil.Format(Authenticode.AuthenticodePromptText_UnknownPublisher,727 path);728 }729 else730 {731 promptText =732 StringUtil.Format(Authenticode.AuthenticodePromptText,733 path,734 signature.SignerCertificate.SubjectName.Name735 );736 }737 738 int userChoice =739 host.UI.PromptForChoice(promptCaption,740 promptText,741 choices,742 (int)RunPromptDecision.DoNotRun);743 decision = (RunPromptDecision)userChoice;744 745 break;746 747 //748 // if the publisher is not trusted, we prompt and749 // ask the user if s/he wants to allow it to run750 //751 default:752 decision = RunPromptDecision.DoNotRun;753 break;754 }755 756 return decision;757 }758 759 private static RunPromptDecision RemoteFilePrompt(string path, PSHost host)760 {761 if ((host == null) || (host.UI == null))762 {763 return RunPromptDecision.DoNotRun;764 }765 766 Collection<ChoiceDescription> choices = GetRemoteFilePromptChoices();767 768 string promptCaption =769 Authenticode.RemoteFilePromptCaption;770 771 string promptText =772 StringUtil.Format(Authenticode.RemoteFilePromptText,773 path);774 775 int userChoice = host.UI.PromptForChoice(promptCaption,776 promptText,777 choices,778 0);779 780 switch (userChoice)781 {782 case 0: return RunPromptDecision.DoNotRun;783 case 1: return RunPromptDecision.RunOnce;784 case 2: return RunPromptDecision.Suspend;785 default: return RunPromptDecision.DoNotRun;786 }787 }788 789 private static Collection<ChoiceDescription> GetAuthenticodePromptChoices()790 {791 Collection<ChoiceDescription> choices = new Collection<ChoiceDescription>();792 793 string neverRun = Authenticode.Choice_NeverRun;794 string neverRunHelp = Authenticode.Choice_NeverRun_Help;795 string doNotRun = Authenticode.Choice_DoNotRun;796 string doNotRunHelp = Authenticode.Choice_DoNotRun_Help;797 string runOnce = Authenticode.Choice_RunOnce;798 string runOnceHelp = Authenticode.Choice_RunOnce_Help;799 string alwaysRun = Authenticode.Choice_AlwaysRun;800 string alwaysRunHelp = Authenticode.Choice_AlwaysRun_Help;801 802 choices.Add(new ChoiceDescription(neverRun, neverRunHelp));803 choices.Add(new ChoiceDescription(doNotRun, doNotRunHelp));804 choices.Add(new ChoiceDescription(runOnce, runOnceHelp));805 choices.Add(new ChoiceDescription(alwaysRun, alwaysRunHelp));806 807 return choices;808 }809 810 private static Collection<ChoiceDescription> GetRemoteFilePromptChoices()811 {812 Collection<ChoiceDescription> choices = new Collection<ChoiceDescription>();813 814 string doNotRun = Authenticode.Choice_DoNotRun;815 string doNotRunHelp = Authenticode.Choice_DoNotRun_Help;816 string runOnce = Authenticode.Choice_RunOnce;817 string runOnceHelp = Authenticode.Choice_RunOnce_Help;818 string suspend = Authenticode.Choice_Suspend;819 string suspendHelp = Authenticode.Choice_Suspend_Help;820 821 choices.Add(new ChoiceDescription(doNotRun, doNotRunHelp));822 choices.Add(new ChoiceDescription(runOnce, runOnceHelp));823 choices.Add(new ChoiceDescription(suspend, suspendHelp));824 825 return choices;826 }827 }828}829 