Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes308downloads
SecurityManager.cs829 linesDownload Raw Back to security
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