Skip to content

Instantly share code, notes, and snippets.

@sayedihashimi
Last active August 29, 2015 14:04
Show Gist options
  • Save sayedihashimi/f2048fd957f860f38ecd to your computer and use it in GitHub Desktop.
Save sayedihashimi/f2048fd957f860f38ecd to your computer and use it in GitHub Desktop.
Uses MSBuild to remove items from the project file
[cmdletbinding()]
param(
[Parameter(
Mandatory=$true,
Position=0,
ValueFromPipeline=$true)]
$folder,
[bool]$backup = $true,
[switch]$recurse
)
# add msbuild types here
Add-Type -AssemblyName Microsoft.Build
<#
.SYNOPSIS
This can be used to open an MSBuild projcet file.
The object returned is of type Microsoft.Build.Construction.ProjectRootElement.
You can get the project either from a file or from an object. Regarding the from an existing
object if the passed in is a ProjectRootElement it will be returned, and otherwise the
value for $sourceObject.ContainingProject is returned. This is useful to enable
pipeline continuations based on the return type of the previous function call.
.OUTPUTS
[Microsoft.Build.Construction.ProjectRootElement]
.EXAMPLE
Get-MSBuildProject -projectFile 'C:\temp\msbuild\new\new.proj'
.EXAMPLE
Get-MSBuildProject -projectFile 'C:\temp\msbuild\new\new.proj' |
Find-PropertyGroup -labelValue second |
Remove-Property -name Configuration |
Get-MSBuildProject |
Save-MSBuildProject -filePath $projFile
#>
function Get-MSBuildProject{
[cmdletbinding()]
param(
[Parameter(
Position=1)]
$projectFile,
[Parameter(
ValueFromPipeline=$true)]
$sourceObject,
$projectCollection = (New-Object Microsoft.Build.Evaluation.ProjectCollection)
)
begin{
Add-Type -AssemblyName System.Core
Add-Type -AssemblyName Microsoft.Build
}
process{
$project = $null
if($projectFile){
$fullPath = (Get-Fullpath $projectFile)
$project = ([Microsoft.Build.Construction.ProjectRootElement]::Open([string]$fullPath,$projectCollection))
}
elseif($sourceObject -is [Microsoft.Build.Construction.ProjectRootElement]){
$project = $sourceObject
}
else{
$project = $sourceObject.ContainingProject
}
return $project
}
}
<#
.SYNOPSIS
Can be used to convert a relative path (i.e. .\project.proj) to a full path.
#>
function Get-Fullpath{
[cmdletbinding()]
param(
[Parameter(
Mandatory=$true,
ValueFromPipeline = $true)]
$path,
$workingDir = ($pwd)
)
process{
$fullPath = $path
$oldPwd = $pwd
Push-Location
Set-Location $workingDir
[Environment]::CurrentDirectory = $pwd
$fullPath = ([System.IO.Path]::GetFullPath($path))
Pop-Location
[Environment]::CurrentDirectory = $oldPwd
return $fullPath
}
}
function RemoveItemsFromProj{
[cmdletbinding()]
param(
[Parameter(
Mandatory=$true,
ValueFromPipeline=$true)]
$project,
$itemsToRemove = @('Content','Compile','None')
)
process{
foreach($p in $project){
if(!($p)){ continue }
'Removing items from project [{0}]' -f ($p.FullPath) | Write-Verbose
# remove any item in the list
foreach($item in $p.Items){
if($itemsToRemove -contains ($item.ItemType)){
# remove the item
"Removing item [(ln {0} col {1}){2}:{3}]" -f ($item.Location.Line), ($item.Location.Column),($item.ItemType), ($item.Include) | Write-Verbose
$item.Parent.RemoveChild($item)
}
}
# look for and remove empty ItemGroup elements
foreach($ig in $p.ItemGroups){
if(!$ig.Items -or $ig.Items.Count -le 0){
"Removing empty ItemGroup at [({0}:{1})]" -f $ig.Location.Line,$ig.Location.Column | Write-Verbose
$ig.Parent.RemoveChild($ig)
}
}
}
}
}
#################################################
# Begin script
#################################################
'Looking for .kproj files under [{0}], please wait' -f $folder | Write-Host
$projects = Get-ChildItem -Path $folder -Include *.kproj -Recurse:$recurse
if($backup){
'Backing up files' | Write-Host
$utcNow = [DateTime]::UtcNow
foreach($p in $projects){
$projPath = $p.Fullname
$backupName = ('{0}.bak.{1}' -f $projPath, ($utcNow.Ticks))
'Backing up project from [{0}] to [{1}]' -f $projPath, $backupName | Write-Verbose
Copy-Item $projPath $backupName
}
}
else{
'Skipping backup as requested' | Write-Host
}
foreach($p in $projects){
$msbProj = Get-MSBuildProject -projectFile $p
RemoveItemsFromProj -project $msbProj
$msbProj.Save()
}
@davidfowl
Copy link

Updated

[cmdletbinding()]
param(
    [Parameter(
        Mandatory=$true,
        Position=0,
        ValueFromPipeline=$true)]
        $folder,

    [bool]$backup = $true,

    [switch]$recurse
)

# add msbuild types here
Add-Type -AssemblyName Microsoft.Build

<#
.SYNOPSIS
    This can be used to open an MSBuild projcet file.
    The object returned is of type Microsoft.Build.Construction.ProjectRootElement.

    You can get the project either from a file or from an object. Regarding the from an existing
    object if the passed in is a ProjectRootElement it will be returned, and otherwise the
    value for $sourceObject.ContainingProject is returned. This is useful to enable
    pipeline continuations based on the return type of the previous function call.

.OUTPUTS
    [Microsoft.Build.Construction.ProjectRootElement]

.EXAMPLE
    Get-MSBuildProject -projectFile 'C:\temp\msbuild\new\new.proj'

.EXAMPLE
    Get-MSBuildProject -projectFile 'C:\temp\msbuild\new\new.proj' | 
        Find-PropertyGroup -labelValue second | 
        Remove-Property -name Configuration |
        Get-MSBuildProject | 
        Save-MSBuildProject -filePath $projFile
#>
function Get-MSBuildProject{
    [cmdletbinding()]
    param(
        [Parameter(
            Position=1)]
        $projectFile,

        [Parameter(
            ValueFromPipeline=$true)]
        $sourceObject,

        $projectCollection = (New-Object Microsoft.Build.Evaluation.ProjectCollection)
    )
    begin{
        Add-Type -AssemblyName System.Core
        Add-Type -AssemblyName Microsoft.Build
    }
    process{
        $project = $null
        if($projectFile){
            $fullPath = (Get-Fullpath $projectFile)
            $project = ([Microsoft.Build.Construction.ProjectRootElement]::Open([string]$fullPath,$projectCollection))
        }
        elseif($sourceObject -is [Microsoft.Build.Construction.ProjectRootElement]){
            $project = $sourceObject
        }
        else{
            $project = $sourceObject.ContainingProject
        }
        return $project
    }
}

<#
.SYNOPSIS
    Can be used to convert a relative path (i.e. .\project.proj) to a full path.
#>
function Get-Fullpath{
    [cmdletbinding()]
    param(
        [Parameter(
            Mandatory=$true,
            ValueFromPipeline = $true)]
        $path,

        $workingDir = ($pwd)
    )
    process{
        $fullPath = $path
        $oldPwd = $pwd

        Push-Location
        Set-Location $workingDir
        [Environment]::CurrentDirectory = $pwd
        $fullPath = ([System.IO.Path]::GetFullPath($path))

        Pop-Location
        [Environment]::CurrentDirectory = $oldPwd

        return $fullPath
    }
}

function RemoveItemsFromProj{
    [cmdletbinding()]
    param(
        [Parameter(
            Mandatory=$true,
            ValueFromPipeline=$true)]
        $project,

        $itemsToRemove = @('Content','Compile','None')
    )
    process{
        foreach($p in $project){
            if(!($p)){ continue }

            'Removing items from project [{0}]' -f ($p.FullPath) | Write-Verbose

            # remove any item in the list
            foreach($item in $p.Items){
                if($itemsToRemove -contains ($item.ItemType)){
                    # remove the item
                    "Removing item [(ln {0} col {1}){2}:{3}]" -f ($item.Location.Line), ($item.Location.Column),($item.ItemType), ($item.Include) | Write-Verbose
                    $item.Parent.RemoveChild($item)
                }
            }

            # look for and remove empty ItemGroup elements
            foreach($ig in $p.ItemGroups){
                if(!$ig.Items -or $ig.Items.Count -le 0){
                    "Removing empty ItemGroup at [({0}:{1})]" -f $ig.Location.Line,$ig.Location.Column | Write-Verbose
                    $ig.Parent.RemoveChild($ig)
                }
            }
        }
    }
}

#################################################
# Begin script
#################################################

'Looking for .kproj files under [{0}], please wait' -f $folder | Write-Host
$projects = Get-ChildItem -Path $folder -Include *.kproj -Recurse:$recurse

if($backup){
    'Backing up files' | Write-Host
    $utcNow = [DateTime]::UtcNow
    foreach($p in $projects){
        $projPath = $p.Fullname
        $backupName = ('{0}.bak.{1}' -f $projPath, ($utcNow.Ticks))
        'Backing up project from [{0}] to [{1}]' -f $projPath, $backupName | Write-Verbose
        Copy-Item $projPath $backupName
    }
}
else{
    'Skipping backup as requested' | Write-Host
}

foreach($p in $projects){
    $msbProj = Get-MSBuildProject -projectFile $p
    RemoveItemsFromProj -project $msbProj
    $msbProj.Save()
}

@sayedihashimi
Copy link
Author

I updated it with your changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment