我正在更新管理一些 .NET 程序集的 PowerShell 脚本。该脚本是为针对 .NET 2(与 PowerShell 运行的框架版本相同)构建的程序集编写的,但现在需要使用 .NET 4 程序集以及 .NET 2 程序集。
由于 .NET 4 支持运行针对旧版本框架构建的应用程序,因此当我需要针对 .NET 4 程序集运行 PowerShell 时,似乎最简单的解决方案是使用 .NET 4 运行时启动 PowerShell。
如何使用 .NET 4 运行时运行 PowerShell?
我发现的最佳解决方案是在博文中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\
路径将类似于(示例)C:\Windows\System32\WindowsPowerShell\v1.0\
放置配置的文件名是:powershell.exe.config 如果您的 PowerShell.exe 正在执行(如果需要,请创建配置文件)。如果 PowerShellISE.Exe 正在运行,那么您需要将其配套配置文件创建为 PowerShellISE.Exe.config
如果 PowerShellISE.Exe 正在运行,那么您需要将其配套配置文件创建为 PowerShellISE.Exe.config
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 的应用程序
请非常小心使用注册表项方法。这些是机器范围的密钥,可强制将所有应用程序迁移到 .NET 4.0。
如果强制迁移,许多产品将无法工作,这是一种测试辅助手段,而不是生产质量机制。 Visual Studio 2008 和 2010、MSBuild、turbotax 和许多网站、SharePoint 等不应自动迁移。
如果您需要将 PowerShell 与 4.0 一起使用,则应使用配置文件在每个应用程序的基础上完成,您应与 PowerShell 团队核实确切的建议。这可能会破坏一些现有的 PowerShell 命令。
如果您只需要在 .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
如果您仍然停留在 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
以下是我用来支持 .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 函数)。
其他答案来自 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
或查看 Determine installed PowerShell version thread。 编辑:还有thread Which .NET version is my PowerShell script using?
在撰写本文时,最新版本的 PowerShell 是 4.0,它可以是 downloaded with the Windows Management Framework (Google search link)。
实际上,您可以让 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 都可以正常工作。
如果您不想修改注册表或 app.config 文件,另一种方法是创建一个简单的 .NET 4 控制台应用程序,该应用程序模仿 PowerShell.exe 的功能并托管 PowerShell ConsoleShell。
请参阅Option 2 – Hosting Windows PowerShell yourself
首先,添加对 System.Management.Automation 和 Microsoft.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
);
}
}
}
只需在 COMPLUS_version
环境变量设置为 v4.0.30319
的情况下运行 powershell.exe。例如,来自 cmd.exe 或 .bat 文件:
set COMPLUS_version=v4.0.30319
powershell -file c:\scripts\test.ps1
不定期副业成功案例分享