【问题标题】:How do I use Powershell to add/remove references to a csproj?如何使用 Powershell 添加/删除对 csproj 的引用?
【发布时间】:2012-01-22 18:10:49
【问题描述】:

关于this previous question 我正在尝试创建一个批处理文件,作为一部分必须删除并添加对 XML *.csproj 文件的引用。我看过thisthisthisthis 上一个问题,但作为一个powershell n00b 无法让它工作(到目前为止)。

谁能帮我解决以下问题?我想删除 VS2010 csproj 文件 (XML) 中的两个特定引用并添加一个新引用。

我打开了csproj,可以在以下位置找到参考

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <!--          ...         -->
  <!-- Omitted for brevity  -->
  <!--          ...         -->

  <ItemGroup Condition="'$(BuildingInsideVisualStudio)' == 'true'">
    <AvailableItemName Include="Effect" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\SomeDirectory\SomeProjectFile.csproj">
      <Project>{AAB784E4-F8C6-4324-ABC0-6E9E0F73E575}</Project>
      <Name>SomeProject</Name>
    </ProjectReference>
    <ProjectReference Include="..\AnotherDirectory\AnotherProjectFile.csproj">
      <Project>{B0AA6A94-6784-4221-81F0-244A68C374C0}</Project>
      <Name>AnotherProject</Name>
    </ProjectReference>
  </ItemGroup>

  <!--          ...         -->
  <!-- Omitted for brevity  -->
  <!--          ...         -->

</Project>

基本上我想:

  • 删除这两个引用
  • 插入对由相对路径指定的预编译 DLL 的新引用
  • 或将程序集引用位置添加到相对路径指定的项目中

作为一个非常简单的示例,我尝试了以下 powershell 脚本来删除所有 ProjectReference 节点。我将路径传递给 csproj 作为参数。我收到错误Cannot validate the argument 'XML'. The Argument is null or empty。我可以确认它正在加载 csproj 并将其保存在原地未修改,因此路径是正确的。

param($path)
$MsbNS = @{msb = 'http://schemas.microsoft.com/developer/msbuild/2003'}

function RemoveElement([xml]$Project, [string]$XPath, [switch]$SingleNode)
{
    $xml | Select-Xml -XPath $XPath | ForEach-Object{$_.Node.ParentNode.RemoveAll()}
}

$proj = [xml](Get-Content $path)
[System.Console]::WriteLine("Loaded project {0} into {1}", $path, $proj)

RemoveElement $proj "//ProjectReference" -SingleNode

    # Also tried
    # RemoveElement $proj "/Project/ItemGroup/ProjectReference[@Include=`'..\SomeDirectory\SomeProjectFile.csproj`']" -SingleNode
    # but complains cannot find XPath

$proj.Save($path)

我做错了什么?欢迎任何 cmets/建议 :)

【问题讨论】:

    标签: xml visual-studio-2010 powershell csproj


    【解决方案1】:

    我认为问题在于您的 XML 文件有一个默认命名空间 xmlns="http://schemas.microsoft.com/developer/msbuild/2003"。这会导致 XPath 出现问题。所以你的 XPath //ProjectReference 将返回 0 个节点。有两种方法可以解决这个问题:

    1. 使用命名空间管理器。
    2. 使用与命名空间无关的 XPath。

    这是您可以使用命名空间管理器的方法:

    $nsmgr = New-Object System.Xml.XmlNamespaceManager -ArgumentList $proj.NameTable
    $nsmgr.AddNamespace('a','http://schemas.microsoft.com/developer/msbuild/2003')
    $nodes = $proj.SelectNodes('//a:ProjectReference', $nsmgr)
    

    或者:

    Select-Xml '//a:ProjectReference' -Namespace $nsmgr
    

    以下是使用与命名空间无关的 XPath 的方法:

    $nodes = $proj.SelectNodes('//*[local-name()="ProjectReference"]')
    

    或者:

    $nodes = Select-Xml '//*[local-name()="ProjectReference"]'
    

    第二种方法可能很危险,因为如果有多个命名空间,它可能会选择错误的节点,但不是你的情况。

    【讨论】:

    • 哇,很有帮助!让我试试这个。谢谢
    • 第一次尝试,我打电话给proj.NameTable' and nsmgr.AddNamespace`,得到System.Xml.Nametable doesn't contain a method named AddNamespace
    • duh [System.Xml.XmlNamespaceManager] $nsmgr = $proj.NameTable 有效。好的,通过这个来删除节点。似乎正在选择没有错误的节点
    • @Dr.AndrewBurnett-Thompson 我应该指出这是未经测试的。我更新了我的答案来解决这个问题。
    • 不用担心,已修复。我使用上面的测试 XML 创建了一个 powershell,并一直在使用它,直到将其删除。您的 AddNamespace 是正确的 - 它找到了节点并可以将其删除。谢谢!
    【解决方案2】:

    为了后代,我将提供完整的 powershell 脚本来添加和删除对 csproj 文件的引用。 如果您觉得这很有用,请投票给 Andy Arismedi 的答案,因为他帮助我找到了答案。随时给我+1,当你在它的时候;-)

    AddReference.ps1

    # Calling convension:
    #   AddReference.PS1 "Mycsproj.csproj", 
    #                    "MyNewDllToReference.dll", 
    #                    "MyNewDllToReference"
    param([String]$path, [String]$dllRef, [String]$refName)
    
    $proj = [xml](Get-Content $path)
    [System.Console]::WriteLine("")
    [System.Console]::WriteLine("AddReference {0} on {1}", $refName, $path)
    
    # Create the following hierarchy
    #  <Reference Include='{0}'>
    #     <HintPath>{1}</HintPath>
    #  </Reference>
    # where (0) is $refName and {1} is $dllRef
    
    $xmlns = "http://schemas.microsoft.com/developer/msbuild/2003"
    $itemGroup = $proj.CreateElement("ItemGroup", $xmlns);
    $proj.Project.AppendChild($itemGroup);
    
    $referenceNode = $proj.CreateElement("Reference", $xmlns);
    $referenceNode.SetAttribute("Include", $refName);
    $itemGroup.AppendChild($referenceNode)
    
    $hintPath = $proj.CreateElement("HintPath", $xmlns);
    $hintPath.InnerXml = $dllRef
    $referenceNode.AppendChild($hintPath)
    
    $proj.Save($path)
    

    RemoveReference.ps1

    # Calling Convention
    #   RemoveReference.ps1 "MyCsProj.csproj" 
    #   "..\SomeDirectory\SomeProjectReferenceToRemove.dll"
    param($path, $Reference)
    
    $XPath = [string]::Format("//a:ProjectReference[@Include='{0}']", $Reference)   
    
    [System.Console]::WriteLine("");
    [System.Console]::WriteLine("XPATH IS {0}", $XPath) 
    [System.Console]::WriteLine("");
    
    $proj = [xml](Get-Content $path)
    [System.Console]::WriteLine("Loaded project {0} into {1}", $path, $proj)
    
    [System.Xml.XmlNamespaceManager] $nsmgr = $proj.NameTable
    $nsmgr.AddNamespace('a','http://schemas.microsoft.com/developer/msbuild/2003')
    $node = $proj.SelectSingleNode($XPath, $nsmgr)
    
    if (!$node)
    { 
        [System.Console]::WriteLine("");
        [System.Console]::WriteLine("Cannot find node with XPath {0}", $XPath) 
        [System.Console]::WriteLine("");
        exit
    }
    
    [System.Console]::WriteLine("Removing node {0}", $node)
    $node.ParentNode.RemoveChild($node);
    
    $proj.Save($path)
    

    【讨论】:

    • 仅供参考。您可以使用 Write-Host cmdlet 而不是 [system.console]::WriteLine,例如Write-Host ("This is {0} typing" -f "less")-f 用于字符串格式化:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-13
    相关资源
    最近更新 更多