Token导航 LogoToken导航TokenDH.com
前端设计需要联网github未标认证来源可访问许可证需确认审计通过

dotnet-msbuild-authoringdotnet msbuild 创作

Agent Skill

用于辅助安全审计、权限检查、凭据风险、认证流程和常见漏洞排查。它适合让 Agent 梳理敏感配置、检查依赖风险、分析鉴权逻辑或生成安全复核清单。使用时不能把工具输出直接当最终结论,涉及密钥、令牌、用户数据或生产系统时,应先确认最小权限、脱敏方式和操作边界。

总安装

396

周安装

16

GitHub Stars

15

下载量

124
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:dotnet-msbuild-authoring(dotnet msbuild 创作)
来源仓库:https://github.com/wshaddix/dotnet-skills
仓库路径:skills/dotnet-msbuild-authoring
安装命令:
npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-msbuild-authoring
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-msbuild-authoring

简介

用于辅助安全审计、权限检查和凭据风险排查。

  • 适合梳理敏感配置或生成安全复核清单。
  • 使用时不能将工具输出直接作为结论。dotnet-msbuild-authoring 属于前端设计类 Skill,可作为该场景下的辅助能力补充。
  • 涉及密钥或用户数据时应确认最小权限。
  • 注意:不覆盖 CI/CD 流程集成等内容。

SKILL.md

dotnet-msbuild-authoring

Guidance for authoring MSBuild project system elements: custom targets with BeforeTargets/AfterTargets/DependsOnTargets, incremental build with Inputs/Outputs, props vs targets import ordering, items and item metadata (Include/Exclude/Update/Remove), conditions, property functions, well-known metadata, and advanced Directory.Build.props/Directory.Build.targets patterns.

Version assumptions:.NET 8.0+ SDK (MSBuild 17.8+). All examples use SDK-style projects.

Scope boundary: This skill owns MSBuild authoring fundamentals -- custom targets, import ordering, items, conditions, property functions, and advanced Directory.Build patterns. Basic solution layout and shared configuration (Directory.Build.props structure, CPM,.editorconfig) is owned by [skill:dotnet-project-structure]. MSBuild error interpretation and CI drift diagnosis is owned by [skill:dotnet-build-analysis].

Cross-references: [skill:dotnet-project-structure] for solution layout and basic Directory.Build.props structure, [skill:dotnet-build-analysis] for interpreting MSBuild errors and CI drift.


Custom Targets

Targets are the unit of execution in MSBuild. Each target runs a sequence of tasks and can declare ordering relationships with other targets.

Defining a Custom Target

<Target Name="PrintBuildInfo"
        BeforeTargets="Build">
  <Message Importance="high"
           Text="Building $(MSBuildProjectName) v$(Version) for $(TargetFramework)" />
</Target>

Ordering: BeforeTargets, AfterTargets, DependsOnTargets

Three mechanisms control target execution order:

MechanismEffectUse when
BeforeTargets="X"Runs this target before XInjecting into an existing pipeline (e.g., run before Build)
AfterTargets="X"Runs this target after XPost-processing (e.g., copy output after Publish)
DependsOnTargets="A;B"Ensures A and B run before this targetDeclaring prerequisite targets within your own target graph
<!-- Run license check before compile -->
<Target Name="CheckLicenseHeaders"
        BeforeTargets="CoreCompile">
  <Exec Command="dotnet tool run license-check -- --verify" />
</Target>

<!-- Copy native libs after publish -->
<Target Name="CopyNativeLibs"
        AfterTargets="Publish">
  <Copy SourceFiles="@(NativeLibrary)"
        DestinationFolder="$(PublishDir)runtimes/%(NativeLibrary.RuntimeIdentifier)/native/" />
</Target>

<!-- Composite target with dependencies -->
<Target Name="FullValidation"
        DependsOnTargets="CheckLicenseHeaders;RunApiCompat">
  <Message Importance="high" Text="All validations passed." />
</Target>

Prefer BeforeTargets/AfterTargets over DependsOnTargets for injecting into the standard build pipeline. DependsOnTargets is best for orchestrating your own custom target graph.

Extending Existing DependsOn Lists

SDK targets expose *DependsOn properties for extension. Append your target name rather than replacing the list:

<PropertyGroup>
  <BuildDependsOn>$(BuildDependsOn);GenerateVersionInfo</BuildDependsOn>
</PropertyGroup>

<Target Name="GenerateVersionInfo">
  <WriteLinesToFile File="$(IntermediateOutputPath)Version.g.cs"
                    Lines="[assembly: System.Reflection.AssemblyInformationalVersion("$(InformationalVersion)")]"
                    Overwrite="true" />
  <ItemGroup>
    <Compile Include="$(IntermediateOutputPath)Version.g.cs" />
  </ItemGroup>
</Target>

Incremental Build with Inputs/Outputs

Targets with Inputs and Outputs only run when outputs are missing or older than inputs. This is critical for build performance.

<Target Name="GenerateEmbeddedResources"
        BeforeTargets="CoreCompile"
        Inputs="@(EmbeddedTemplate)"
        Outputs="@(EmbeddedTemplate->'$(IntermediateOutputPath)%(Filename).g.cs')">
  <Exec Command="dotnet tool run template-gen -- %(EmbeddedTemplate.Identity) -o $(IntermediateOutputPath)%(EmbeddedTemplate.Filename).g.cs" />
  <ItemGroup>
    <Compile Include="$(IntermediateOutputPath)%(EmbeddedTemplate.Filename).g.cs" />
  </ItemGroup>
</Target>

How incrementality works:

  1. MSBuild compares timestamps of Inputs items against Outputs items.
  2. If all outputs exist and are newer than all inputs, the target is skipped entirely.
  3. If any input is newer than any output, the full target runs.

Common incrementality failures:

  • Missing Outputs: Target runs every build. Always pair Inputs with Outputs.
  • Volatile outputs: If another target writes to the output path mid-build, timestamps reset and trigger unnecessary rebuilds.
  • Generator side effects: Code generators that write unconditionally (even when content unchanged) break incrementality. Write to a temp file and copy only if content differs.
  • File copy timestamps: Copy task with SkipUnchangedFiles="true" preserves timestamps; without it, every copy updates the timestamp.

Props vs Targets: Import Ordering

MSBuild evaluates project files in a specific order. Understanding this is essential for correct customization.

Evaluation Order

1. Directory.Build.props          (imported by SDK early)
2. <Project Sdk="...">            (SDK props imported)
3. Explicit <Import> in project   (your .props imports)
4. Project body <PropertyGroup>,  (project-level properties)
   <ItemGroup>
5. SDK targets imported            (SDK targets)
6. Directory.Build.targets         (imported by SDK late)
7. Explicit .targets imports       (your .targets imports)

Rules

  • .props files set default property values and define items. They run before the project body, so project-level properties can override them.
  • .targets files define targets and finalize item lists. They run after the project body, so they see all project-level settings.
<!-- MyDefaults.props -- sets defaults, project can override -->
<Project>
  <PropertyGroup>
    <TreatWarningsAsErrors Condition="'$(TreatWarningsAsErrors)' == ''">true</TreatWarningsAsErrors>
    <Nullable Condition="'$(Nullable)' == ''">enable</Nullable>
  </PropertyGroup>
</Project>
<!-- MyTargets.targets -- runs after project evaluation -->
<Project>
  <Target Name="ValidatePackageMetadata"
          BeforeTargets="Pack"
          Condition="'$(IsPackable)' == 'true'">
    <Error Condition="'$(Description)' == ''"
           Text="Description is required for packable projects." />
  </Target>
</Project>

Key rule: Properties in .props files should use Condition="'$(Prop)' == ''" to allow project-level overrides. Properties in .targets files are evaluated last and cannot be overridden by the project.


Items and Item Metadata

Items are named collections of files or values. Each item can carry metadata (key-value pairs).

Item Operations

<ItemGroup>
  <!-- Include: add items matching a glob -->
  <Content Include="assets/**/*.png" />

  <!-- Exclude: remove items matching a pattern from the Include -->
  <Compile Include="**/*.cs" Exclude="**/*.generated.cs" />

  <!-- Update: modify metadata on existing items (does not add new items) -->
  <Content Update="assets/logo.png">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <Pack>true</Pack>
    <PackagePath>contentFiles/any/any/</PackagePath>
  </Content>

  <!-- Remove: remove items matching a pattern from the item list -->
  <Compile Remove="legacy/**/*.cs" />
</ItemGroup>

**SDK-style projects auto-include *.cs files. Do not add a `<Compile Include="/*.cs" /> -- it causes NETSDK1022 duplicate items. Use Remove first, then Include` for conditional compilation scenarios:

<!-- TFM-conditional compilation -->
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
  <Compile Remove="Polyfills/**/*.cs" />
</ItemGroup>

Well-Known Metadata

Every item has built-in metadata accessible via %(ItemName.MetadataName):

MetadataValueExample for src/Models/Order.cs
%(FullPath)Absolute path/repo/src/Models/Order.cs
%(RootDir)Root directory/
%(Directory)Directory relative to rootrepo/src/Models/
%(Filename)File name without extensionOrder
%(Extension)File extension.cs
%(RecursiveDir)Part matched by ** in globModels/ (if glob was src/**/*.cs)
%(Identity)Item spec as declaredsrc/Models/Order.cs

Item Metadata and Batching

Custom metadata enables per-item behavior through MSBuild batching:

<ItemGroup>
  <DbMigration Include="migrations/*.sql">
    <TargetDb>main</TargetDb>
  </DbMigration>
  <DbMigration Include="migrations/audit/*.sql">
    <TargetDb>audit</TargetDb>
  </DbMigration>
</ItemGroup>

<!-- Batching: the task runs once per unique %(TargetDb) value -->
<Target Name="RunMigrations">
  <Exec Command="sqlcmd -d %(DbMigration.TargetDb) -i %(DbMigration.Identity)"
        Condition="'@(DbMigration)' != ''" />
</Target>

%(Metadata) in a task attribute triggers batching. MSBuild groups items by the metadata value and invokes the task once per group.


Conditions

Conditions control whether properties, items, targets, and tasks are evaluated.

Property Conditions

<PropertyGroup>
  <!-- Default: set only if not already defined -->
  <LangVersion Condition="'$(LangVersion)' == ''">latest</LangVersion>

  <!-- TFM condition -->
  <DefineConstants Condition="$(TargetFramework.StartsWith('net8'))">$(DefineConstants);NET8_OR_GREATER</DefineConstants>

  <!-- Configuration condition -->
  <Optimize Condition="'$(Configuration)' == 'Release'">true</Optimize>

  <!-- OS condition -->
  <RuntimeIdentifier Condition="$([MSBuild]::IsOSPlatform('Windows'))">win-x64</RuntimeIdentifier>
</PropertyGroup>

Item and Target Conditions

<!-- Conditional item inclusion -->
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
  <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
</ItemGroup>

<!-- Conditional target execution -->
<Target Name="SignAssembly"
        AfterTargets="Build"
        Condition="'$(Configuration)' == 'Release' AND '$(SignAssembly)' == 'true'">
  <Exec Command="signtool sign /fd SHA256 $(TargetPath)" />
</Target>

Condition Operators

OperatorExample
== / !='$(Config)' == 'Release'
AND / OR'$(A)' == '1' AND '$(B)'!= ''
! (negation)!Exists('$(OutDir)')
Exists()Exists('$(SolutionDir)global.json')
HasTrailingSlash()HasTrailingSlash('$(OutputPath)')

Always single-quote both sides of comparisons. '$(Prop)' == 'value' is correct. Unquoted comparisons fail when the property is empty.


Property Functions

MSBuild properties can call.NET static methods and MSBuild intrinsic functions inline.

.NET Static Method Calls

<PropertyGroup>
  <!-- String manipulation -->
  <NormalizedName>$([System.String]::Copy('$(PackageId)').ToLowerInvariant())</NormalizedName>

  <!-- Path combination (prefer over string concatenation) -->
  <ToolPath>$([System.IO.Path]::Combine('$(MSBuildThisFileDirectory)', 'tools', 'analyzer.dll'))</ToolPath>

  <!-- GUID generation -->
  <BuildId>$([System.Guid]::NewGuid().ToString('N'))</BuildId>

  <!-- Regex replacement -->
  <CleanVersion>$([System.Text.RegularExpressions.Regex]::Replace('$(Version)', '-.*$', ''))</CleanVersion>

  <!-- Environment variable -->
  <CiServer>$([System.Environment]::GetEnvironmentVariable('CI'))</CiServer>
</PropertyGroup>

MSBuild Intrinsic Functions

<PropertyGroup>
  <!-- OS detection -->
  <IsWindows>$([MSBuild]::IsOSPlatform('Windows'))</IsWindows>
  <IsLinux>$([MSBuild]::IsOSPlatform('Linux'))</IsLinux>
  <IsMacOS>$([MSBuild]::IsOSPlatform('OSX'))</IsMacOS>

  <!-- Arithmetic -->
  <NextVersion>$([MSBuild]::Add($(PatchVersion), 1))</NextVersion>

  <!-- Version comparison (MSBuild 17.0+) -->
  <HasModernSdk>$([MSBuild]::VersionGreaterThanOrEquals('$(NETCoreSdkVersion)', '8.0.100'))</HasModernSdk>

  <!-- Stable hash for deterministic output -->
  <InputHash>$([MSBuild]::StableStringHash('$(InputFile)'))</InputHash>

  <!-- Path resolution: find file by walking up directory tree -->
  <SharedPropsPath>$([MSBuild]::GetPathOfFileAbove('SharedConfig.props', '$(MSBuildProjectDirectory)'))</SharedPropsPath>

  <!-- Normalize path separators -->
  <SafePath>$([MSBuild]::NormalizePath('$(MSBuildProjectDirectory)', '..', 'shared'))</SafePath>
</PropertyGroup>

Useful MSBuild Properties

PropertyValue
$(MSBuildProjectDirectory)Directory containing the current .csproj
$(MSBuildThisFileDirectory)Directory containing the current .props/.targets file
$(MSBuildProjectName)Project name without extension
$(IntermediateOutputPath)obj/ output path
$(OutputPath)bin/ output path
$(TargetFramework)Current TFM (e.g., net10.0)
$(TargetFrameworks)Multi-TFM list (e.g., net8.0;net10.0)
$(Configuration)Debug or Release
$(SolutionDir)Solution directory (only set when building from solution)

Use $(MSBuildThisFileDirectory) in .props/.targets files, not $(MSBuildProjectDirectory). The former resolves to the file's own location, which is correct when the file is imported from a NuGet package or a different directory.


Directory.Build.props/targets Advanced Patterns

Basic Directory.Build layout is covered in [skill:dotnet-project-structure]. This section covers advanced patterns for multi-repo and monorepo scenarios.

Import Chain with GetPathOfFileAbove

In monorepos with nested directories, each level can define its own Directory.Build.props that chains to the parent:

repo/
  Directory.Build.props            (repo-wide defaults)
  src/
    Directory.Build.props          (src-specific overrides)
    MyApp/
      MyApp.csproj
  tests/
    Directory.Build.props          (test-specific overrides)
    MyApp.Tests/
      MyApp.Tests.csproj
<!-- src/Directory.Build.props -->
<Project>
  <!-- Chain to parent Directory.Build.props (with existence guard) -->
  <PropertyGroup>
    <_ParentBuildProps>$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)..'))</_ParentBuildProps>
  </PropertyGroup>
  <Import Project="$(_ParentBuildProps)" Condition="'$(_ParentBuildProps)' != ''" />

  <PropertyGroup>
    <!-- Source-specific overrides -->
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
  </PropertyGroup>
</Project>
<!-- tests/Directory.Build.props -->
<Project>
  <!-- Chain to parent Directory.Build.props (with existence guard) -->
  <PropertyGroup>
    <_ParentBuildProps>$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)..'))</_ParentBuildProps>
  </PropertyGroup>
  <Import Project="$(_ParentBuildProps)" Condition="'$(_ParentBuildProps)' != ''" />

  <PropertyGroup>
    <IsPackable>false</IsPackable>
    <IsTestProject>true</IsTestProject>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Test.Sdk" />
    <PackageReference Include="xunit.v3" />
    <PackageReference Include="xunit.runner.visualstudio" />
  </ItemGroup>
</Project>

Condition Guards

Prevent property values from being overridden by child imports:

<!-- repo/Directory.Build.props -->
<Project>
  <PropertyGroup>
    <!-- Defaults: can be overridden by child Directory.Build.props or project -->
    <TreatWarningsAsErrors Condition="'$(TreatWarningsAsErrors)' == ''">true</TreatWarningsAsErrors>
    <Nullable Condition="'$(Nullable)' == ''">enable</Nullable>
    <ImplicitUsings Condition="'$(ImplicitUsings)' == ''">enable</ImplicitUsings>
  </PropertyGroup>
</Project>

Rule: Properties in .props files should use the Condition="'$(Prop)' == ''" guard so that inner .props files and project-level properties can override them. Properties you want to enforce unconditionally belong in Directory.Build.targets (which evaluates last).

Preventing Double Imports

When multiple Directory.Build.props files chain upward, a shared import could be evaluated twice. Use a sentinel property to guard against this:

<!-- shared/Common.props -->
<Project>
  <!-- Guard: only evaluate once -->
  <PropertyGroup Condition="'$(_CommonPropsImported)' != 'true'">
    <_CommonPropsImported>true</_CommonPropsImported>
    <Authors>My Company</Authors>
    <Company>My Company</Company>
    <Copyright>Copyright (c) My Company. All rights reserved.</Copyright>
  </PropertyGroup>
</Project>

The sentinel and content properties must be in the same PropertyGroup with the != 'true' condition. Putting content in a separate block with == 'true' does not prevent re-evaluation -- it runs on every import because the sentinel is already set.

A cleaner approach uses Condition on the <Import> element:

<!-- Only import if not already imported -->
<Import Project="$(SharedPropsPath)"
        Condition="'$(_CommonPropsImported)' != 'true' AND Exists('$(SharedPropsPath)')" />

Enforcing Settings in Directory.Build.targets

Properties set in .targets files cannot be overridden by project-level PropertyGroup elements because they evaluate after the project body:

<!-- Directory.Build.targets -->
<Project>
  <!-- Enforced: projects cannot override these -->
  <PropertyGroup>
    <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
    <AnalysisLevel>latest-recommended</AnalysisLevel>
  </PropertyGroup>

  <!-- Conditional enforcement: only for src projects -->
  <PropertyGroup Condition="'$(IsTestProject)' != 'true' AND '$(IsPackable)' != 'false'">
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
  </PropertyGroup>
</Project>

Agent Gotchas

  1. Unquoted condition comparisons. Always quote both sides: '$(Prop)' == 'value'. Unquoted $(Prop) == value fails silently when the property is empty or contains spaces.
  2. Using $(MSBuildProjectDirectory) in shared .props/.targets files. This resolves to the importing project's directory, not the file's own directory. Use $(MSBuildThisFileDirectory) to reference paths relative to the .props/.targets file itself.
  3. Setting properties in .targets and expecting project overrides. Properties in .targets evaluate after the project body and override project-level values. If a property should be overridable, set it in .props with a Condition="'$(Prop)' == ''" guard.
  4. Adding `<Compile Include="/*.cs" /> in SDK-style projects.** SDK-style projects auto-include all *.cs files. Explicit inclusion causes NETSDK1022 duplicate items. Use Remove then Include` for conditional scenarios.
  5. Missing Outputs on targets with Inputs. A target with Inputs but no Outputs runs every build. Always pair them for incremental behavior.
  6. Using $(SolutionDir) in .props/.targets files. This property is only set when building through a solution file. Command-line dotnet build MyProject.csproj leaves it empty. Use $([MSBuild]::GetPathOfFileAbove('*.sln', '$(MSBuildProjectDirectory)')) or pass paths relative to $(MSBuildThisFileDirectory).
  7. Putting items in PropertyGroup or properties in ItemGroup. Items (using Include=) must be in <ItemGroup>. Properties (using element value) must be in <PropertyGroup>. Mixing them produces silent evaluation failures.
  8. Forgetting Condition guard on parent import chain. GetPathOfFileAbove returns empty string when no file is found. The <Import> must have Condition="Exists('$(ResolvedPath)')" or the build fails with a file-not-found error.

References

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

34.89%
按下载量换算43

Claude

27.88%
按下载量换算35

Cursor

18.96%
按下载量换算24

Gemini CLI

9.02%
按下载量换算11

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills