如何使用 .NET 4 运行时运行 PowerShell?

Posted

技术标签:

【中文标题】如何使用 .NET 4 运行时运行 PowerShell?【英文标题】:How can I run PowerShell with the .NET 4 runtime? 【发布时间】:2011-01-06 20:55:47 【问题描述】:

我正在更新管理一些 .NET 程序集的 PowerShell 脚本。该脚本是为针对 .NET 2(与 PowerShell 运行的框架版本相同)构建的程序集编写的,但现在需要使用 .NET 4 程序集以及 .NET 2 程序集。

由于 .NET 4 支持运行针对旧版本框架构建的应用程序,因此当我需要针对 .NET 4 程序集运行 PowerShell 时,似乎最简单的解决方案是使用 .NET 4 运行时启动它。

【问题讨论】:

***.com/questions/1940983/… 的副本。 现在最简单的解决方案是安装使用 CLRVersion: 4.0.30319.1 的 Powershell 3.0 CTP。 任何人仍然坚持使用 PowerShell 2,see Tim Lewis's answer 以获得不需要编辑任何机器范围配置的本地化解决方案。 对于非系统范围和无文件的解决方案,请参阅this answer 【参考方案1】:

我发现的最佳解决方案是在博文中Using Newer Version(s) of .NET with PowerShell。这允许 powershell.exe 与 .NET 4 程序集一起运行。

只需修改(或创建)$pshome\powershell.exe.config,使其包含以下内容:

<?xml version="1.0"?> 
<configuration> 
    <startup useLegacyV2RuntimeActivationPolicy="true"> 
        <supportedRuntime version="v4.0.30319"/> 
        <supportedRuntime version="v2.0.50727"/> 
    </startup> 
</configuration> 

其他快速设置说明:

位置和文件在某种程度上取决于平台;但是会给你一个关于如何使解决方案适合你的内嵌要点。

您可以通过在 Powershell 窗口中执行cd $pshome在您的计算机上找到 PowerShell 的位置(在 DOS 提示符下不起作用)。 路径类似于(示例)C:\Windows\System32\WindowsPowerShell\v1.0\ 如果您的PowerShell.exe 正在执行,则要放入配置的文件名是:powershell.exe.config(如果需要,请创建配置文件)。 如果PowerShellISE.Exe 正在运行,那么您需要将其配套配置文件创建为PowerShellISE.Exe.config

【讨论】:

绝对是正确的方法。这只会改变 Powershell 的行为,而不是您机器上的所有其他 .NET 应用程序... 这很好用,但会影响您的所有 PowerShell。如果您只想要一些功能,请复制 powershell 文件夹,然后在那里编辑文件。 我添加了一个如上所述的文件。但是,我无法再在该文件存在的情况下运行 PowerShell - 我收到错误消息“文件的卷已被外部更改,因此打开的文件不再有效。”有什么想法吗? @JoshL - 在 64 位系统上,我发现 .exe.config 需要进入 SysWOW64\WindowsPowershell(32 位文件夹),即使您尝试运行 64 位电源外壳。否则,您会收到“外部更改”错误。 powershell.exe.config 需要在两个地方.... C:\Windows\System32\WindowsPowerShell\v1.0\ 和 C:\Windows\SysWOW64\WindowsPowerShell\v1.0 \【参考方案2】:

PowerShell(引擎)在 .NET 4.0 下运行良好。 PowerShell(控制台主机和ISE)没有,因为它们是针对旧版本的.NET 编译的。有一个注册表设置将更改系统范围内加载的 .NET 框架,从而允许 PowerShell 使用 .NET 4.0 类:

reg add hklm\software\microsoft\.netframework /v OnlyUseLatestCLR /t REG_DWORD /d 1
reg add hklm\software\wow6432node\microsoft\.netframework /v OnlyUseLatestCLR /t REG_DWORD /d 1

要仅更新 ISE 以使用 .NET 4.0,您可以将配置 ($psHome\powershell_ise.exe.config) 文件更改为具有如下块:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup>
      <supportedRuntime version="v4.0.30319" />
    </startup>
</configuration>

您可以使用 PowerShell API (System.Management.Automation.PowerShell) 构建调用 PowerShell 的 .NET 4.0 应用程序,但这些步骤将有助于使内置 PowerShell 主机在 .NET 4.0 下工作。


当您不再需要这些注册表项时,请删除它们。这些是机器范围的密钥,强制将所有应用程序迁移到 .NET 4.0,甚至是使用 .net 2 和 .net 3.5 的应用程序


【讨论】:

明确一点,powershell.exe(控制台主机应用程序)本身是一个本机应用程序 - 不受管理。 我从上面发现了我的问题。在 64 位操作系统上运行时,您必须将配置文件放在 64 位目录中。 32 位 powershell 可执行文件似乎可以很好地从那里进行更改。 只是一个小建议。不再需要时删除注册表项。我只是浪费了大量时间试图找出为什么我无法构建我正在处理的一些 .NET 3.5 项目。 如果您正在执行多目标(即在 VS2010 中编写 .NET 2.0 应用程序),建议的注册表修改解决方案会产生令人讨厌的副作用。当心。 请注意,Microsoft 强烈警告不要这样做:“虽然可以使用各种机制(例如为 PowerShell 创建配置文件或编辑注册表)来强制 PowerShell 2.0 与 .NET Framework 4.0 一起运行,但这些机制不受支持,并且可能对其他 PowerShell 功能产生负面影响,例如 PowerShell 远程处理和具有混合模式程序集的 cmdlet。” connect.microsoft.com/PowerShell/feedback/details/525435/… Powershell 3.0 原生支持 .NET 4.0。【参考方案3】:

请非常小心使用注册表项方法。这些是机器范围的密钥,并强制将所有应用程序迁移到 .NET 4.0。

如果强制迁移,许多产品将无法工作,这是一种测试辅助手段,而不是生产质量机制。 Visual Studio 2008 和 2010、MSBuild、turbotax 和许多网站、SharePoint 等不应自动迁移。

如果您需要在 4.0 中使用 PowerShell,则应使用配置文件在每个应用程序的基础上完成,您应与 PowerShell 团队核实确切的建议。这可能会破坏一些现有的 PowerShell 命令。

【讨论】:

使用注册表键非常好。令人高兴的是,带有配置文件的启动器应用程序运行良好。我们的脚本主要使用文件系统命令和直接 .NET 调用,并且我们没有注意到命令损坏的任何问题。由于 .NET 4 在很大程度上向后兼容 .NET 2.0,我认为不太可能会有很多损坏的命令(尽管小心一点也无妨:)。【参考方案4】:

如果您只需要在 .NET 4 中执行单个命令、脚本块或脚本文件,请尝试使用 Activation Configuration Files from .NET 4 以使用 CLR 版本 4 仅启动单个 PowerShell 实例。

详细信息:

http://blog.codeassassin.com/2011/03/23/executing-individual-powershell-commands-using-net-4/

一个示例 PowerShell 模块:

https://gist.github.com/882528

【讨论】:

【参考方案5】:

如果您仍然停留在 PowerShell v1.0 或 v2.0,这里是我对 Jason Stangroome 出色答案的变体。

在路径的某处创建一个powershell4.cmd,内容如下:

@echo off
:: http://***.com/questions/7308586/using-batch-echo-with-special-characters
if exist %~dp0powershell.exe.activation_config goto :run
echo.^<?xml version="1.0" encoding="utf-8" ?^>                 > %~dp0powershell.exe.activation_config
echo.^<configuration^>                                        >> %~dp0powershell.exe.activation_config
echo.  ^<startup useLegacyV2RuntimeActivationPolicy="true"^>  >> %~dp0powershell.exe.activation_config
echo.    ^<supportedRuntime version="v4.0"/^>                 >> %~dp0powershell.exe.activation_config
echo.  ^</startup^>                                           >> %~dp0powershell.exe.activation_config
echo.^</configuration^>                                       >> %~dp0powershell.exe.activation_config
:run
:: point COMPLUS_ApplicationMigrationRuntimeActivationConfigPath to the directory that this cmd file lives in
:: and the directory contains a powershell.exe.activation_config file which matches the executable name powershell.exe
set COMPLUS_ApplicationMigrationRuntimeActivationConfigPath=%~dp0
%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe %*
set COMPLUS_ApplicationMigrationRuntimeActivationConfigPath=

这将允许您启动在 .NET 4.0 下运行的 powershell 控制台实例。

通过检查从 cmd 运行的以下两个命令的输出,您可以看到我的系统上安装了 PowerShell 2.0 的差异。

C:\>powershell -ExecutionPolicy ByPass -Command $PSVersionTable

Name                           Value
----                           -----
CLRVersion                     2.0.50727.5485
BuildVersion                   6.1.7601.17514
PSVersion                      2.0
WSManStackVersion              2.0
PSCompatibleVersions           1.0, 2.0
SerializationVersion           1.1.0.1
PSRemotingProtocolVersion      2.1


C:\>powershell4.cmd -ExecutionPolicy ByPass -Command $PSVersionTable

Name                           Value
----                           -----
PSVersion                      2.0
PSCompatibleVersions           1.0, 2.0
BuildVersion                   6.1.7601.17514
CLRVersion                     4.0.30319.18408
WSManStackVersion              2.0
PSRemotingProtocolVersion      2.1
SerializationVersion           1.1.0.1

【讨论】:

这是迄今为止最好的答案,因为它是一个非常本地化的更改,不会对系统进行任何持久性更改。好东西! 太棒了!你能在这里帮忙吗? ***.com/questions/39801315/… @TimLewis,是否可以将多个语句发送到同一个 ps4.cmd 实例? @johnywhy,向 .cmd 发送多个语句与向 .exe 发送多个语句相同,因为 .cmd 使用 %* 将其所有参数传递给 .exe。但是,这并没有什么不同,因为当 cmd.exe 将参数传递给它正在启动的可执行文件时,您仍然必须小心它如何解析命令行。我会看看你的其他堆栈溢出问题并在那里解决具体问题。 我尝试将此技术与 -Version 命令行参数结合使用 docs.microsoft.com/en-us/powershell/scripting/core-powershell/… 遗憾的是,它不起作用;我的最新版本 PowerShell (5.1.17134.407) 由 $PSVersionTable.PSVersion 确定,而是启动了。【参考方案6】:

这是我用来支持 .NET 2.0 和 .NET 4 程序集的配置文件的内容:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <!-- http://msdn.microsoft.com/en-us/library/w4atty68.aspx -->
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0" />
    <supportedRuntime version="v2.0.50727" />
  </startup>
</configuration>

此外,这是我用来从传入的命令行参数执行脚本的 PowerShell 1.0 兼容代码的简化版本:

class Program 
  static void Main( string[] args ) 
    Console.WriteLine( ".NET " + Environment.Version );

    string script = "& " + string.Join( " ", args );
    Console.WriteLine( script );
    Console.WriteLine( );

    // Simple host that sends output to System.Console
    PSHost host = new ConsoleHost( this );
    Runspace runspace = RunspaceFactory.CreateRunspace( host );

    Pipeline pipeline = runspace.CreatePipeline( );
    pipeline.Commands.AddScript( script );

    try 
      runspace.Open( );
      IEnumerable<PSObject> output = pipeline.Invoke( );
      runspace.Close( );

      // ...
    
    catch( RuntimeException ex ) 
      string psLine = ex.ErrorRecord.InvocationInfo.PositionMessage;
      Console.WriteLine( "error : 0: 12", ex.GetType( ), ex.Message, psLine );
      ExitCode = -1;
    
  

除了上面显示的基本错误处理之外,我们还在脚本中注入了trap 语句以显示额外的诊断信息(类似于Jeffrey Snover 的Resolve-Error 函数)。

【讨论】:

【参考方案7】:

其他答案来自 2012 年之前,他们专注于“破解”PowerShell 1.0 或 PowerShell 2.0 以针对较新版本的 .NET Framework 和公共语言运行时 (CLR)。

但是,正如许多 cmets 中所写的那样,自 2012 年(当 PowerShell 3.0 出现时)以来,一个更好的解决方案是安装最新版本的 PowerShell。它将自动以 CLR v4.0.30319 为目标。这意味着 .NET 4.0、4.5、4.5.1、4.5.2 或 4.6(预计在 2015 年推出),因为所有这些版本都是彼此的就地替换。如果您不确定自己的 PowerShell 版本,请使用 $PSVersionTable 或查看 Determine installed PowerShell version thread。

在撰写本文时,PowerShell 的最新版本是 4.0,它可以是downloaded with the Windows Management Framework (Google search link)。

【讨论】:

Windows Management Framework 4.0 的系统要求(与 3.0 类似)为:Windows 7、Windows Embedded Standard 7、Windows Server 2008 R2、Windows Server 2012。【参考方案8】:

实际上,您可以让 PowerShell 使用 .NET 4 运行 而不会影响其他 .NET 应用程序。我需要这样做才能使用新的 HttpWebRequest“Host”属性,但是更改“OnlyUseLatestCLR”会破坏 Fiddler,因为它不能在 .NET 4 下使用。

PowerShell 的开发人员显然预见到了这种情况的发生,他们添加了一个注册表项来指定它应该使用哪个版本的框架。一个小问题是您需要在更改注册表项之前获得其所有权,因为即使管理员也无权访问。

HKLM:\Software\Microsoft\Powershell\1\PowerShellEngine\RuntimeVersion(64 位和 32 位) HKLM:\Software\Wow6432Node\Microsoft\Powershell\1\PowerShellEngine\RuntimeVersion(64 位机器上的 32 位)

将该键的值更改为所需的版本。请记住,尽管某些管理单元可能不再加载,除非它们与 .NET 4 兼容(WASP 是唯一一个我遇到问题的管理单元,但我并没有真正使用它)。 VMWare、SQL Server 2008、PSCX、Active Directory(Microsoft 和 Quest Software)和 SCOM 都可以正常工作。

【讨论】:

+1 这是一个非常重要的替代方案(并且更好),它比其他 reg 条目会影响所有 .net 应用程序,但此解决方案仅影响 powershell。 在实施“OnlyUseLatestCLR”后,我的 Fiddler 坏了,一些 powershell 脚本由于无法联系某些服务器而不再运行。我在 regedt32 中手动将值更改回 0,现在一切都可以正常工作了。谢谢! 什么是 WASP、PSCX 和 SCOM(在此上下文中)?【参考方案9】:

如果您不想修改注册表或 app.config 文件,另一种方法是创建一个简单的 .NET 4 控制台应用程序,该应用程序模仿 PowerShell.exe 的功能并托管 PowerShell ConsoleShell。

见Option 2 – Hosting Windows PowerShell yourself

首先,添加对 System.Management.AutomationMicrosoft.PowerShell.ConsoleHost 程序集的引用,这些程序集可以在 %programfiles%\Reference Assemblies 下找到\Microsoft\WindowsPowerShell\v1.0

然后使用以下代码:

using System;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell;

namespace PSHostCLRv4

    class Program
    
        static int Main(string[] args)
        
            var config = RunspaceConfiguration.Create();
                return ConsoleShell.Start(
                config,
                "Windows PowerShell - Hosted on CLR v4\nCopyright (C) 2010 Microsoft Corporation. All rights reserved.",
                "",
                args
            );
        
    

【讨论】:

【参考方案10】:

作为另一种选择,最新的PoshConsole 版本包括针对.NET 4 RC 的二进制文件(对 RTM 版本运行良好),无需任何配置。

【讨论】:

【参考方案11】:

只需运行 powershell.exe 并将 COMPLUS_version 环境变量设置为 v4.0.30319。 例如,来自 cmd.exe 或 .bat-file:

set COMPLUS_version=v4.0.30319
powershell -file c:\scripts\test.ps1

【讨论】:

以上是关于如何使用 .NET 4 运行时运行 PowerShell?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Mono 在 XSP 上运行 .NET 4.5?

当 Fiddler 运行 .Net 4.5 时,WCF 服务正在工作

.NET 3.5 运行时和 .NET 4 运行时兼容性

ASP.NET Core EF Add-Migration 命令不起作用

Windows 10 中的 CoCreateInstance 错误 0x80131700:无法使用 .NET 运行时 4.0

如何使用 .Net 4.0 中包含的 HttpClient 类将文件上传到在 IIS Express 中运行的 Asp.Net MVC 4.0 操作