如何在.NET 4运行时中运行PowerShell?


234

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

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

如何在.NET 4运行时中运行PowerShell?



8
如今,最简单的解决方案是安装使用CLRVersion:4.0.30319.1。的Powershell 3.0 CTP。
jon Z

2
仍然对PowerShell 2感兴趣的人,请参见Tim Lewis的答案,以获取不需要编辑任何计算机范围内配置的本地化解决方案。
埃里克·埃斯基尔森

1
对于非系统范围和无文件的解决方案,请参见以下答案
vkrzv

Answers:


147

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的应用程序



9
需要明确的是,powershell.exe(控制台主机应用程序)本身是一个本机应用程序-不受管理。
基思·希尔

4
我从上面发现了我的问题。在64位操作系统上运行时,必须将配置文件放在64位目录中。32位Powershell可执行文件似乎可以从那里进行更改。
克里斯·麦肯齐

11
只是一个小建议。当您不再需要注册表项时,请删除它们。我只是浪费了很多时间试图找出为什么我无法构建我正在从事的.NET 3.5项目。
克拉克

7
如果您要进行多目标处理(即在VS2010中编写.NET 2.0应用程序),则建议的注册表修改解决方案会产生讨厌的副作用。谨防。
Todd Sprang

9
请注意,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的本机支持。
Timbo,2012年

238

我发现的最佳解决方案是在博客文章《使用PowerShell将.NET的较新版本》中。这使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> 

其他快速设置注意事项:

位置和文件在某种程度上取决于平台。但是,它将为您提供如何使解决方案为您服务的内在要旨。

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

23
绝对是正确的方法。这仅会更改Powershell的行为,而不会更改计算机上的所有其他.NET应用程序的行为……
Erik A. Brandstadmoen 2011年

4
这很好,但会影响您的所有PowerShell。如果只需要其中一些功能,请复制powershell文件夹,然后在此处编辑文件。
马特

8
如上所述,我添加了一个文件。但是,我无法再在该文件存在的情况下运行PowerShell-我收到错误消息“文件的卷已从外部更改,因此打开的文件不再有效。” 有任何想法吗?
2011年

13
@JoshL-在64位系统上,即使您尝试运行64位Powershell,我也发现.exe.config需要进入SysWOW64 \ WindowsPowershell(32位文件夹)中。否则,您会收到“外部更改”错误。
山姆

4
powershell.exe.config需要放在两个位置。...C:\ Windows \ System32 \ WindowsPowerShell \ v1.0 \和C:\ Windows \ SysWOW64 \ WindowsPowerShell \ v1.0 \
Jonesome恢复Monica

28

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

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

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


关于使用注册表项的非常重要的一点。幸运的是,带有配置文件的启动器应用程序运行正常。我们的脚本主要使用文件系统命令和直接的.NET调用,而对于损坏的命令,我们没有发现任何问题。由于.NET 4在很大程度上与.NET 2.0向后兼容,因此我认为不会出现很多中断的命令(尽管小心一点也不会造成伤害:)。
XLII皇帝2010年


21

如果您仍然使用PowerShell v1.0或v2.0,这是我对Jason Stangroome出色答案的理解。

powershell4.cmd使用以下内容在路径上创建一个位置:

@echo off
:: http://stackoverflow.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

3
到目前为止,这是最好的答案,因为它是非常本地化的更改,不会对系统进行任何持久更改。好东西!
塞巴斯蒂安


@TimLewis,是否可以将多个语句发送到同一ps4.cmd实例?
约翰尼,为什么

@johnywhy,向.cmd发送多个语句与向.exe发送多个语句相同,因为.cmd使用%*将其所有参数传递到.exe。但是,这没有什么区别,因为当cmd.exe将参数传递给正在启动的可执行文件时,您仍然必须注意cmd.exe如何解析命令行。我将看一下您的其他堆栈溢出问题,并在其中解决具体问题。
蒂姆·刘易斯

我试图将这种技术与-Version命令行参数docs.microsoft.com/en-us/powershell/scripting/core-powershell/结合使用。我的最新版本的PowerShell(5.1.17134.407)由$ PSVersionTable.PSVersion确定。
eisenpony

17

这是我用来支持.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}: {1}{2}", ex.GetType( ), ex.Message, psLine );
      ExitCode = -1;
    }
  }
}

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


10

其他答案来自2012年之前,它们的重点是“攻击” PowerShell 1.0或PowerShell 2.0,以定位较新版本的.NET Framework和公共语言运行时(CLR)。

但是,正如许多评论中所述,自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请使用或查看“ 确定已安装的PowerShell版本”线程

在撰写本文时,PowerShell的最新版本是4.0,可以通过Windows Management Framework(Google搜索链接)下载


2
对于Windows管理框架4.0的系统要求(它们是3.0类似)为:Windows 7,Windows嵌入式标准7和Windows Server 2008 R2和Windows Server 2012
彼得·莫特森

9

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

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

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

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


+1这是一个非常重要的替代方法(并且更好),它会影响所有.net应用程序的其他注册表项,但是此解决方案仅影响powershell。
Christian Mikkelsen'3

实施“ OnlyUseLatestCLR”后,我的Fiddler崩溃了,由于无法联系某些服务器,一些powershell脚本不再运行。我在regedt32中手动将值更改回0,现在重新工作。谢谢!
内维尔

什么是WASP,PSCX和SCOM(在此情况下)?
彼得·莫滕森

7

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

请参阅选项2 –自己托管Windows PowerShell

首先,添加对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
            );
        }
    }
}


1

只需将powershell.exe的COMPLUS_version环境变量设置为即可v4.0.30319。例如,从cmd.exe或.bat文件中:

set COMPLUS_version=v4.0.30319
powershell -file c:\scripts\test.ps1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.